Git Product home page Git Product logo

objgen's Introduction

objgen

Dynamically generate class objects by digesting key-value / pairwise data structures as object specifications.

objgen has no external dependencies, can be used immediately, and is more fun (and less limiting) than calling type('NewClassName', (*inheritances), {'attr': 'value'}).

usage

>>> from objgen.generators.generic import Base
>>> base = Base()
>>> vars(base)
{}

Pass a dictionary to a generator instance to construct its object, then use the object.

>>> hydrated = Base({'attr1': 'val1', 'attr2': 'val2'}, attr3='val3')
>>> vars(hydrated)
{'attr1': 'val1', 'attr2': 'val2', 'attr3': 'val3'}
>>> hydrated.attr1, hydrated.attr2, hydrated.attr3
('val1', 'val2', 'val3')

Any input that can be cast into a dictionary will be digested; any data that cannot will be discarded.

>>> from objgen.generators.generic import Base
>>> b = Base(
...     {'this': 'is', 'valid': 'input'},
...     'this_is_not_pairwise_data',
...     [('this', 'however'), ('will', 'work'), ('just', 'fine')]
... )
Element cannot be cast into dict, and is being discarded: <class 'str'> this_is_not_pairwise_data

If multiples of a field exists in a given collection of input arguments, the most recent passed value for that field will be preserved.

>>> b = Base({'this': 'is'}, [('this', 'however'), ])
>>> b
Base ['this']
>>> b.this
'however'

gore ( fun! ( examples ) )

nesting - manual

Say we want to create a dog, but also be able to access/call a dog.actions.{action}.

>>> dog_info = {
...         'name': 'monty',
...         'breed': 'donkey child',
...         'is_good_boy': True,
...         'actions': {'run_to': 'car', 'bark_at': 'squirrel', 'pee_on': 'hydrant'},
...     }

Instantiate and hydrate a generator as dog, then do the same to the resulting dog.actions.

>>> from objgen.generators.generic import Base
>>>
>>> dog = Base(dog_info)
>>> dog.actions
{'run_to': 'car', 'bark_at': 'squirrel', 'pee_on': 'hydrant'}
>>> dog.actions = Base(dog.actions)
>>> dog.actions.run_to
'car'

back

nesting - recursive

Let's make a Recursive generator to digest the full depth of the data structure -- having to call cls.attr = Base(cls.attr) for every single nested attributes at each given 'depth' is ridiculous.

Whereas a Base generator will simply create cls.key = value relationships,

                setattr(self, field, spec[field])

a Recursive generator will continue to digest any dictionary objects it encounters along any nesting path.

                if isinstance(spec[field], dict):
                    setattr(self, field, Recursive(spec[field]))

Let's try making our dog again, but with a Recursive generator:

>>> from objgen.generators.generic import Recursive
>>>
>>> dog = Recursive(dog_info)
>>> dog.actions
<objgen.generators.generic.Recursive object at 0x7f2bb4ef2c18>
>>> dog.actions.run_to
'car'

back

nesting - selectively recursive

So far so good - except, what if we want certain things to stay as dictionaries, rather than be indiscriminately digested?

For example, we want to add our dog's friends, and be able to access dog.friends - however, it would be silly for each {friend} to become a dog.friends.{friend} attribute instead of staying preserved as elements in a data structure.

... dog_info.update(
...     {
...         'friends': {
...             'lassie': {'breed': 'collie', 'met_at': 'dog park'},
...             'marnie': {'breed': 'shih tzu', 'met_at': 'dms'},
...             'air_bud': {'breed': 'golden retriever', 'met_at': 'basketball courts'},
...             'laika': {'breed': 'mongrel', 'met_at': 'outer space'}
...         }
...    }
...)

Let's make a RecursiveFiltered that deals with this for us.

Optionally, supply either _exclude or _include_only keyword arguments when creating the RecursiveFilter to determine which fields are (dis)allowed to be digested.

>>> from objgen.generators.generic import RecursiveFiltered
>>>
>>> dog = RecursiveFiltered(dog_info, _exclude='friends')
>>>
>>> type(dog.actions)
<class 'objgen.generators.generic.RecursiveFiltered'>
>>> type(dog.friends)
<class 'dict'>

Note that excluding a field means that digestion along that path in the data tree will terminate at that field, rather than skip that field and continue down that path's depth.


back

objgen's People

Contributors

oaao avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.