String Parsing- parsing EnvVars easily¶
Envolved comes with a rich suite of parsers out of the box, to be used the the type param for
Single-Variable EnvVars.
Primitive parsers¶
By default, any callable that accepts a string can be used as a parser, this includes many built-in types and factories
like int, float, datetime.fromisoformat, json.loads, re.compile, and even str.
Special parsers¶
Some built-in callables translate to special predefined parsers. For example, the bool type would be pretty
ineffective on its own as a parser, which is why envolved knows to treat the bool type as a special parser that
translates the string "True" and "False" to True and False respectively.
enable_cache_ev = env_var("ENABLE_CACHE", type=bool)
os.environ["ENABLE_CACHE"] = "False"
assert enable_cache_ev.get() is False
Users can disable the special meaning of some types by wrapping them in a dummy callable.
enable_cache_ev = env_var("ENABLE_CACHE", type=lambda x: bool(x))
os.environ["ENABLE_CACHE"] = "False"
assert enable_cache_ev.get() is True
All the special parsers are:
bytes: encodes the string as UTF-8bool: translates the string"True"and"False"toTrueandFalserespectively (equivalent toBoolParser(['true'], ['false']), seeBoolParser).complex: parses the string as a complex number, treating “i” as an imaginary unit in addition to “j”.union type
A | Noneortyping.Union[A, None]ortyping.Optional[A]: Will treat the parser as though it only parsesA.enum type
E: translates each enum name to the corresponding enum member, ignoring cases (equivalent toLookupParser.case_insensitive(E)seeLookupParser).pydantic
BaseModel: parses the string as JSON and validates it against the model (both pydantic v1 and v2 models are supported).pydantic
TypeAdapter: parses the string as JSON and validates it against the adapted type.
Utility Parsers¶
- class BoolParser(maps_to_true: Iterable[str] = (), maps_to_false: Iterable[str] = (), *, default: bool | None = None, case_sensitive: bool = False)[source]¶
A parser to translate strings to
TrueorFalse.- Parameters:
maps_to_true – A list of strings that translate to
True.maps_to_false – A list of strings that translate to
False.default – The default value to return if the string is not mapped to either value. Set to
Noneto raise an exception.case_sensitive – Whether the strings to match are case sensitive.
- class CollectionParser(delimiter: str | Pattern, inner_parser: ParserInput[E], output_type: Callable[[Iterator[E]], G] = list, opener: str | Pattern = '', closer: str | Pattern = '', *, strip: bool = True)[source]¶
A parser to translate a delimited string to a collection of values.
- Parameters:
delimiter – The delimiter string or pattern to split the string on.
inner_parser – The parser to use to parse the elements of the collection. Note this parser is treated the same an an EnvVar type, so Special parsers apply.
output_type – The type to use to aggregate the parsed items to a collection. Defaults to list.
opener – If set, specifies a string or pattern that should be at the beginning of the delimited string.
closer – If set, specifies a string or pattern that should be at the end of the delimited string. Note that providing a pattern will slow down the parsing process.
strip – Whether or not to strip whitespaces from the beginning and end of each item.
countries = env_var("COUNTRIES", type=CollectionParser(",", str.lower, set)) os.environ["COUNTRIES"] = "United States,Canada,Mexico" assert countries.get() == {"united states", "canada", "mexico"}
- classmethod pair_wise_delimited(pair_delimiter: str | Pattern, key_value_delimiter: str | Pattern, key_type: ParserInput[K], value_type: ParserInput[V] | Mapping[K, ParserInput[V]], output_type: Callable[[Iterable[tuple[K, V]]], G] = ..., *, key_first: bool = True, opener: str | Pattern = '', closer: str | Pattern = '', strip: bool = True, strip_keys: bool = True, strip_values: bool = True) CollectionParser[G][source]¶
A factory method to create a
CollectionParserwhere each item is a delimited key-value pair.- Parameters:
pair_delimiter – The delimiter string or pattern between any two key-value pairs.
key_value_delimiter – The delimiter string or pattern between the key and the value.
key_type – The parser to use to parse the keys. Note this parser is treated the same an an EnvVar type, so Special parsers apply.
value_type – The parser to use to parse the values. Note this parser is treated the same an an EnvVar type, so Special parsers apply. This can also be a mapping from keys to parsers, to specify different parsers for different keys.
output_type – The type to use to aggregate the parsed key-value pairs to a collection. Defaults to a
dictthat raises an exception if a key appears more than once.key_first – If set to
True(the default), the first element in each key-value pair will be interpreted as the key. If set toFalse, the second element in each key-value pair will be interpreted as the key.opener – Acts the same as in the
constructor.closer – Acts the same as in the
constructor.strip – Acts the same as in the
constructor.strip_keys – Whether or not to strip whitespaces from the beginning and end of each key in every pair.
strip_values – Whether or not to strip whitespaces from the beginning and end of each value in every pair.
Using CollectionParser.pair_wise_delimited to parse arbitrary HTTP headers.¶headers_ev = env_var("HTTP_HEADERS", type=CollectionParser.pair_wise_delimited(";", ":", str.upper, str)) os.environ["HTTP_HEADERS"] = "Foo:bar;baz:qux" assert headers_ev.get() == {"FOO": "bar", "BAZ": "qux"}
Using CollectionParser.pair_wise_delimited to parse a key-value collection with differing value types.¶server_params_ev = env_var("SERVER_PARAMS", type=CollectionParser.pair_wise_delimited(";", ":", str, { 'host': str, 'port': int, 'is_ssl': bool,})) os.environ["SERVER_PARAMS"] = "host:localhost;port:8080;is_ssl:false" assert server_params_ev.get() == {"host": "localhost", "port": 8080, "is_ssl": False}
- class FindIterCollectionParser(element_pattern: Pattern, element_func: Callable[[Match], E], output_type: Callable[[Iterator[E]], G] = list, opener: str | Pattern = '', closer: str | Pattern = '')[source]¶
A parser to translate a string to a collection of values by splitting the string to continguous elements that match a regex pattern. This parser is useful for parsing strings that have a repeating, complex structure, or in cases where a
naive splitwould split the string incorrectly.- Parameters:
element_pattern – A regex pattern to find the elements in the string.
element_func – A function that takes a regex match object and returns an element.
output_type – The type to use to aggregate the parsed items to a collection. Defaults to list.
opener – If set, specifies a string or pattern that should be at the beginning of the string.
closer – If set, specifies a string or pattern that should be at the end of the string. Note that providing a pattern will slow down the parsing process.
Using FindIterCollectionParser to parse a string of comma-separated groups of numbers.¶def parse_group(match: re.Match) -> set[int]: return {int(x) for x in match.group(1).split(',')} groups_ev = env_var("GROUPS", type=FindIterCollectionParser( re.compile(r"{([,\d]+)}(,|$)"), parse_group )) os.environ["GROUPS"] = "{1,2,3},{4,5,6},{7,8,9}" assert groups_ev.get() == [{1, 2, 3}, {4, 5, 6}, {7, 8, 9}]
- class MatchParser(cases: Iterable[tuple[Pattern[str] | str, T]] | Mapping[str, T] | type[Enum], fallback: T = ...)[source]¶
A parser that checks a string against a se of cases, returning the value of first case that matches.
- Parameters:
cases – An iterable of match-value pairs. The match can be a string or a regex pattern (which will need to fully match the string). The case list can also be a mapping of strings to values, or an enum type, in which case the names of the enum members will be used as the matches.
fallback – The value to return if no case matches. If not specified, an exception will be raised.
class Color(enum.Enum): RED = 1 GREEN = 2 BLUE = 3 color_ev = env_var("COLOR", type=MatchParser(Color)) os.environ["COLOR"] = "RED" assert color_ev.get() == Color.RED
- classmethod case_insensitive(cases: Iterable[tuple[str, T]] | Mapping[str, T] | type[Enum], fallback: T = ...) MatchParser[T][source]¶
Create a
MatchParserwhere the matches are case insensitive. If two cases are equivalent under case-insensitivity, an error will be raised.- Parameters:
cases – Acts the same as in the
constructor. Regex patterns are not supported.fallback – Acts the same as in the
constructor.
- class LookupParser(lookup: collection.abc.Iterable[tuple[str, T]] | Mapping[str, T] | type[Enum], fallback: T = ...)[source]¶
A parser that checks a string against a set of cases, returning the value of the matching case. This is a more efficient version of
MatchParserthat uses a dictionary to store the cases.- Parameters:
lookup – An iterable of match-value pairs, a mapping of strings to values, or an enum type, in which case the names of the enum members will be used as the matches.
fallback – The value to return if no case matches. If not specified, an exception will be raised.
class Color(enum.Enum): RED = 1 GREEN = 2 BLUE = 3 color_ev = env_var("COLOR", type=LookupParser(Color)) os.environ["COLOR"] = "RED" assert color_ev.get() == Color.RED
- classmethod case_insensitive(lookup: collection.abc.Iterable[tuple[str, T]] | Mapping[str, T] | type[Enum], fallback: T = ...) LookupParser[T][source]¶
Create a
LookupParserwhere the matches are case insensitive. If two cases are equivalent under case-insensitivity, an error will be raised.- Parameters:
lookup – Acts the same as in the
constructor.fallback – Acts the same as in the
constructor.