0

I have what is probably a very obscure problem. My python script is intended to be ran from the command line with some command line arguments. Each argument needs to be parsed into a type more useful than a string. I am doing the following:

typed_arguments = []
for argument, (parameter, parameter_type) in zip(arguments, self.parameters.items()):
    try:
        argument = parameter_type(argument)
        typed_arguments.append(argument)
    except ValueError:
        print(self.usage_prompt)
        raise TypeError(f"Invalid {parameter}! Must conform to {parmeter_type}.")

where arguments is sys.argv[1:] and self.parameters is an OrderedDict[str, type] mapping the names of the parameters to the type they should conform to.

One of the arguments needs to be of an enum type. I have the following:

from enum import Enum

class MessageType(Enum):
    READ = 1
    CREATE = 2
    RESPONSE = 3
    ...

where the entry in the parameter dictionary is {"message_type" : MessageType}

The problem, is that the code MessageType("READ") throws an exception instead of returning <MessageType.READ: 1>. Converting string to enum is instead done like so MessageType["READ"], but this is not helpful for my above code.

Is there some way, maybe through overriding __new__, making a MetaClass, or somthing entirely different, that I can make MessageType("READ") give me MessageType.READ and not throw an error?

Also, whilst trying to solve this problem, I discovered the argparse module. However this doesn't really solve my problem. Performing

parser.add_argument("message_type", type=MessageType)

still gives me error: argument message_type: invalid MessageType value: 'READ', as I presume its trying to do the exact same thing

Harry
  • 193
  • 1
  • 12
  • "The problem, is that the code MessageType("READ") throws an exception instead of returning . Converting string to enum is instead done like so MessageType["READ"], but this is not helpful for my above code." - to be clear: the issue is that you want each `parameter_type` from the iteration to have the consistent interface of being called, rather than subscripted, in order to enforce the type? ... Can you think of a way, given the enum class, to create a callable that would create the instance in the right way, and store it in `self.parameters`? – Karl Knechtel Aug 30 '23 at 22:07
  • see rogueleaderr's answer at the linked duplicate; it specifically covers the approach of adding a `@staticmethod` to the enum type that provides the interface you want. (You can implement it in terms of the existing `__getitem__` rather than with custom logic, of course.) There's also an approach that involves inheriting from both `Enum` and `str`, then matching the enumeration values, as strings, to their names. – Karl Knechtel Aug 30 '23 at 22:14
  • And yes, the standard library `argparse` will basically implement the logic of your first code snippet for you, but it will not bypass the need for the type-enforcer to be callable. `argparse` is also quite old and has some strange limitations and idiosyncracies; you may want to look in to third-party alternatives (but of course, such recommendations are off topic here). – Karl Knechtel Aug 30 '23 at 22:16
  • I men, you can define something like `def MessageTypeWrapper(s): return MessageType[s]`, no? if you just need a callable – juanpa.arrivillaga Aug 30 '23 at 22:18
  • I just upgraded to Python3.11 so I can use StrEnum :/ – Harry Aug 30 '23 at 22:34

0 Answers0