{"id":16868697,"url":"https://github.com/vltr/middle","last_synced_at":"2025-04-21T19:31:49.410Z","repository":{"id":37251797,"uuid":"138063484","full_name":"vltr/middle","owner":"vltr","description":"Flexible, extensible Python data structures for general usage","archived":false,"fork":false,"pushed_at":"2025-04-14T20:53:09.000Z","size":206,"stargazers_count":10,"open_issues_count":26,"forks_count":1,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-04-14T21:48:21.796Z","etag":null,"topics":["attrs","customizable","hooks","models","object","primitives","serialization","utilities"],"latest_commit_sha":null,"homepage":"https://middle.readthedocs.io/en/latest/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vltr.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.rst","contributing":"CONTRIBUTING.rst","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.rst","dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-06-20T17:15:26.000Z","updated_at":"2023-01-31T17:01:29.000Z","dependencies_parsed_at":"2023-02-16T11:45:36.698Z","dependency_job_id":"b19d99ec-1f46-4320-bc7b-74f35570772a","html_url":"https://github.com/vltr/middle","commit_stats":{"total_commits":97,"total_committers":2,"mean_commits":48.5,"dds":"0.020618556701030966","last_synced_commit":"f7782610fbb1d9232a3b4cfea057a9331db2775e"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vltr%2Fmiddle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vltr%2Fmiddle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vltr%2Fmiddle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vltr%2Fmiddle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vltr","download_url":"https://codeload.github.com/vltr/middle/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250119944,"owners_count":21378116,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["attrs","customizable","hooks","models","object","primitives","serialization","utilities"],"created_at":"2024-10-13T14:59:10.677Z","updated_at":"2025-04-21T19:31:49.135Z","avatar_url":"https://github.com/vltr.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"==========\n``middle``\n==========\n\n.. start-badges\n\n.. image:: https://img.shields.io/pypi/status/middle.svg\n    :alt: PyPI - Status\n    :target: https://pypi.org/project/middle/\n\n.. image:: https://img.shields.io/pypi/v/middle.svg\n    :alt: PyPI Package latest release\n    :target: https://pypi.org/project/middle/\n\n.. image:: https://img.shields.io/pypi/pyversions/middle.svg\n    :alt: Supported versions\n    :target: https://pypi.org/project/middle/\n\n.. image:: https://travis-ci.org/vltr/middle.svg?branch=master\n    :alt: Travis-CI Build Status\n    :target: https://travis-ci.org/vltr/middle\n\n.. image:: https://ci.appveyor.com/api/projects/status/github/vltr/middle?branch=master\u0026svg=true\n    :alt: AppVeyor Build Status\n    :target: https://ci.appveyor.com/project/vltr/middle\n\n.. image:: https://readthedocs.org/projects/middle/badge/?style=flat\n    :target: https://readthedocs.org/projects/middle\n    :alt: Documentation Status\n\n.. image:: https://codecov.io/github/vltr/middle/coverage.svg?branch=master\n    :alt: Coverage Status\n    :target: https://codecov.io/github/vltr/middle\n\n.. image:: https://api.codacy.com/project/badge/Grade/10c6ef32dfbe497087d57c9d86c02c80\n    :alt: Codacy Grade\n    :target: https://www.codacy.com/app/vltr/middle?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=vltr/middle\u0026amp;utm_campaign=Badge_Grade\n\n.. image:: https://pyup.io/repos/github/vltr/middle/shield.svg\n    :target: https://pyup.io/account/repos/github/vltr/middle/\n    :alt: Packages status\n\n.. end-badges\n\nFlexible, extensible Python data structures for general usage. Get data in and out, reliably, without boilerplate and with speed!\n\n``middle`` stands on the shoulders of ``attrs`` and aims to be as simple as possible to get data from complex objects to Python primitives and vice-versa, with validators, converters, a lot of sugar and other utilities! ``middle`` can be used with your preferred web framework, background job application, configuration parser and more!\n\nSneak peek\n----------\n\nThe most simple example of ``middle`` and some of its features (using Python 3.6+ syntax):\n\n.. code-block:: pycon\n\n    \u003e\u003e\u003e import typing\n    \u003e\u003e\u003e import middle\n\n    \u003e\u003e\u003e class Address(middle.Model):\n    ...     street_name: str\n    ...     number: typing.Optional[int]\n    ...     city: str\n\n    \u003e\u003e\u003e class Person(middle.Model):\n    ...     name: str\n    ...     age: int\n    ...     address: typing.Dict[str, Address]\n\n    \u003e\u003e\u003e data = {\n    ...     \"name\": \"John Doe\",\n    ...     \"age\": 42,\n    ...     \"address\": {\n    ...         \"home\": {\n    ...             \"street_name\": \"Foo St\",\n    ...             \"number\": None,\n    ...             \"city\": \"Python Park\"\n    ...         },\n    ...         \"work\": {\n    ...             \"street_name\": \"Bar Blvd\",\n    ...             \"number\": \"1337\",\n    ...             \"city\": \"Park City\"\n    ...         }\n    ...     }\n    ... }\n\n    \u003e\u003e\u003e person = Person(data)\n\n    \u003e\u003e\u003e person\n    Person(name='John Doe', age=42, address={'home': Address(street_name='Foo St', number=None, city='Python Park'), 'work': Address(street_name='Bar Blvd', number=1337, city='Park City')})\n\n    \u003e\u003e\u003e middle.asdict(person)\n    {'name': 'John Doe', 'age': 42, 'address': {'home': {'street_name': 'Foo St', 'number': None, 'city': 'Python Park'}, 'work': {'street_name': 'Bar Blvd', 'number': 1337, 'city': 'Park City'}}}\n\nWanted a more complex example, with Python 3.5 compatible syntax? For sure!\n\n.. code-block:: pycon\n\n    \u003e\u003e\u003e from typing import Dict, List\n    \u003e\u003e\u003e import middle\n\n    \u003e\u003e\u003e class Game(middle.Model):\n    ...     name: str = middle.field()\n    ...     score: float = middle.field(minimum=0, maximum=10)\n    ...     resolution_tested: str = middle.field(pattern=\"^\\d+x\\d+$\")\n    ...     genre: List[str] = middle.field(unique_items=True)\n    ...     rating: Dict[str, float] = middle.field(max_properties=5)\n\n    \u003e\u003e\u003e data = {\n    ...     \"name\": \"Cities: Skylines\",\n    ...     \"score\": 9.0,\n    ...     \"resolution_tested\": \"1920x1200\",\n    ...     \"genre\": [\"Simulators\", \"City Building\"],\n    ...     \"rating\": {\n    ...         \"IGN\": 8.5,\n    ...         \"Gamespot\": 8.0,\n    ...         \"Steam\": 4.5\n    ...     }\n    ... }\n\n    \u003e\u003e\u003e game = Game(**data)\n\n    \u003e\u003e\u003e game\n    Game(name='Cities: Skylines', score=9.0, resolution_tested='1920x1200', genre=['Simulators', 'City Building'], rating={'IGN': 8.5, 'Gamespot': 8.0, 'Steam': 4.5})\n\n    \u003e\u003e\u003e middle.asdict(game)\n    {'name': 'Cities: Skylines', 'score': 9.0, 'resolution_tested': '1920x1200', 'genre': ['Simulators', 'City Building'], 'rating': {'IGN': 8.5, 'Gamespot': 8.0, 'Steam': 4.5}}\n\n\n``middle`` is flexible enough to understand ``Enum``, nested models and a large variety of types declared on the ``typing`` module out of the box. Also, you can `extend it \u003chttps://middle.readthedocs.io/en/latest/extending.html\u003e`_ to your own classes!\n\n.. warning::\n\n    **IMPORTANT**: ``middle`` is in **very early stages** of development. There are some requirements (like ``python-dateutil``) that would not be required in future releases; as there's a lot of functionalities that needs to be implemented and some known misbehaviors to be addressed, not to mention it needs a lot of testing before moving to any other status rather than **alpha**.\n\nTODO\n====\n\n- Alias options (keys) to populate classes;\n- Read-only and write-only fields;\n- Better error handling (almost everywhere);\n- Create a benchmark suite against other solutions;\n- Formatters are still missing;\n- Possibility to \"cast\" an instance to another instance where the original object is a subclass of it;\n\nDone\n----\n\n- If possible, fine grain the converters, so a ``str`` input value of ``{}`` doesn't end up as ``str({})``;\n- Get ``date`` and ``datetime`` converters to be customizable, instead of an ``if isinstance`` statement;\n- Implement more validators and a registerable for more metadata options;\n- Implement a better \"type dispatcher\" based on more complex rules (other than ``type(field.type)`` delivered by ``functools.singledispatch``) because the ``typing`` module has changed **a bit** between Python 3.6 and 3.7;\n- Support more types (``typing.Tuple``, ``decimal.Decimal``);\n- Get 100% (or closer) in code coverage;\n- Lots of documentation;\n- Python 3.5 support (with the exception of Windows platforms, see warning for Windows developers below);\n\nFuture discussions\n------------------\n\n- In Python 3.7, a neat feature was added: ``dataclasses``. I know it sounds really awesome to not depend on a 3rd-party library - such as ``attrs``, but the latest provides a lot of functionalities that can't be found on Python 3.7 ``dataclasses`` (for now), so I'll leave this open for further discussion.\n\nWarning for Windows developers\n------------------------------\n\nIf you're using Windows and Python 3.5, I think ``middle`` would not work well for you. CI in AppVeyor was disabled for Python 3.5 because of `this issue \u003chttps://github.com/python/typing/issues/523\u003e`_. If Guido doesn't care, why should I (or you) ?\n\nDocumentation\n=============\n\nhttps://middle.readthedocs.io/en/latest/\n\nUseful links\n------------\n\n* `Source code \u003chttps://github.com/vltr/middle\u003e`_\n* `Issues \u003chttps://github.com/vltr/middle/issues\u003e`_\n\nInspirations and thanks\n=======================\n\nSome libs that inspired the creation of ``middle``:\n\n- `attrs \u003chttp://www.attrs.org/en/stable/\u003e`_: how such a simple library can be such flexible, extendable and fast?\n- `cattrs \u003chttps://github.com/Tinche/cattrs\u003e`_: for its speed on creating ``attrs`` instances from ``dict`` and to instances again;\n- `pydantic \u003chttps://pydantic-docs.helpmanual.io/\u003e`_: for such pythonic and beautiful approach on creating classes using ``typing`` hints;\n- `mashmallow \u003chttps://marshmallow.readthedocs.io/en/latest/\u003e`_: it is one of the most feature rich modelling APIs I've seen;\n- `apistar \u003chttps://docs.apistar.com/\u003e`_: it's almost magical!\n- `Sanic \u003chttp://sanic.readthedocs.io/en/latest/\u003e`_: \"*Gotta go fast!*\"\n- `ionelmc/cookiecutter-pylibrary \u003chttps://github.com/ionelmc/cookiecutter-pylibrary\u003e`_: The most complete (or interesting) ``cookiecutter`` template I found so far (make sure to `read this article \u003chttps://blog.ionelmc.ro/2014/05/25/python-packaging/\u003e`_ too);\n\nLicense\n=======\n\n``middle`` is a free software distributed under the `MIT \u003chttps://choosealicense.com/licenses/mit/\u003e`_ license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvltr%2Fmiddle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvltr%2Fmiddle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvltr%2Fmiddle/lists"}