<img src='./.images/logo.png' width='140' align="left" />
<a href='https://codecov.io/github/genomoncology/related/'><img src='https://codecov.io/github/genomoncology/related/branch/master/graph/badge.svg' align="right" /></a>
<a href='https://travis-ci.org/genomoncology/related'><img src='https://img.shields.io/travis/genomoncology/related.svg' align="right" /></a>
<a href='https://pypi.python.org/pypi/related'><img src='https://img.shields.io/pypi/v/related.svg' align="right" /></a>
<br/><br/>
`Related` is 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]),
`Related` object models can be used to convert to and from
nested data formats (e.g. JSON, YAML).
Example use cases for `related` object models include:
* Configuration file reading and writing
* REST API message response generation and request processing
* Object-Document Mapping for a document store (e.g. MongoDB, elasticsearch)
* Data import parsing or export generation
<br/>
![flow-image]
<br/>
# Requirements
* Python (2.7, 3.5, 3.6)
# Installation
Install using `pip`...
pip install related
# First Example
```python
import related
@related.immutable
class Person(object):
first_name = related.StringField()
last_name = related.StringField()
@related.immutable
class RoleModels(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:
```yaml
scientists:
- first_name: Grace
last_name: Hopper
- first_name: Katherine
last_name: Johnson
```
# Second Example
The below example is based off of this [Docker 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.
```yaml
version: '2'
services:
web:
build: .
ports:
- 5000:5000
volumes:
- .:/code
redis:
image: redis
```
Below is the `related` object model that represents the above configuration.
Notice how the name-based mapping of services (i.e. web, redis) are
represented by the model.
```python
import related
@related.immutable
class Service(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.immutable
class Compose(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. The `related` module uses `OrderedDict` objects
in order to maintain sort order by default.
```python
from os.path import join, dirname
from model import Compose
from related import to_yaml, from_yaml, to_model
YML_FILE = join(dirname(__file__), "docker-compose.yml")
def test_compose_from_yml():
original_yaml = open(YML_FILE).read().strip()
yml_dict = from_yaml(original_yaml)
compose = to_model(Compose, yml_dict)
assert compose.version == '2'
assert compose.services['web'].ports == ["5000:5000"]
assert compose.services['redis'].image == "redis"
generated_yaml = to_yaml(compose,
suppress_empty_values=True,
suppress_map_key_values=True).strip()
assert original_yaml == generated_yaml
```
# More Examples
More examples can be found by reviewing the [tests/] folder of this project.
Below are links and descriptions of the tests provided so far.
| Example | description |
| -------------- | ------------------------------------------------------------------ |
| [Example 00] | First example above that shows how SetFields work. |
| [Example 01] | Second example above that demonstrates YAML (de)serialization. |
| [Example 02] | Compose v3 with long-form ports and singledispatch to_dict |
| [Example 03] | A single class (Company) with a bunch of value fields. |
| [Example 04] | A multi-class object model with Enum class value field. |
| [Example 05] | Handling of renaming of attributes including Python keywords. |
| [Example 06] | Basic JSON (de)serialization with TimeField, DateTimeField and DecimalField. |
| [Example 07] | Function decorator that converts inputs to obj and outputs to dict |
| [Example 08] | Handle self-referencing and out-of-order references using strings. |
# Documentation
Below is a quick version of documentation until more time can be dedicated.
## Overview
The [attrs] library is the underlying engine for `related`.
As explained in [this article by Glyph],
`attrs` cleanly 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 framework
The `related` project is an opinionated layer
built on top of the `attrs` library
that provides the following:
* Value fields that handle both validation and conversion
to and from basic data types like
``str``, ``float``, and ``bool``.
* Nested fields that support relationships such as
Child, Sequences, Mappings, and Sets of objects.
* ``to_dict`` function that converts nested object graphs
to python dictionaries.
Made customizable (without resorting to [monkey-patching])
by the [singledispatch library].
* ``to_model`` function 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.
* ``@mutable`` and ``@immutable`` for decorating classes
as related models without the need for inheritance increasing
maintainability and flexibility.
## Class Decorators
| decorator | description |
| -------------- | ---------------------------------------------------------------- |
| @mutable | Activate a related class that instantiates changeable objects. |
| @immutable | Activate a related class that instantiates unchangeable objects. |
See the [decorators.py] file to view the source code until proper
documentation is generated.
## Field Types
| field type | description |
| -------------- | ---------------------------------------------------------------- |
| BooleanField | `bool` value field. |
| ChildField | Child object of a specified type `cls`. |
| DateField | `date` field formatted using `formatter`. |
| DateTimeField | `datetime` field formatted using `formatter`. |
| TimeField | `time` field formatted using `formatter`. |
| FloatField | `float` value field. |
| IntegerField | `int` value field. |
| MappingField(cls,key) | Dictionary of objects of type `cls` index by `key` field values. |
| RegexField(regex) | `str` value field that is validated by re.match(`regex`). |
| SequenceField(cls) | List of objects all of specified type `cls`. |
| SetField | Set of objects all of a specified type `cls`. |
| StringField | `str` value field. |
| URLField | [ParseResult] object. |
| UUIDField | [UUID] object, will create [uuid4] by default if not specified. |
Adding your own field types is fairly straightforward
due to the power of the underlying `attrs` project.
See the [fields.py] file to see how the above are constructed.
## Functions
| function | description |
| ------------------- | ----------------------------------------------------- |
| from_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 a `cls` instance. |
| to_yaml(obj) | Convert object to a YAML string via to_dict. |
See the [functions.py] file to view the source code until proper
documentation is generated.
# Credits/Prior Art
The `related` project has been heavily influenced by the following
projects that might be worth looking at if `related` doesn't meet your needs.
* [attrs] - The engine that powers `related` functionality.
* [Django ORM] - Object-relational mapping for Django that inspired `related's` design.
* [cattrs] - Alternative take for handling nested-objects using `attrs`.
* [addict] and [box] - Python dictionary wrappers that do not require a model.
* [Jackson] - Java-based technology for serializing and de-serializing objects.
# License
The MIT License (MIT)
Copyright (c) 2017 [Ian Maurer], [Genomoncology LLC]
[flow-image]: ./.images/flow.png
[decorators.py]: ./src/related/decorators.py
[fields.py]: ./src/related/fields.py
[functions.py]: ./src/related/functions.py
[attrs]: http://attrs.readthedocs.io/en/stable/
[this article by Glyph]: https://glyph.twistedmatrix.com/2016/08/attrs.html
[Genomoncology LLC]: http://genomoncology.com
[Ian Maurer]: https://github.com/imaurer
[singledispatch library]: https://pypi.python.org/pypi/singledispatch
[monkey-patching]: http://stackoverflow.com/questions/5626193/what-is-a-monkey-patch
[Django ORM]: https://docs.djangoproject.com/en/1.11/topics/db/models/
[UUID]: https://docs.python.org/3/library/uuid.html#uuid.UUID
[uuid4]: https://docs.python.org/3/library/uuid.html#uuid.uuid4
[ParseResult]: https://docs.python.org/2/library/urlparse.html#urlparse.ParseResult
[cattrs]: http://cattrs.readthedocs.io/en/latest/readme.html
[addict]: https://github.com/mewwts/addict
[box]: https://pypi.python.org/pypi/python-box
[Jackson]: https://github.com/FasterXML/jackson
[Docker Compose example]: https://docs.docker.com/compose/gettingstarted/#step-3-define-services-in-a-compose-file
[PyYAML]: https://pypi.python.org/pypi/PyYAML
[tests/]: ./tests/
[Example 00]: ./tests/ex00_sets_hashes
[Example 01]: ./tests/ex01_compose_v2
[Example 02]: ./tests/ex02_compose_v3.2
[Example 03]: ./tests/ex03_company
[Example 04]: ./tests/ex04_contact
[Example 05]: ./tests/ex05_field_names
[Example 06]: ./tests/ex06_json
[Example 07]: ./tests/ex07_serializer
[Example 08]: ./tests/ex08_self_reference
0.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: ImmutableDict
- Add function on TypedMapping
- Bug 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.
Raw data
{
"_id": null,
"home_page": "https://github.com/genomoncology/related",
"name": "related",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "related object models yaml json dict nested",
"author": "",
"author_email": "",
"download_url": "https://files.pythonhosted.org/packages/d9/9f/6e81bf466b6d69f602fa354fddc1ce3138a121de7451c1f105ad5459e890/related-0.7.3.tar.gz",
"platform": null,
"description": "<img src='./.images/logo.png' width='140' align=\"left\" />\n<a href='https://codecov.io/github/genomoncology/related/'><img src='https://codecov.io/github/genomoncology/related/branch/master/graph/badge.svg' align=\"right\" /></a>\n<a href='https://travis-ci.org/genomoncology/related'><img src='https://img.shields.io/travis/genomoncology/related.svg' align=\"right\" /></a>\n<a href='https://pypi.python.org/pypi/related'><img src='https://img.shields.io/pypi/v/related.svg' align=\"right\" /></a>\n\n<br/><br/>\n\n`Related` is a Python library for creating nested object models\nthat can be serialized to and de-serialized from\nnested python dictionaries.\nWhen paired with other libraries (e.g. [PyYAML]),\n`Related` object models can be used to convert to and from\nnested data formats (e.g. JSON, YAML).\n\nExample use cases for `related` object models include:\n\n* Configuration file reading and writing\n* REST API message response generation and request processing\n* Object-Document Mapping for a document store (e.g. MongoDB, elasticsearch)\n* Data import parsing or export generation\n\n<br/>\n\n![flow-image]\n\n<br/>\n\n# Requirements\n\n* Python (2.7, 3.5, 3.6)\n\n\n# Installation\n\nInstall using `pip`...\n\n pip install related\n\n\n# First Example\n\n```python\nimport related\n\n@related.immutable\nclass Person(object):\n first_name = related.StringField()\n last_name = related.StringField()\n\n@related.immutable\nclass RoleModels(object):\n scientists = related.SetField(Person)\n\npeople = [Person(first_name=\"Grace\", last_name=\"Hopper\"),\n Person(first_name=\"Katherine\", last_name=\"Johnson\"),\n Person(first_name=\"Katherine\", last_name=\"Johnson\")]\n\nprint(related.to_yaml(RoleModels(scientists=people)))\n```\n\nYields:\n\n```yaml\nscientists:\n- first_name: Grace\n last_name: Hopper\n- first_name: Katherine\n last_name: Johnson\n```\n\n\n# Second Example\n\nThe below example is based off of this [Docker Compose example].\nIt shows how a YAML file can be loaded into an object model, tested, and\nthen generated back into a string that matches the original YAML.\n\n```yaml\nversion: '2'\nservices:\n web:\n build: .\n ports:\n - 5000:5000\n volumes:\n - .:/code\n redis:\n image: redis\n```\n\nBelow is the `related` object model that represents the above configuration.\nNotice how the name-based mapping of services (i.e. web, redis) are\nrepresented by the model.\n\n\n```python\nimport related\n\n\n@related.immutable\nclass Service(object):\n name = related.StringField()\n image = related.StringField(required=False)\n build = related.StringField(required=False)\n ports = related.SequenceField(str, required=False)\n volumes = related.SequenceField(str, required=False)\n command = related.StringField(required=False)\n\n\n@related.immutable\nclass Compose(object):\n version = related.StringField(required=False, default=None)\n services = related.MappingField(Service, \"name\", required=False)\n```\n\nThe above yaml can then be loaded by using one of the convenience\nmethod and then round-tripped back to yaml to check that the format\nhas been maintained. The `related` module uses `OrderedDict` objects\nin order to maintain sort order by default.\n\n```python\nfrom os.path import join, dirname\n\nfrom model import Compose\nfrom related import to_yaml, from_yaml, to_model\n\nYML_FILE = join(dirname(__file__), \"docker-compose.yml\")\n\n\ndef test_compose_from_yml():\n original_yaml = open(YML_FILE).read().strip()\n yml_dict = from_yaml(original_yaml)\n compose = to_model(Compose, yml_dict)\n\n assert compose.version == '2'\n assert compose.services['web'].ports == [\"5000:5000\"]\n assert compose.services['redis'].image == \"redis\"\n\n generated_yaml = to_yaml(compose,\n suppress_empty_values=True,\n suppress_map_key_values=True).strip()\n\n assert original_yaml == generated_yaml\n```\n\n\n# More Examples\n\nMore examples can be found by reviewing the [tests/] folder of this project.\nBelow are links and descriptions of the tests provided so far.\n\n| Example | description |\n| -------------- | ------------------------------------------------------------------ |\n| [Example 00] | First example above that shows how SetFields work. |\n| [Example 01] | Second example above that demonstrates YAML (de)serialization. |\n| [Example 02] | Compose v3 with long-form ports and singledispatch to_dict |\n| [Example 03] | A single class (Company) with a bunch of value fields. |\n| [Example 04] | A multi-class object model with Enum class value field. |\n| [Example 05] | Handling of renaming of attributes including Python keywords. |\n| [Example 06] | Basic JSON (de)serialization with TimeField, DateTimeField and DecimalField. |\n| [Example 07] | Function decorator that converts inputs to obj and outputs to dict |\n| [Example 08] | Handle self-referencing and out-of-order references using strings. |\n\n\n# Documentation\n\nBelow is a quick version of documentation until more time can be dedicated.\n\n\n## Overview\n\nThe [attrs] library is the underlying engine for `related`.\nAs explained in [this article by Glyph],\n`attrs` cleanly and cleverly\neliminates a lot of the boilerplate\nrequired when creating Python classes\nwithout using inheritance.\nSome core functionality provided by attrs:\n\n* Generated initializer method\n (``__init__``)\n* Generated comparison methods\n (``__eq__``, ``__ne__``, ``__lt__``, ``__le__``, ``__gt__``, ``__ge__`` )\n* Human-readable representation method\n (``__repr__``)\n* Attribute converter and validator framework\n\n\nThe `related` project is an opinionated layer\nbuilt on top of the `attrs` library\nthat provides the following:\n\n* Value fields that handle both validation and conversion\n to and from basic data types like\n ``str``, ``float``, and ``bool``.\n* Nested fields that support relationships such as\n Child, Sequences, Mappings, and Sets of objects.\n* ``to_dict`` function that converts nested object graphs\n to python dictionaries.\n Made customizable (without resorting to [monkey-patching])\n by the [singledispatch library].\n* ``to_model`` function that instantiated classes\n used by the de-serialization process going from\n python dictionaries to the related model.\n* Conversion helper functions\n (``to_yaml``, ``from_yaml``, ``to_json``, ``from_json``)\n for easily going between\n related models and data formats.\n* ``@mutable`` and ``@immutable`` for decorating classes\n as related models without the need for inheritance increasing\n maintainability and flexibility.\n\n\n## Class Decorators\n\n| decorator | description |\n| -------------- | ---------------------------------------------------------------- |\n| @mutable | Activate a related class that instantiates changeable objects. |\n| @immutable | Activate a related class that instantiates unchangeable objects. |\n\nSee the [decorators.py] file to view the source code until proper\ndocumentation is generated.\n\n\n## Field Types\n\n| field type | description |\n| -------------- | ---------------------------------------------------------------- |\n| BooleanField | `bool` value field. |\n| ChildField | Child object of a specified type `cls`. |\n| DateField | `date` field formatted using `formatter`. |\n| DateTimeField | `datetime` field formatted using `formatter`. |\n| TimeField | `time` field formatted using `formatter`. |\n| FloatField | `float` value field. |\n| IntegerField | `int` value field. |\n| MappingField(cls,key) | Dictionary of objects of type `cls` index by `key` field values. |\n| RegexField(regex) | `str` value field that is validated by re.match(`regex`). |\n| SequenceField(cls) | List of objects all of specified type `cls`. |\n| SetField | Set of objects all of a specified type `cls`. |\n| StringField | `str` value field. |\n| URLField | [ParseResult] object. |\n| UUIDField | [UUID] object, will create [uuid4] by default if not specified. |\n\n\nAdding your own field types is fairly straightforward\ndue to the power of the underlying `attrs` project.\nSee the [fields.py] file to see how the above are constructed.\n\n\n## Functions\n\n| function | description |\n| ------------------- | ----------------------------------------------------- |\n| from_json(s,cls) | Convert a JSON string or stream into specified class. |\n| from_yaml(s,cls) | Convert a YAML string or stream into specified class. |\n| is_related(obj) | Returns True if object is @mutable or @immutable. |\n| to_dict(obj) | Singledispatch function for converting to a dict. |\n| to_json(obj) | Convert object to a (pretty) JSON string via to_dict. |\n| to_model(cls,value) | Convert a value to a `cls` instance. |\n| to_yaml(obj) | Convert object to a YAML string via to_dict. |\n\n\nSee the [functions.py] file to view the source code until proper\ndocumentation is generated.\n\n\n# Credits/Prior Art\n\nThe `related` project has been heavily influenced by the following\nprojects that might be worth looking at if `related` doesn't meet your needs.\n\n* [attrs] - The engine that powers `related` functionality.\n* [Django ORM] - Object-relational mapping for Django that inspired `related's` design.\n* [cattrs] - Alternative take for handling nested-objects using `attrs`.\n* [addict] and [box] - Python dictionary wrappers that do not require a model.\n* [Jackson] - Java-based technology for serializing and de-serializing objects.\n\n\n# License\n\nThe MIT License (MIT)\nCopyright (c) 2017 [Ian Maurer], [Genomoncology LLC]\n\n\n\n\n[flow-image]: ./.images/flow.png\n[decorators.py]: ./src/related/decorators.py\n[fields.py]: ./src/related/fields.py\n[functions.py]: ./src/related/functions.py\n[attrs]: http://attrs.readthedocs.io/en/stable/\n[this article by Glyph]: https://glyph.twistedmatrix.com/2016/08/attrs.html\n[Genomoncology LLC]: http://genomoncology.com\n[Ian Maurer]: https://github.com/imaurer\n[singledispatch library]: https://pypi.python.org/pypi/singledispatch\n[monkey-patching]: http://stackoverflow.com/questions/5626193/what-is-a-monkey-patch\n[Django ORM]: https://docs.djangoproject.com/en/1.11/topics/db/models/\n[UUID]: https://docs.python.org/3/library/uuid.html#uuid.UUID\n[uuid4]: https://docs.python.org/3/library/uuid.html#uuid.uuid4\n[ParseResult]: https://docs.python.org/2/library/urlparse.html#urlparse.ParseResult\n[cattrs]: http://cattrs.readthedocs.io/en/latest/readme.html\n[addict]: https://github.com/mewwts/addict\n[box]: https://pypi.python.org/pypi/python-box\n[Jackson]: https://github.com/FasterXML/jackson\n[Docker Compose example]: https://docs.docker.com/compose/gettingstarted/#step-3-define-services-in-a-compose-file\n[PyYAML]: https://pypi.python.org/pypi/PyYAML\n\n[tests/]: ./tests/\n[Example 00]: ./tests/ex00_sets_hashes\n[Example 01]: ./tests/ex01_compose_v2\n[Example 02]: ./tests/ex02_compose_v3.2\n[Example 03]: ./tests/ex03_company\n[Example 04]: ./tests/ex04_contact\n[Example 05]: ./tests/ex05_field_names\n[Example 06]: ./tests/ex06_json\n[Example 07]: ./tests/ex07_serializer\n[Example 08]: ./tests/ex08_self_reference\n\n\n0.7.1 (2018-10-13)\n------------------\n- Add URL to related pypi page [#28]\n- Make singledispatch an optional dependency for < python 3.4. Thanks [GhostofGoes].\n- URLField bug [#20]\n- Deprecation warnings fixed for python 3.7 [#27]\n\n\n0.6.2 (2018-02-12)\n----------------\n- Contribution [GabrielDav]: TimeField and DateTimeField fields.\n\n\n0.6.1 (2018-01-31)\n----------------\n- Strict Mode [Issue #8] throws an exception when receiving an undefined key.\n\n\n0.3 (2017-06-23)\n----------------\n- New type: ImmutableDict\n- Add function on TypedMapping\n- Bug fixes in from_yaml and from_json functions.\n\n\n0.2 (2017-06-05)\n----------------\n- Allow None by default in Typed Collections.\n\n\n0.1 (2017-05-24)\n----------------\n- Initial release.\n",
"bugtrack_url": null,
"license": "MIT license",
"summary": "Related: Straightforward nested object models in Python",
"version": "0.7.3",
"project_urls": {
"Homepage": "https://github.com/genomoncology/related"
},
"split_keywords": [
"related",
"object",
"models",
"yaml",
"json",
"dict",
"nested"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "f5825b30d556a576172b2e771cfa31360884c8fb7edf2c34cee196b30f03e257",
"md5": "02f3bdb2df1c9fc298e73c4c52d300cb",
"sha256": "d9b1f512b231f72911b7564370638b692fae81c54ef25fa4c04773db2ae58b75"
},
"downloads": -1,
"filename": "related-0.7.3-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "02f3bdb2df1c9fc298e73c4c52d300cb",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": null,
"size": 16634,
"upload_time": "2022-08-02T18:30:01",
"upload_time_iso_8601": "2022-08-02T18:30:01.913927Z",
"url": "https://files.pythonhosted.org/packages/f5/82/5b30d556a576172b2e771cfa31360884c8fb7edf2c34cee196b30f03e257/related-0.7.3-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "d99f6e81bf466b6d69f602fa354fddc1ce3138a121de7451c1f105ad5459e890",
"md5": "6c9a6a8056a2ec1e80323c63715d90c7",
"sha256": "22a99ba805ba3ee6cdf46057accb3925ee2ed579202e5f5c6a648636b96b1490"
},
"downloads": -1,
"filename": "related-0.7.3.tar.gz",
"has_sig": false,
"md5_digest": "6c9a6a8056a2ec1e80323c63715d90c7",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 27598,
"upload_time": "2022-08-17T20:54:17",
"upload_time_iso_8601": "2022-08-17T20:54:17.730116Z",
"url": "https://files.pythonhosted.org/packages/d9/9f/6e81bf466b6d69f602fa354fddc1ce3138a121de7451c1f105ad5459e890/related-0.7.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2022-08-17 20:54:17",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "genomoncology",
"github_project": "related",
"travis_ci": true,
"coveralls": false,
"github_actions": false,
"tox": true,
"lcname": "related"
}