rym-lpath
The lpath module serves two primary purposes:
Easier access for nested structures
Consistent interface regardless of access type
It’s a simple enough premise, and possibly over-engineered, but lpath can help lower code redundancy and complexity by reducing the number of try-except blocks and specialized handling needed for nested structures.
The primary use is lpath.get. With get, you don’t really need anything else as you can add, remove, and update once you’ve pulled the appropriate item.
Usage
Access any nested index, item, or attribute
>>> from types import SimpleNamespace
>>> from rym import lpath
>>> example = [
... {"a": list('xyz'), "b": 42},
... SimpleNamespace(foo={"bar": "baz"}),
... ]
>>> lpath.get(example, '1.foo.bar')
'baz'
Use a default value if the item doesn’t exist
>>> lpath.get(example, 'hello.world', default='oops')
'oops'
Or, specify multiple options and get the first match
>>> lpath.get(example, ['hello.world', '0.a.1'])
'y'
Wildcards can be used to access any element. A trailing asterisk will always return the final value as is; in all other cases, the return value will be a list of items.
>>> lpath.get(example, '*.*.bar')
[['baz']]
>>> lpath.get(example, '*.*.*')
[[['x', 'y', 'z'], 42], [{'bar': 'baz'}]]
Set any nested index, item, or attribute
>>> from types import SimpleNamespace
>>> from rym import lpath
>>> example = [
... {"a": list('xyz'), "b": 42},
... SimpleNamespace(foo={"bar": "baz"}),
... ]
>>> lpath.set(example, '1.foo.bar', 'nope')
>>> example[1].foo['bar']
'nope'
You can also add new keys with mappings:
>>> lpath.set(example, '0.c', 'u l8r')
>>> example[0]['c']
'u l8r'
Recommended: Just use `lpath.get`
>>> lpath.get(example, '0.a').append('aa')
>>> lpath.get(example, '0.a.3')
'aa'
>>> setattr(lpath.get(example, '1'), 'baz', 42)
>>> lpath.get(example, '1.baz')
42
API
- rym.lpath.get(value: Any, key: str | Iterable[str], default: Any | None = 'any random string that is unlikely to be provided', *, delim: str | None = None) Any
Return the value of the property found at the given key.
- Wildcards:
A single asterisk may be used as a wildcard to match any value. A trailing asterisk will return the final value as is; i.e., it doesn’t really do much. When used in any other position, the return value will always be a list of the matched values.
- Parameters:
value – An object, iterable, or mapping
key – A string indicating the path to the value. An itererable of strings may be provided. The first match will be returned.
delim – Specify the delimiter. Default is ‘.’.
- Returns:
The property found.
- Raises:
AttributeError, IndexError, or KeyError if the requested key could not be found. –
ValueError if an invalid key given. –
- rym.lpath.get_default_delimiter() str
Return the default delimiter.
- Returns:
The default delimiter.
- rym.lpath.get_delimiter() str
Return the current delimiter.
- rym.lpath.pop(instance: object | Iterable | Mapping, key: str, *, delim: str | None = None) Any
Remove and return value at given key.
- Parameters:
instance – An object that supports item retrieval.
key – Delimited lookup string.
- Returns:
The removed value.
- Raises:
AttributeError, KeyError, IndexError – If no item exists at that key.
TypeError for unsupported input. –
- rym.lpath.reset_delimiter() None
Reset to the default delimiter.
- rym.lpath.set(instance: object | Iterable | Mapping, key: str, value: Any, *, delim: str | None = None) None
Set value of the item at the given path.
Will add keys to existing mappings, but cannot add attributes to objects or elements to lists.
- Parameters:
instance – A mutable object, iterable, or mapping.
key – The delimiter-separated path to the target.
value – The value to apply.
- Returns:
None.
- Raises:
AttributeError, IndexError, or KeyError if the path does not exist. –
TypeError if unable to set the value at the given key. –
- rym.lpath.set_delimiter(value: str) None
Set the lpath delimeter.
- Parameters:
value (str) – The delimiter to use.
- Returns:
None.