{ "info": { "author": "Alexander Sosedkin", "author_email": "monk@unboiled.info", "bugtrack_url": null, "classifiers": [], "description": "mutants, a Python library for objects that mutate on access\n===========================================================\n\n\nIn short\n--------\n`mutants` allows to create Python objects that mutate on access.\nIt works by creating proxy objects\nthat change underlying objects on every access.\n\n\nDemo\n----\n```python\nimport random\n\nimport mutants\n\n\nn = mutants.OnAccessMutant(0, lambda n: n + 1)\nprint(n) # prints 1\nprint(n) # prints 2\nprint(n) # prints 3\n\n\nclass Duck:\n feathers = True\n\n def quack(self):\n print('quack')\n\n\nclass Wolf:\n teeth = 'sharp'\n\n def quack(self):\n print('no quack')\n\n\ndef random_animal():\n return random.choice([Duck(), Wolf()])\n\nrandy = mutants.ImmutableMutant(random_animal)\nrandy.quack() # prints 'quack' or 'no quack'\nrandy.quack() # prints 'quack' or 'no quack'\nprint(hasattr(randy, 'feathers')) # prints 'True' or 'False'\nrandy.name = 'Randy'\nprint(hasattr(randy, 'name')) # prints 'False', see below\n\n\ndef class_toggler(animal):\n if isinstance(animal, Duck):\n return Wolf\n return Duck\n\ntracy = mutants.ClassHopperMutant(Duck(), class_toggler)\ntracy.quack() # prints 'no quack' as it's a Wolf\ntracy.quack() # prints 'quack' as it's a Duck\nprint(tracy.teeth) # prints 'sharp' as it's a Wolf\ntracy.name = 'Tracy'\nprint(tracy.name) # prints 'Tracy'\n\n\ndef class_extender(animal):\n class SleepyAnimal(animal.__class__):\n def quack(self):\n super().quack()\n print('zzz')\n return SleepyAnimal\n\nzetta = mutants.ClassHopperMutant(Duck(), class_extender)\nzetta.quack() # prints 'quack' and 'zzz'\n```\n\n\nDetails\n-------\nDepending on what you want, you can choose\none of two mutant kinds: ImmutableMutant and ClassyMutant\nor make a custom OnAccessMutant.\n\n### OnAccessMutant\n\n`OnAccessMutant` is the core class of the library.\nIt wraps an object much like `wrapt.ObjectProxy` does.\nBut there's a callback that is called before each access\nand has the ability to modify or replace the proxied object.\n\nUsage: `OnAccessMutant(initial_object, callable_mutator)`\nwhere: `callable_mutator(wrapped_object) -> new_wrapped_object`\n\n### ImmutableMutant\n\n`ImmutableMutant` can impersonate different objects.\nIts constructor takes a callable.\nBefore each access, this callable is called to provide an object\nthat `ImmutableMutant` will impersonate.\n\nUsage: `ImmutableMutant(callable_returning_objects_to_be_proxied)`\n\nModifying `ImmutableMutant` is probably a strange idea,\nbecause it doesn't remember the objects that it impersonates\nand the callable will probably return something else next time.\n\nIn this pure Python implementation it's implemented as:\n```python\ndef ImmutableMutant(mutator):\n return OnAccessMutant(None, lambda _: mutator())\n```\nFuture C extensions may implement it separately for performance benefits.\n\n### ClassHopperMutant\n\n`ClassHopper` reevaluates the class of the wrapped object on every access.\nIt's like `obj.__class__ = callable_returning_a_class()`,\nbut magically happening before every manipulation with the object.\n\nUsage: `mutant.ClassHopper(initial_object, callable_returning_a_class)`\n\nIn this pure Python implementation it's implemented as:\n```python\ndef ClassHopperMutant(initial_object, class_returning_callable, copy=True):\n\n from copy import copy as _copy\n\n def class_mutator(obj):\n obj.__class__ = class_returning_callable(obj)\n return obj\n\n if copy:\n initial_object = _copy(initial_object)\n\n return OnAccessMutant(initial_object, class_mutator)\n```\nFuture C extensions may implement it separately for performance benefits.\n\n\nMore about mutants\n------------------\n`mutants` were born to serve the needs of another library, `hacks`,\nthat aids modifying object, function or class behaviour,\nstacking such modifications\nand switching `currently active modification stacks' easily on the fly.\nCheck it out: https://github.com/t184256/hacks\n\n`mutants` is similar to `wrapt.ObjectProxy` or `lazy-object-proxy`\nbut with bugs and flexibility instead of laziness, caching and performance.\nCPython/Python guys, please give us something cleaner to pull off our tricks!\n\n`mutants` is currently in alpha state,\nso send in pull requests if something is broken!\n\n\nLicense\n-------\n`mutants` is distributed under the terms of the MIT License;\nsee [LICENSE.txt](LICENSE.txt).", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/t184256/mutants", "keywords": "hacks", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "mutants", "package_url": "https://pypi.org/project/mutants/", "platform": null, "project_url": "https://pypi.org/project/mutants/", "project_urls": { "Homepage": "https://github.com/t184256/mutants" }, "release_url": "https://pypi.org/project/mutants/0.0.2/", "requires_dist": null, "requires_python": "", "summary": "mutants, a Python library for objects that mutate on access", "version": "0.0.2" }, "last_serial": 2363721, "releases": { "0.0.0": [], "0.0.1": [ { "comment_text": "", "digests": { "md5": "fd64ae096152b6006b93a9d9675b5b5d", "sha256": "18ea036eda614a4feaeab695d2669a24443cbf751d79493d1bd90a5564d3f16c" }, "downloads": -1, "filename": "mutants-0.0.1.tar.gz", "has_sig": false, "md5_digest": "fd64ae096152b6006b93a9d9675b5b5d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8886, "upload_time": "2016-09-19T10:21:23", "url": "https://files.pythonhosted.org/packages/cd/c8/9e1401f6af82548360c0e105152cb4640cedb92aa55f385564073c65617a/mutants-0.0.1.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "3e0a85a4dac383f2d27ae0cec01dfff0", "sha256": "de02f0134424b7fb79192eb33e5dd3c6f41132e79732ab7a782c353fd47a6f85" }, "downloads": -1, "filename": "mutants-0.0.2.tar.gz", "has_sig": false, "md5_digest": "3e0a85a4dac383f2d27ae0cec01dfff0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10320, "upload_time": "2016-09-26T10:01:17", "url": "https://files.pythonhosted.org/packages/84/b8/d7e37b1acd477bdf91e672705f58bc1465cac5cc2dc2e4efd7a4b44a4d9c/mutants-0.0.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "3e0a85a4dac383f2d27ae0cec01dfff0", "sha256": "de02f0134424b7fb79192eb33e5dd3c6f41132e79732ab7a782c353fd47a6f85" }, "downloads": -1, "filename": "mutants-0.0.2.tar.gz", "has_sig": false, "md5_digest": "3e0a85a4dac383f2d27ae0cec01dfff0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10320, "upload_time": "2016-09-26T10:01:17", "url": "https://files.pythonhosted.org/packages/84/b8/d7e37b1acd477bdf91e672705f58bc1465cac5cc2dc2e4efd7a4b44a4d9c/mutants-0.0.2.tar.gz" } ] }