Package: related
Relatedis a Python library for creating nested object models
that can be serialized to and de-serialized from
nested python dictionaries.
When paired with other libraries (e.g.PyYAML),Relatedobject models can be used to convert to and from
nested data formats (e.g. JSON, YAML).Example use cases forrelatedobject models include:Configuration file reading and writingREST API message response generation and request processingObject-Document Mapping for a document store (e.g. MongoDB, elasticsearch)Data import parsing or export generationRequirementsPython (2.7, 3.5, 3.6)InstallationInstall usingpip...pip install relatedFirst Exampleimportrelated@related.immutableclassPerson(object):first_name=related.StringField()last_name=related.StringField()@related.immutableclassRoleModels(object):scientists=related.SetField(Person)people=[Person(first_name="Grace",last_name="Hopper"),Person(first_name="Katherine",last_name="Johnson"),Person(first_name="Katherine",last_name="Johnson")]print(related.to_yaml(RoleModels(scientists=people)))Yields:scientists:-first_name:Gracelast_name:Hopper-first_name:Katherinelast_name:JohnsonSecond ExampleThe below example is based off of thisDocker Compose example.
It shows how a YAML file can be loaded into an object model, tested, and
then generated back into a string that matches the original YAML.version:'2'services:web:build:.ports:-5000:5000volumes:-.:/coderedis:image:redisBelow is therelatedobject model that represents the above configuration.
Notice how the name-based mapping of services (i.e. web, redis) are
represented by the model.importrelated@related.immutableclassService(object):name=related.StringField()image=related.StringField(required=False)build=related.StringField(required=False)ports=related.SequenceField(str,required=False)volumes=related.SequenceField(str,required=False)command=related.StringField(required=False)@related.immutableclassCompose(object):version=related.StringField(required=False,default=None)services=related.MappingField(Service,"name",required=False)The above yaml can then be loaded by using one of the convenience
method and then round-tripped back to yaml to check that the format
has been maintained. Therelatedmodule usesOrderedDictobjects
in order to maintain sort order by default.fromos.pathimportjoin,dirnamefrommodelimportComposefromrelatedimportto_yaml,from_yaml,to_modelYML_FILE=join(dirname(__file__),"docker-compose.yml")deftest_compose_from_yml():original_yaml=open(YML_FILE).read().strip()yml_dict=from_yaml(original_yaml)compose=to_model(Compose,yml_dict)assertcompose.version=='2'assertcompose.services['web'].ports==["5000:5000"]assertcompose.services['redis'].image=="redis"generated_yaml=to_yaml(compose,suppress_empty_values=True,suppress_map_key_values=True).strip()assertoriginal_yaml==generated_yamlMore ExamplesMore examples can be found by reviewing thetests/folder of this project.
Below are links and descriptions of the tests provided so far.ExampledescriptionExample 00First example above that shows how SetFields work.Example 01Second example above that demonstrates YAML (de)serialization.Example 02Compose v3 with long-form ports and singledispatch to_dictExample 03A single class (Company) with a bunch of value fields.Example 04A multi-class object model with Enum class value field.Example 05Handling of renaming of attributes including Python keywords.Example 06Basic JSON (de)serialization with TimeField, DateTimeField and DecimalField.Example 07Function decorator that converts inputs to obj and outputs to dictExample 08Handle self-referencing and out-of-order references using strings.DocumentationBelow is a quick version of documentation until more time can be dedicated.OverviewTheattrslibrary is the underlying engine forrelated.
As explained inthis article by Glyph,attrscleanly and cleverly
eliminates a lot of the boilerplate
required when creating Python classes
without using inheritance.
Some core functionality provided by attrs:Generated initializer method
(__init__)Generated comparison methods
(__eq__,__ne__,__lt__,__le__,__gt__,__ge__)Human-readable representation method
(__repr__)Attribute converter and validator frameworkTherelatedproject is an opinionated layer
built on top of theattrslibrary
that provides the following:Value fields that handle both validation and conversion
to and from basic data types likestr,float, andbool.Nested fields that support relationships such as
Child, Sequences, Mappings, and Sets of objects.to_dictfunction that converts nested object graphs
to python dictionaries.
Made customizable (without resorting tomonkey-patching)
by thesingledispatch library.to_modelfunction that instantiated classes
used by the de-serialization process going from
python dictionaries to the related model.Conversion helper functions
(to_yaml,from_yaml,to_json,from_json)
for easily going between
related models and data formats.@mutableand@immutablefor decorating classes
as related models without the need for inheritance increasing
maintainability and flexibility.Class Decoratorsdecoratordescription@mutableActivate a related class that instantiates changeable objects.@immutableActivate a related class that instantiates unchangeable objects.See thedecorators.pyfile to view the source code until proper
documentation is generated.Field Typesfield typedescriptionBooleanFieldboolvalue field.ChildFieldChild object of a specified typecls.DateFielddatefield formatted usingformatter.DateTimeFielddatetimefield formatted usingformatter.TimeFieldtimefield formatted usingformatter.FloatFieldfloatvalue field.IntegerFieldintvalue field.MappingField(cls,key)Dictionary of objects of typeclsindex bykeyfield values.RegexField(regex)strvalue field that is validated by re.match(regex).SequenceField(cls)List of objects all of specified typecls.SetFieldSet of objects all of a specified typecls.StringFieldstrvalue field.URLFieldParseResultobject.UUIDFieldUUIDobject, will createuuid4by default if not specified.Adding your own field types is fairly straightforward
due to the power of the underlyingattrsproject.
See thefields.pyfile to see how the above are constructed.Functionsfunctiondescriptionfrom_json(s,cls)Convert a JSON string or stream into specified class.from_yaml(s,cls)Convert a YAML string or stream into specified class.is_related(obj)Returns True if object is @mutable or @immutable.to_dict(obj)Singledispatch function for converting to a dict.to_json(obj)Convert object to a (pretty) JSON string via to_dict.to_model(cls,value)Convert a value to aclsinstance.to_yaml(obj)Convert object to a YAML string via to_dict.See thefunctions.pyfile to view the source code until proper
documentation is generated.Credits/Prior ArtTherelatedproject has been heavily influenced by the following
projects that might be worth looking at ifrelateddoesn't meet your needs.attrs- The engine that powersrelatedfunctionality.Django ORM- Object-relational mapping for Django that inspiredrelated'sdesign.cattrs- Alternative take for handling nested-objects usingattrs.addictandbox- Python dictionary wrappers that do not require a model.Jackson- Java-based technology for serializing and de-serializing objects.LicenseThe MIT License (MIT)
Copyright (c) 2017Ian Maurer,Genomoncology LLC0.7.1 (2018-10-13)Add URL to related pypi page [#28]Make singledispatch an optional dependency for < python 3.4. Thanks [GhostofGoes].URLField bug [#20]Deprecation warnings fixed for python 3.7 [#27]0.6.2 (2018-02-12)Contribution [GabrielDav]: TimeField and DateTimeField fields.0.6.1 (2018-01-31)Strict Mode [Issue #8] throws an exception when receiving an undefined key.0.3 (2017-06-23)New type: ImmutableDictAdd function on TypedMappingBug fixes in from_yaml and from_json functions.0.2 (2017-06-05)Allow None by default in Typed Collections.0.1 (2017-05-24)Initial release.