{ "info": { "author": "Joe Jevnik", "author_email": "joejev@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Pre-processors", "Topic :: Utilities" ], "description": "metautils3\n==========\n\nExperimental utilities for writing and composing metaclasses.\n\nFor safe and stable metaclass utilities, see metautils_\n\nTemplate Model\n--------------\n\nWhy do we need or want to write class templates.\n\nConsider the two metaclasses.\n\n.. code:: python\n\n class AllLower(type):\n def __new__(mcls, name, bases, dict_):\n dict_ = {k.lower(): v for k, v in dict_.items()}\n return super().__new__(mcls, name, bases, dict_)\n\n\n class MethodCatcher(type):\n def __new__(mcls, name, bases, dict_):\n dict_['methods'] = [v for v in dict_.values() if callable(v)]\n return super().__new__(mcls, name, bases, dict_)\n\nWhat would we do if we wanted to make a class that used *BOTH* of these\nmetaclasses? Using a class that subclasses both ``AllLower`` and\n``MethodCatcher`` does not work, what we want is a way to chain them.\n\nWith the class template model, we could have written our metaclasses\nas:\n\n.. code:: python\n\n from metautils3 import T, templated\n\n class AllLower(T):\n @templated\n def __new__(mcls, name, bases, dict_):\n dict_ = {k.lower(): v for k, v in dict_.items()}\n return super().__new__(mcls, name, bases, dict_)\n\n\n class MethodCatcher(T):\n @templated\n def __new__(mcls, name, bases, dict_):\n dict_['methods'] = [v for v in dict_.values() if callable(v)];\n return super().__new__(mcls, name, bases, dict_)\n\n\nPython 2 style super calls will also work, like: ``super(AllLower, mcls)``.\nWe can write the above classes without using super by delagating to ``T``\njust like we would delegate to a concrete class, for example:\n\n.. code:: python\n\n from metautils3 import T, templated\n\n class AllLower(T):\n @templated\n def __new__(mcls, name, bases, dict_):\n dict_ = {k.lower(): v for k, v in dict_.items()}\n return T.__new__(mcls, name, bases, dict_)\n\n\n class MethodCatcher(T):\n @templated\n def __new__(mcls, name, bases, dict_):\n dict_['methods'] = [v for v in dict_.values() if callable(v)];\n return T.__new__(mcls, name, bases, dict_)\n\n\nInside the context of a templated function, ``T`` with refer to the concrete\nclass that was used to instantiate an instance of the template.\nAnother name that will be changed out from under you is the class name\nitself. When you are in the context of a method, the class name will actually\nresolve to the concrete type.\n\nNow we can define classes that use *BOTH* of these metaclasses like so:\n\n.. code:: python\n\n class C(object, metaclass=MethodCatcher(AllLower())):\n def F():\n pass\n\n def g():\n pass\n\n a = 'a'\n B = 'b'\n\nWe can see that this applied the composition of the metaclasses.\n\n.. code:: python\n\n >>> C.f\n \n >>> C.g\n \n >>> C.b\n 'b'\n >>> C.a\n 'a'\n >>> C.methods\n [, ]\n\nThe order that the metaclasses are composed is explicit as they act as\ntransformers over each other.\n\n\n``Template``\n------------\n\nWhile the previous example only showed metaclasses, you can use this for any\nclass; however, it is most useful for metaclasses where having a compatible\nmetaclass hierarchy is important.\n\nA ``Template`` is a callable that takes a ``type`` object and\nreturns a new ``type`` object. It takes the following arguments:\n\n- ``base``: A type object. ``default``: ``type``.\n- ``adjust_name``: Should we prepend the name of the ``base`` to the\n new type object. ``default``: ``True``.\n\nThese can be chained together with any concrete metaclass at the end,\ne.g.:\n\n.. code:: python\n\n new_class = m(n,p(q(...z(type)...)))\n\nYou can also use the compose function to do this:\n\n.. code:: python\n\n from metautils3 import compose\n\n new_class_template = compose(m, n, p, q, ..., z)\n\n\nDifferences with ``metautils``\n------------------------------\n\nmetautils3 uses far more experimental features, including bytecode and code\nobject transformations that allow for more work to be done implicitly. This is\nhow the ``T`` object can refernece the template argument inside of a method, or\nhow we can get ``super`` to work as intended. This package also calls into\n``ctypes`` and other CPython specific code, making it less portable and more\ndifficult to maintain. This is mainly an interesting proof of concept to push\n``metautils`` to the limits. For any production code, I have to recommend you\nuse the more stable version.\n\n\n.. _metautils: https://github.com/quantopian/metautils", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/llllllllll/metautils3", "keywords": null, "license": "Apache 2.0", "maintainer": null, "maintainer_email": null, "name": "metautils3", "package_url": "https://pypi.org/project/metautils3/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/metautils3/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/llllllllll/metautils3" }, "release_url": "https://pypi.org/project/metautils3/0.1.2/", "requires_dist": null, "requires_python": null, "summary": "Experimental utilities for working with metaclasses.", "version": "0.1.2" }, "last_serial": 1601372, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "41305108a46729eead6aa0a8887e9af3", "sha256": "e8110dc3119e0870858ae78042da264f8f2d9caf8dba08d7474b3747c89f00a5" }, "downloads": -1, "filename": "metautils3-0.1.0.tar.gz", "has_sig": false, "md5_digest": "41305108a46729eead6aa0a8887e9af3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6076, "upload_time": "2015-06-07T22:13:38", "url": "https://files.pythonhosted.org/packages/b6/ad/805921895afcd587ca95f6a8e4425f2c93a7e5c7c20a93c6f9e1eb6849cc/metautils3-0.1.0.tar.gz" } ], "0.1.1": [], "0.1.2": [ { "comment_text": "", "digests": { "md5": "e95893a22e1b525e6eeb89172515ae0e", "sha256": "1c2c3d33f1146c7cf763d88b1a7497d0cf5d55f25352a38579d61e2e3ec7c255" }, "downloads": -1, "filename": "metautils3-0.1.2.tar.gz", "has_sig": false, "md5_digest": "e95893a22e1b525e6eeb89172515ae0e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6081, "upload_time": "2015-06-22T01:47:21", "url": "https://files.pythonhosted.org/packages/46/97/26574000f63defafc91775d2f9b8fe2deca65e42bbc078c29dcaff03a384/metautils3-0.1.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "e95893a22e1b525e6eeb89172515ae0e", "sha256": "1c2c3d33f1146c7cf763d88b1a7497d0cf5d55f25352a38579d61e2e3ec7c255" }, "downloads": -1, "filename": "metautils3-0.1.2.tar.gz", "has_sig": false, "md5_digest": "e95893a22e1b525e6eeb89172515ae0e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6081, "upload_time": "2015-06-22T01:47:21", "url": "https://files.pythonhosted.org/packages/46/97/26574000f63defafc91775d2f9b8fe2deca65e42bbc078c29dcaff03a384/metautils3-0.1.2.tar.gz" } ] }