cmdkit.namespace#



Reference#


class Namespace(*args: Iterable | Mapping, **kwargs: Any)[source]#

Bases: NSCoreMixin

A dictionary with depth-first updates and factory methods.

Example:
>>> ns = Namespace({'a': {'x': 1, 'y': 2}, 'b': 3})
>>> ns.update({'a': {'x': 4, 'z': 5}})
>>> ns
Namespace({'a': {'x': 4, 'y': 2, 'z': 5}, 'b': 3})
>>> ns.to_local('config.toml')
>>> Namespace.from_local('config.toml', ignore_if_missing=True)
Namespace({'a': {'x': 4, 'y': 2, 'z': 5}, 'b': 3})

update(*args, **kwargs) None#

Depth-first update method.


classmethod from_local(filepath: str, ignore_if_missing: bool = False, ftype: str | None = None, **options) Namespace[source]#

Load from a local file.

If filepath does not exist an exception is raised as expected, unless ignore_if_missing is True and an empty Namespace is returned instead.

Supported formats are yaml, toml, and json. You must have the necessary library installed (i.e., pyyaml or toml respectively).

Example:
>>> Namespace.from_local('config.toml', ignore_if_missing=True)
Namespace({})
>>> Namespace({'a': {'x': 1, 'y': 2}, 'b': 3}).to_local('config.toml')
>>> Namespace.from_local('config.toml')
Namespace({'a': {'x': 1, 'y': 2}, 'b': 3})
>>> Namespace.from_local('config', ftype='toml', ignore_if_missing=True)
Namespace({})
to_local(filepath: str, ftype: str | None = None, **options) None[source]#

Output to local file. If ftype not set, format based on file extension.


classmethod from_yaml(path_or_file: str | IO, **options) Namespace[source]#

Load a namespace from a YAML file.

classmethod from_toml(path_or_file: str | IO, **options) Namespace[source]#

Load a namespace from a TOML file.

classmethod from_json(path_or_file: str | IO, **options) Namespace[source]#

Load a namespace from a JSON file.


to_yaml(path_or_file: str | IO, encoding: str = 'utf-8', **kwargs) None[source]#

Output to YAML file.

to_toml(path_or_file: str | IO, encoding: str = 'utf-8', **kwargs) None[source]#

Output to TOML file.

to_json(path_or_file: str | IO, encoding: str = 'utf-8', indent: int = 4, **kwargs) None[source]#

Output to JSON file.


classmethod from_env(prefix: str | None = None, defaults: Dict[str, Any] | None = None) Environ[source]#

Create a Namespace from os.environ, optionally filtering variables based on their name using prefix.

Args:
prefix (str):

An optional prefix to filter the environment variables. The results will be any variable that starts with this prefix.

defaults (dict):

An existing Namespace of defaults to be overriden if present in the environment.

Example:
>>> Namespace.from_env(prefix='MYAPP', defaults={'MYAPP_LOGGING_LEVEL': 'WARNING', })
Environ({'MYAPP_LOGGING_LEVEL': 'WARNING', 'MYAPP_COUNT': '42'})
See Also:

Environ: adds expand() method

to_env() Environ[source]#

Translate namespace to an Environ namespace.


duplicates() Dict[str, List[Tuple[str, ...]]][source]#

Find all the repeated leaves.

Example:
>>> ns = Namespace({'a': {'x': 1, 'y': 2}, 'b': {'x': 3, 'z': 4}})
>>> ns
Namespace({'a': {'x': 1, 'y': 2}, 'b': {'x': 3, 'z': 4}})
>>> ns.duplicates()
{'x': [('a',), ('b',)]}

whereis(leaf: str, value: ~typing.Callable[[~cmdkit.namespace.T], bool] | ~cmdkit.namespace.T = <function Namespace.<lambda>>) List[Tuple[str, ...]][source]#

Find paths to leaf, optionally filtered on value.

Example:
>>> ns = Namespace({'a': {'x': 1, 'y': 2}, 'b': {'x': 3, 'z': 4}})
>>> ns
Namespace({'a': {'x': 1, 'y': 2}, 'b': {'x': 3, 'z': 4}})
>>> ns.whereis('x')
[('a',), ('b',)]
>>> ns.whereis('x', 1)
[('a',)]
>>> ns.whereis('x', lambda v: v % 3 == 0)
[('b',)]

class Environ(prefix: str | None = None, defaults: dict | None = None)[source]#

Bases: NSCoreMixin

A Namespace initialized via from_env(). The special method expand() melts the normalized variables by splitting on underscores into a full heirarchy.

Example:
>>> env = Namespace.from_env('MYAPP')
>>> env
Environ({'MYAPP_A_X': '1', 'MYAPP_A_Y': '2', 'MYAPP_B': '3'})
>>> env.expand()
Environ({'a': {'x': 1, 'y': 2}, 'b': 3})

expand(converter: Callable[[str], Any] | None = None) Environ[source]#

De-normalize the key-value pairs into a nested dictionary. The prefix is stripped away and structure is derived by splitting on underscores.

The converter should be a function that accepts an input value and returns a new value appropriately coerced. The default converter attempts first to coerce a value to an integer if possible, then a float, except the following special values. Otherwise, the string remains.

Input Value

Output Value

'', 'null'

None

'true' / 'false'

True / False

flatten(prefix: str | None = None) Environ[source]#

Collapse a namespace down to a single level by merging keys with their parent section by underscore.

Example:
>>> env = Namespace.from_env('MYAPP')
>>> env
Environ({'MYAPP_A_X': '1', 'MYAPP_A_Y': '2', 'MYAPP_B': '3'})
>>> env.expand()
Environ({'a': {'x': 1, 'y': 2}, 'b': 3})
>>> env.expand().flatten(prefix='MYAPP')
Environ({'MYAPP_A_X': '1', 'MYAPP_A_Y': '2', 'MYAPP_B': '3'})

export(prefix: str | None = None) None[source]#

Calls flatten() before persisting members to os.environ.