{ "info": { "author": "Richard Kuesters", "author_email": "rkuesters@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Operating System :: Unix", "Programming Language :: Python", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Utilities" ], "description": "==========\n``middle``\n==========\n\n\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 >>> import typing\n >>> import middle\n\n >>> class Address(middle.Model):\n ... street_name: str\n ... number: typing.Optional[int]\n ... city: str\n\n >>> class Person(middle.Model):\n ... name: str\n ... age: int\n ... address: typing.Dict[str, Address]\n\n >>> 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 >>> person = Person(data)\n\n >>> 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 >>> 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 >>> from typing import Dict, List\n >>> import middle\n\n >>> 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 >>> 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 >>> game = Game(**data)\n\n >>> 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 >>> 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 `_ 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 `_. 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 `_\n* `Issues `_\n\nInspirations and thanks\n=======================\n\nSome libs that inspired the creation of ``middle``:\n\n- `attrs `_: how such a simple library can be such flexible, extendable and fast?\n- `cattrs `_: for its speed on creating ``attrs`` instances from ``dict`` and to instances again;\n- `pydantic `_: for such pythonic and beautiful approach on creating classes using ``typing`` hints;\n- `mashmallow `_: it is one of the most feature rich modelling APIs I've seen;\n- `apistar `_: it's almost magical!\n- `Sanic `_: \"*Gotta go fast!*\"\n- `ionelmc/cookiecutter-pylibrary `_: The most complete (or interesting) ``cookiecutter`` template I found so far (make sure to `read this article `_ too);\n\nLicense\n=======\n\n``middle`` is a free software distributed under the `MIT `_ license.\n\n\nChangelog\n=========\n\nv0.2.2 on 2018-10-28\n--------------------\n\n* Added the possibility for models to have methods, functions, properties and etc.\n\nv0.2.1 on 2018-07-26\n--------------------\n\n* Quick fix related to the change log and MANIFEST.in files\n\nv0.2.0 on 2018-07-26\n--------------------\n\n* Released (part) of the documentation\n* Got 99% coverage (finally combined)\n* Python 3.5 support added\n\nv0.1.1 on 2018-07-02\n--------------------\n\n* Add proper unit testing and support for Python 3.6 and 3.7\n* Made the API a bit more flexible\n* Code format and check done with `black `_\n\nv0.1.0 on 2018-06-21\n--------------------\n\n* First release on PyPI.\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/vltr/middle", "keywords": "attrs,object,primitives,serialization,models,hooks,customizable,utilities", "license": "MIT license", "maintainer": "", "maintainer_email": "", "name": "middle", "package_url": "https://pypi.org/project/middle/", "platform": "", "project_url": "https://pypi.org/project/middle/", "project_urls": { "Homepage": "https://github.com/vltr/middle" }, "release_url": "https://pypi.org/project/middle/0.2.4/", "requires_dist": [ "attrs (>=19.1.0)", "python-dateutil (>=2.8.0)" ], "requires_python": "", "summary": "Flexible, extensible Python data structures for general usage", "version": "0.2.4" }, "last_serial": 5415936, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "bfcd871c21bb1b43364584939c4e088d", "sha256": "13d521384174a62a3cc202a04089111c0a0001ea75631c81f9d52a233fc31f57" }, "downloads": -1, "filename": "middle-0.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "bfcd871c21bb1b43364584939c4e088d", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 9521, "upload_time": "2018-06-21T20:01:25", "url": "https://files.pythonhosted.org/packages/6f/9c/5c34d71fa1a603a4bdeac57b5ce18bc67cf52933b1801ef178a3ad700374/middle-0.1.0-py2.py3-none-any.whl" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "339d5f018765d37788c1c359a9376066", "sha256": "2fd80d80abbadb1f1b88178c369a073beb326d5fb5a65e9177847cb5affdfd60" }, "downloads": -1, "filename": "middle-0.1.1.linux-x86_64.tar.gz", "has_sig": false, "md5_digest": "339d5f018765d37788c1c359a9376066", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23794, "upload_time": "2018-07-02T18:28:54", "url": "https://files.pythonhosted.org/packages/c1/a7/9e0ee4184fba3cd685b4bbda6ec28005cb83dce066e5e7f2be88dbf34810/middle-0.1.1.linux-x86_64.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "feb97e54600f9e4628001114cde8a252", "sha256": "b9fa7f05be81c0e46efaee4120d66b3b4b60764395a5334ba46cd71e22cf0adc" }, "downloads": -1, "filename": "middle-0.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "feb97e54600f9e4628001114cde8a252", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 18204, "upload_time": "2018-07-26T20:12:54", "url": "https://files.pythonhosted.org/packages/ed/a2/de8be360659afde5609ea80b333e524d4dbc93531bf53faf6eb937ef9bad/middle-0.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "340f05eb40285802b13b92262c020607", "sha256": "68004f207e3ecbe6f6e33e7cac4b70603ef2adbe53c4d2af1234b4c25206be76" }, "downloads": -1, "filename": "middle-0.2.0.tar.gz", "has_sig": false, "md5_digest": "340f05eb40285802b13b92262c020607", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 63676, "upload_time": "2018-07-26T20:12:56", "url": "https://files.pythonhosted.org/packages/1c/c9/a1b53472bc37a28ecc8bab8675a73b61431e5217ae6755b6a36624572358/middle-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "48c09ac3f04856cabea9fddc9dc191d6", "sha256": "9ef8b9cfb6d3d6b8fe2e1eb4064d7df133fb13ac47f593ac08b00a77c124bf44" }, "downloads": -1, "filename": "middle-0.2.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "48c09ac3f04856cabea9fddc9dc191d6", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 18256, "upload_time": "2018-07-26T20:24:03", "url": "https://files.pythonhosted.org/packages/18/4e/be515ce78bf8a633bd2377b41bb9c8c920a071a8809c0ed78b5f06e75770/middle-0.2.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9cdc25f6ad7e8ddf90e50b4a63958ad6", "sha256": "5ed98047a4ccbfffa59b0a583a281d6f6a39f806719372d146b7539dd00f5a29" }, "downloads": -1, "filename": "middle-0.2.1.tar.gz", "has_sig": false, "md5_digest": "9cdc25f6ad7e8ddf90e50b4a63958ad6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 63783, "upload_time": "2018-07-26T20:24:04", "url": "https://files.pythonhosted.org/packages/e8/b0/fe4040dc501ca41745c8dcec02e8a2ae0555d9f0a0fd037f255c825f7362/middle-0.2.1.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "3d8ea01de2d5d62c1c766b9f8f3c9bb8", "sha256": "3a821786eaeab41c1ce6c4110d84105fda2a1eb5421018009ec2589374c7bba9" }, "downloads": -1, "filename": "middle-0.2.2-py3-none-any.whl", "has_sig": false, "md5_digest": "3d8ea01de2d5d62c1c766b9f8f3c9bb8", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20017, "upload_time": "2018-10-26T15:35:08", "url": "https://files.pythonhosted.org/packages/58/27/464407640308033d70594360b620606ac13d66274d4ad0043402423d181e/middle-0.2.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "91fc9c8de6a7a03134d6c8678dafc470", "sha256": "53da043ec7a74e6a84a4280f356ab6d246e84356bb4cb42ebfa03c5e547fb0e8" }, "downloads": -1, "filename": "middle-0.2.2.tar.gz", "has_sig": false, "md5_digest": "91fc9c8de6a7a03134d6c8678dafc470", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 61154, "upload_time": "2018-10-26T15:35:10", "url": "https://files.pythonhosted.org/packages/c2/73/ac9341bd9cb326961d64bb675592c9a12a0a8f544014fa1e70c1c9d37734/middle-0.2.2.tar.gz" } ], "0.2.4": [ { "comment_text": "", "digests": { "md5": "c64753af3a80e3ecaba28bc462922872", "sha256": "d5d2d0b62ce8f33d29c1a8bc193754019b401e9395f323e6afc00f69e4215564" }, "downloads": -1, "filename": "middle-0.2.4-py3-none-any.whl", "has_sig": false, "md5_digest": "c64753af3a80e3ecaba28bc462922872", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20029, "upload_time": "2019-06-18T15:13:56", "url": "https://files.pythonhosted.org/packages/8e/70/856c72196dd8c22850fc0bb0ca31e9c10d3467bca0a6fe67bff3a0c0ce0e/middle-0.2.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "79814741ec0b0a6dd1bd9052d603145e", "sha256": "95c3971b7bf7fe8c98e112be098b38e519a572cfa18870811388c2daa3c62a89" }, "downloads": -1, "filename": "middle-0.2.4.tar.gz", "has_sig": false, "md5_digest": "79814741ec0b0a6dd1bd9052d603145e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 61007, "upload_time": "2019-06-18T15:13:59", "url": "https://files.pythonhosted.org/packages/0a/81/1021ea18bbb00f76e24a0681dbdfa05f3f28ed0ac65fdc3724263a84456b/middle-0.2.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "c64753af3a80e3ecaba28bc462922872", "sha256": "d5d2d0b62ce8f33d29c1a8bc193754019b401e9395f323e6afc00f69e4215564" }, "downloads": -1, "filename": "middle-0.2.4-py3-none-any.whl", "has_sig": false, "md5_digest": "c64753af3a80e3ecaba28bc462922872", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20029, "upload_time": "2019-06-18T15:13:56", "url": "https://files.pythonhosted.org/packages/8e/70/856c72196dd8c22850fc0bb0ca31e9c10d3467bca0a6fe67bff3a0c0ce0e/middle-0.2.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "79814741ec0b0a6dd1bd9052d603145e", "sha256": "95c3971b7bf7fe8c98e112be098b38e519a572cfa18870811388c2daa3c62a89" }, "downloads": -1, "filename": "middle-0.2.4.tar.gz", "has_sig": false, "md5_digest": "79814741ec0b0a6dd1bd9052d603145e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 61007, "upload_time": "2019-06-18T15:13:59", "url": "https://files.pythonhosted.org/packages/0a/81/1021ea18bbb00f76e24a0681dbdfa05f3f28ed0ac65fdc3724263a84456b/middle-0.2.4.tar.gz" } ] }