With Python's type-hinting, it's possible that one could specify a compound type as a type hint:
class Person:
name: str
age: int
class Environment:
person: Person
env = Environment()
envconfig.process(env)
Decide how we want to handle this. There's a couple of options here:
- Recursively process
Person as if it were another environment container object. One problem that could arise with this is that we'd need to enforce that these compound types have such type hints set up. Most Python classes that I've seen don't do this. We'd also have to maybe prepend the name of the class prior to reading the env var, as there might be a top-level attribute in Environment called name. So we'd have to do something like read PERSON_NAME instead. This gets pretty unwieldy as we keep nesting our classes.
- Add a keyword argument option to
envconfig.process that is a postprocessor dictionary. This will be a map from the name of the attribute (in the above case, the name of the attribute is person) to a function that knows how to parse a Person specified by an environment variable. E.g, PERSON=TheName,25 then we can pass a postprocessor like lambda x: Person(x.split(',')[0], x.split(',')[1]) to construct a person object and set that as the attribute in Environment.
I'm leaning towards the second option because it's more explicit than the first, which is more magical and requires being aware of the recursive behavior. In general, most users probably don't want the implicit behavior and want to define exactly how to construct a particular object from an environment variable if they need to do so.
With Python's type-hinting, it's possible that one could specify a compound type as a type hint:
Decide how we want to handle this. There's a couple of options here:
Personas if it were another environment container object. One problem that could arise with this is that we'd need to enforce that these compound types have such type hints set up. Most Python classes that I've seen don't do this. We'd also have to maybe prepend the name of the class prior to reading the env var, as there might be a top-level attribute inEnvironmentcalledname. So we'd have to do something like readPERSON_NAMEinstead. This gets pretty unwieldy as we keep nesting our classes.envconfig.processthat is a postprocessor dictionary. This will be a map from the name of the attribute (in the above case, the name of the attribute isperson) to a function that knows how to parse aPersonspecified by an environment variable. E.g,PERSON=TheName,25then we can pass a postprocessor likelambda x: Person(x.split(',')[0], x.split(',')[1])to construct a person object and set that as the attribute inEnvironment.I'm leaning towards the second option because it's more explicit than the first, which is more magical and requires being aware of the recursive behavior. In general, most users probably don't want the implicit behavior and want to define exactly how to construct a particular object from an environment variable if they need to do so.