{ "info": { "author": "Jackson J. Gilman", "author_email": "jackson.gilman@cardinalhealth.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3 :: Only", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Quality Assurance" ], "description": "====================================================\n`typycal` -- A handy tool to make type-aware classes\n====================================================\n\n.. image:: https://img.shields.io/pypi/v/typycal.svg\n :target: https://pypi.org/project/typycal/\n\n.. image:: https://img.shields.io/pypi/pyversions/typycal.svg\n :target: https://pypi.org/project/typycal/\n\n.. image:: https://travis-ci.org/cardinal-health/typycal.svg?branch=master\n :target: https://travis-ci.org/cardinal-health/typycal\n\n.. image:: https://coveralls.io/repos/github/cardinal-health/typycal/badge.svg?branch=master\n :target: https://coveralls.io/github/cardinal-health/typycal?branch=master\n\n.. note::\n\n Yes, Python 3.7 introduced data classes, which basically provide the\n majority of features this library offers. Future development will likely\n cover helpers for this new feature.\n\n Still, there are some other cool uses for this library!\n\nThis lightweight library is for the developer who enjoys the assistance provided\nby Python's type annotations.\n\n^^^^^^^^^^^^^\n``typed_env``\n^^^^^^^^^^^^^\n\nIf your Python program relies on a custom os environment, it can be difficult to\nremember the string names for all those variables. This decorator will provide\na means to deal with your environment in an object-oriented fashion.\n\n>>> from typycal import typed_env\n>>> import os\n>>> import pathlib\n\nFor example, say your program obtains database connection info from the\nenvironment\n\n>>> os.environ.update({'DB_HOSTNAME': 'localhost', 'DB_PORT': '3306'})\n>>> os.getenv('DB_PORT')\n'3306'\n\nYou can itemize all the environment variables you use in one class\n\n>>> @typed_env\n... class Environment:\n... DB_HOSTNAME: str\n... DB_PORT: int\n... DB_USER: str = 'default_user'\n... README_PATH: pathlib.Path = 'README.rst'\n... JSON_DATA: dict = {'foo': 'bar'}\n\nThen you can create a singleton instance for use by the rest of your program\n\n>>> env = Environment()\n\nAnd your variables will be typed appropriately\n\n>>> (env.DB_HOSTNAME, env.DB_PORT, env.DB_USER)\n('localhost', 3306, 'default_user')\n\nAnd maintained in env properly\n\n>>> os.getenv('JSON_DATA')\n'{\"foo\": \"bar\"}'\n\nYou can do some neat things...\n\n>>> assert env.README_PATH.exists()\n\nIf you want to enforce the presence of certain variables in your environment,\nyou can add them this way\n\n>>> @typed_env\n... class StricterEnvironment:\n... __required_on_init__ = ('NEED_ME', )\n...\n... NEED_ME: str\n\nAn error will be thrown immediately when the environment object is instantiated.\n\n>>> stricter_env = StricterEnvironment()\nTraceback (most recent call last):\n ...\nOSError: Variable 'NEED_ME' is required, but has not been defined.\n\n\n^^^^^^^^^^^^^^\n``typed_dict``\n^^^^^^^^^^^^^^\n\nThis decorator offers a simple, declarative means of converting a plain Python\ndictionary or string object into a type-aware object, with properties to access\na defined set of keys.\n\nDevelopers working with REST APIs or any data loaded as a dictionary can use\ntypycal to effectively design \"contracts\" with their code, and ideally end up\nwith more readable software\n\nThat said, since the release of Python 3.7, you likely will be better served\nwith data classes.\n\nLet's say you have a settings file sitting somewhere, and it's loaded into your\nproject as a dictionary (such as ``json.load``, ``yaml.safe_load``, etc...):\n\n.. code:: json\n\n {\n \"db\": {\n \"username\": \"maxwell\",\n \"password\": \"SECRET\",\n \"port\": \"5432\",\n \"use_ssl\": false\n },\n \"log_level\": \"DEBUG\"\n }\n\n\n...let's say this configuration gets real messy real quick. It can be a\nreal pain to have to remember the names of all your keys for what becomes a\nPython ``dict``. So, here's an easy way to wrap your project's configuration in\na type-aware object\n\n>>> from typycal import typed_dict\n>>> @typed_dict\n... class DBConfig(dict):\n... username: str\n... password: str\n... port: int\n... use_ssl: bool\n\n>>> @typed_dict\n... class ProjectConfig(dict):\n... log_level: str\n... db: DBConfig\n\n>>> settings = {\n... \"db\": {\n... 'username': 'maxwell',\n... 'password': 'SECRET',\n... 'port': '5432',\n... },\n... 'log_level': 'DEBUG'\n... }\n>>> config = ProjectConfig(settings)\n\n\n>>> config.db.username == 'maxwell'\nTrue\n\n>>> config.db.port == 5432\nTrue\n\nSee that? Even though you passed a string for the port, because you explicitly\ndefined the type, it was cast for you! Now, let's try to access a missing\nproperty\n\n>>> config.db.use_ssl is None\nTrue\n\nNote, an AttributeError wasn't raised because by default, ``typed_dict`` will\ndecorate your class so that any unset values which you have declared a type for\nwill be set to ``None`` You can disable this as follows\n\n>>> @typed_dict(initialize_with_none=False)\n... class StricterConfig(dict):\n... foo: str\n... bar: int\n\n>>> StricterConfig({'foo': 30}).bar\nTraceback (most recent call last):\n ...\nAttributeError: 'StricterConfig' object has no attribute 'bar'\n\nThis makes the object-like treatment of the `dict` behave closer to how Python\nwould yell at you about accessing missing object attributes.\n\n^^^^^^^^^^^^^\n``typed_str``\n^^^^^^^^^^^^^\n\nAnother handy thing this library gives you is a way to quickly validate a string\nwith a regex, and then store the group match values as attributes on the str,\nand access them. Here's a (roughly) complete example\n\n\n>>> model_pattern = r\"([0-9]{4}) (Ford|Toyota) (.+)\"\n\n>>> from typycal import typed_str\n>>> @typed_str(model_pattern, 'year', 'make', 'name')\n... class CarModel(str):\n... year: int\n... make: str\n... name: str\n\n>>> @typed_str(r'(?P[A-Za-z]+) (?P.+)')\n... class Car(str):\n... color: str\n... model: CarModel\n\n>>> my_car = Car('Brown 1985 Ford Crown Victoria')\n\nNow we can get attributes for the matches!\n\n>>> my_car.color == \"Brown\"\nTrue\n\nNesting and types are honored as well!\n\n>>> my_car.model.year == 1985\nTrue\n\nYou can provide a template string as well to support (kinda) mutability.\n\n>>> @typed_str(r'^([0-9]+) things', 'qty', template='{qty} things')\n... class Things(str):\n... qty: int\n\n>>> things = Things('20 things')\n>>> things.qty = 50\n>>> things\n50 things\n\nNote however, this only changes the behavior of ``__str__`` and ``__repr__``.\nSee the comparison of the \"new\" value vs the original string value:\n\n>>> things == '50 things', things == '20 things'\n(False, True)\n\n...so you'll need to explicitly cast\n\n>>> str(things) == '50 things'\nTrue\n\n----------\nChange Log\n----------\n\nSee CHANGELOG.rst", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/cardinal-health/typycal", "keywords": "", "license": "Apache License 2.0", "maintainer": "", "maintainer_email": "", "name": "typycal", "package_url": "https://pypi.org/project/typycal/", "platform": "", "project_url": "https://pypi.org/project/typycal/", "project_urls": { "Homepage": "https://github.com/cardinal-health/typycal" }, "release_url": "https://pypi.org/project/typycal/0.7.0/", "requires_dist": null, "requires_python": "", "summary": "Easily add type intelligence to simple Python objects", "version": "0.7.0" }, "last_serial": 4395799, "releases": { "0.4.0": [ { "comment_text": "", "digests": { "md5": "c4a7c27d2ea2159ee9bd3ff61fc2d40b", "sha256": "85cf382e166f8ced9bbb3c862ebefb920974313756da6a299eef54b9dad4185e" }, "downloads": -1, "filename": "typycal-0.4.0.tar.gz", "has_sig": false, "md5_digest": "c4a7c27d2ea2159ee9bd3ff61fc2d40b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3462, "upload_time": "2018-06-05T02:22:45", "url": "https://files.pythonhosted.org/packages/0b/49/ba6ae554d88e6e4e190e9f3ab532deb66b50ea50fd62a3d31e9ec2dc3c7f/typycal-0.4.0.tar.gz" } ], "0.5.2": [ { "comment_text": "", "digests": { "md5": "d8121c9b1d57d8126fd5b6046581d65b", "sha256": "d34f4b09c7eafbd0840bf10139a7a065efd62b09927e456a968b22dafdb26e94" }, "downloads": -1, "filename": "typycal-0.5.2.tar.gz", "has_sig": false, "md5_digest": "d8121c9b1d57d8126fd5b6046581d65b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6711, "upload_time": "2018-07-25T17:53:12", "url": "https://files.pythonhosted.org/packages/59/2b/f7451ee496cf981be646677c0370bed70d7d5943f119d2989424d2da7e4f/typycal-0.5.2.tar.gz" } ], "0.6.0": [ { "comment_text": "", "digests": { "md5": "100673dddd537442e7d396ae8300ddab", "sha256": "2cb827ad14a793434deb7b380fbeb7f18dc2732c4bd950f5971f3c9ef9176b97" }, "downloads": -1, "filename": "typycal-0.6.0.tar.gz", "has_sig": false, "md5_digest": "100673dddd537442e7d396ae8300ddab", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7894, "upload_time": "2018-09-18T22:41:20", "url": "https://files.pythonhosted.org/packages/47/af/02fb7472d425915104e832cb97a5c46d01705e31e80a2e81f16f58af74c3/typycal-0.6.0.tar.gz" } ], "0.7.0": [ { "comment_text": "", "digests": { "md5": "48f619ae2b6dc76e272b73afa5c9f5f1", "sha256": "58f6cbb3c13347c411372d8f2949fbce087b12a62cd6af29510d71a9f9191072" }, "downloads": -1, "filename": "typycal-0.7.0.tar.gz", "has_sig": false, "md5_digest": "48f619ae2b6dc76e272b73afa5c9f5f1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8512, "upload_time": "2018-10-19T21:13:18", "url": "https://files.pythonhosted.org/packages/aa/f1/be67262572cd09c55370daefa6e4a0cfae26e0f731b132224c458fba1c80/typycal-0.7.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "48f619ae2b6dc76e272b73afa5c9f5f1", "sha256": "58f6cbb3c13347c411372d8f2949fbce087b12a62cd6af29510d71a9f9191072" }, "downloads": -1, "filename": "typycal-0.7.0.tar.gz", "has_sig": false, "md5_digest": "48f619ae2b6dc76e272b73afa5c9f5f1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8512, "upload_time": "2018-10-19T21:13:18", "url": "https://files.pythonhosted.org/packages/aa/f1/be67262572cd09c55370daefa6e4a0cfae26e0f731b132224c458fba1c80/typycal-0.7.0.tar.gz" } ] }