related-without-future


Namerelated-without-future JSON
Version 0.7.4 PyPI version JSON
download
home_pagehttps://github.com/Antoni-Czaplicki/related-without-future
SummaryRelated: Straightforward nested object models in Python
upload_time2023-12-16 13:17:49
maintainer
docs_urlNone
author
requires_python
licenseMIT license
keywords related object models yaml json dict nested
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI
coveralls test coverage No coveralls.
            <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/>

This fork sacrifices support for Python 2.7 in favorof Python 3.12

`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 3.5+


# 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/Antoni-Czaplicki/related-without-future",
    "name": "related-without-future",
    "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/f5/74/84685ef2dd329d56212cc16cf721494f925cf4407b351a48dd07e60807cc/related-without-future-0.7.4.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\nThis fork sacrifices support for Python 2.7 in favorof Python 3.12\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 3.5+\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.4",
    "project_urls": {
        "Homepage": "https://github.com/Antoni-Czaplicki/related-without-future"
    },
    "split_keywords": [
        "related",
        "object",
        "models",
        "yaml",
        "json",
        "dict",
        "nested"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "15ce986e69348899c8e687c9b29f704a96d9773149b0d3cb7f91e9c18a3979a5",
                "md5": "4c90a7a1d960703f34ff4e139e0451b4",
                "sha256": "1ef8f6da46fd5d638a5ede7256a9c3a7d64419394e3fa2642e7e76f3e66eda7d"
            },
            "downloads": -1,
            "filename": "related_without_future-0.7.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "4c90a7a1d960703f34ff4e139e0451b4",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 16815,
            "upload_time": "2023-12-16T13:17:47",
            "upload_time_iso_8601": "2023-12-16T13:17:47.992636Z",
            "url": "https://files.pythonhosted.org/packages/15/ce/986e69348899c8e687c9b29f704a96d9773149b0d3cb7f91e9c18a3979a5/related_without_future-0.7.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f57484685ef2dd329d56212cc16cf721494f925cf4407b351a48dd07e60807cc",
                "md5": "b70f9c1fc054f70dd0c4c7c22ea477a0",
                "sha256": "934d75a409003a70a062d7ce65c3606f43e267cbae425c365b5772815880bdce"
            },
            "downloads": -1,
            "filename": "related-without-future-0.7.4.tar.gz",
            "has_sig": false,
            "md5_digest": "b70f9c1fc054f70dd0c4c7c22ea477a0",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 27794,
            "upload_time": "2023-12-16T13:17:49",
            "upload_time_iso_8601": "2023-12-16T13:17:49.598857Z",
            "url": "https://files.pythonhosted.org/packages/f5/74/84685ef2dd329d56212cc16cf721494f925cf4407b351a48dd07e60807cc/related-without-future-0.7.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-12-16 13:17:49",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Antoni-Czaplicki",
    "github_project": "related-without-future",
    "travis_ci": true,
    "coveralls": false,
    "github_actions": false,
    "tox": true,
    "lcname": "related-without-future"
}
        
Elapsed time: 0.22653s