Skip to main content

UserDict subclass with extra stuff

Project description

Last release Platforms


Python dictionary with extra stuff.

Starting off, if you're seeing this, please give feedback!

You can install with pip install trict or conda install -c saska trict (working on conda-forge). Doesn't currently have any dependencies (although you'll need pytest if you want to run the tests for some reason), only works with python>3.6 strictly because I like f-strings which I can reformat out if someone needs this to work on something else.

Tricktionaries (subclass of collections.UserDict) are dictionary-type things that have recursive (and other) helper things I've previously needed. Here's how they work:

You initialize a tricktionary with a normal dictionary.

>>> from trict import Trict

>>> t = Trict({
    'user': {
        'information': {
            'attribute': 'infonugget',
            'another_attribute': 'secondnugget'
        'moreinformation': 'extranugget'

You can then perform all sorts of cool operations with it, like period-separated setting and getting (or any-string-separated, you can specify key_sep as a keyword argument in the Trict constructor, default is .).

>>> t['user.information.attribute']

Just like a python dictionary, Trict implements get(key, default=None) if you don't like KeyErrors.

When setting, the Trict will create intermediary keys for you:

>>> t['user.newinformation.newattribute'] = 'new'
>>> t['user.newinformation.newattribute']

Deleting also works as you'd expect, so you can also .pop(). You can also do any of this using sequences as keys.

>>> key = ['user', 'information', 'another_attribute']
>>> t[key]

If you want to flatten your dictionary for a csv export for example (use keys as the header), you can do that. The constructor arg key_sep also affects how keys are formatted here. The Tricktionary can be rebuilt by passing this type of flattened dictionary into the alternate from_flat_dict constructor with the same key_sep.

>>> t.flatten()
  'user.information.attribute': 'infonugget', 
  'user.information.another_attribute': 'secondnugget', 
  'user.moreinformation': 'extranugget', 
  'user.newinformation.newattribute': 'new'

Or do a complete traversal with traverse. It returns a generator yielding 2-tuples of (key-path, value).

>>> for k, v in t.traverse():
...     print(f"{k}: {v}")
['user']: {'information': {'attribute': 'infonugget', 'another_attribute': 'secondnugget'}, 'moreinformation': 'extranugget', 'newinformation': {'newattribute': 'new'}}
['user', 'information']: {'attribute': 'infonugget', 'another_attribute': 'secondnugget'}
['user', 'information', 'attribute']: infonugget
['user', 'information', 'another_attribute']: secondnugget
['user', 'moreinformation']: extranugget
['user', 'newinformation']: {'newattribute': 'new'}
['user', 'newinformation', 'newattribute']: new

If you just need the leaves, you can do that as well with a similar format.

>>> for k, v in t.leaves():
...     print(f"{k}: {v}")
['user', 'information', 'attribute']: infonugget
['user', 'information', 'another_attribute']: secondnugget
['user', 'moreinformation']: extranugget
['user', 'newinformation', 'newattribute']: new

You can also map the leaves (the actual values at the end of your dictionary) with a callable.

>>> t.map_leaves(lambda x: x + " - and there's more!")
  'user': {
    'information': {
      'attribute': "infonugget - and there's more!", 
      'another_attribute': "secondnugget - and there's more!"
    'moreinformation': "extranugget - and there's more!", 
    'newinformation': {
      'newattribute': "new - and there's more!"

All the dictionary helper methods are also provided standalone. There's also an extra one, iter_keys that iterates over anything that's a key - helpful if there's a bunch of people writing in your codebase and you want to enforce say a regex naming convention on your keys or something.

If you're more of the "I need to make sure my API can handle most anything thrown at it!" type, you can define a mapper (using {new_key: [str or sequence]}, try and stick to one, it's prettier, example has both) and throw any dicts you receive into a Tricktionary and map them to the same format. Pretty handy if you need to take in documents in multiple formats, just make sure document x doesn't have different data from document y in the same key path.

>>> mapper = {
        'newkey': [
            'user.noninformation.nonattribute', # Doesn't exist
            'user.information.another_attribute' # Finds
        'othernewkey': [
            ['user', 'noninformation'], # Doesn't exist
            ['user', 'information'] # Finds
>>> t.map_with_dict(mapper)
  'newkey': "secondnugget - and there's more!", 
  'othernewkey': {
    'attribute': "infonugget - and there's more!", 
    'another_attribute': "secondnugget - and there's more!"

Similar functionality can be found in get_by_seq which also takes [str or sequence] and returns val if any of those keys exists.

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

trict-0.1.6.tar.gz (7.7 kB view hashes)

Uploaded source

Built Distribution

trict-0.1.6-py3-none-any.whl (7.3 kB view hashes)

Uploaded py3

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring Fastly Fastly CDN Google Google Object Storage and Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page