{"id":16333534,"url":"https://github.com/t184256/mutants","last_synced_at":"2026-01-22T19:49:59.448Z","repository":{"id":57444191,"uuid":"68592612","full_name":"t184256/mutants","owner":"t184256","description":"mutants, a Python library for objects that mutate on access","archived":false,"fork":false,"pushed_at":"2016-09-26T09:58:08.000Z","size":20,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-19T14:49:32.336Z","etag":null,"topics":["library","limitation","mutate","mutate-on-access","object-proxying","proxy","python","python3"],"latest_commit_sha":null,"homepage":null,"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/t184256.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-09-19T09:53:11.000Z","updated_at":"2018-09-08T22:20:50.000Z","dependencies_parsed_at":"2022-09-14T00:52:51.352Z","dependency_job_id":null,"html_url":"https://github.com/t184256/mutants","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/t184256/mutants","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/t184256%2Fmutants","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/t184256%2Fmutants/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/t184256%2Fmutants/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/t184256%2Fmutants/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/t184256","download_url":"https://codeload.github.com/t184256/mutants/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/t184256%2Fmutants/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28669718,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T19:36:09.361Z","status":"ssl_error","status_checked_at":"2026-01-22T19:36:05.567Z","response_time":144,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["library","limitation","mutate","mutate-on-access","object-proxying","proxy","python","python3"],"created_at":"2024-10-10T23:35:52.215Z","updated_at":"2026-01-22T19:49:59.432Z","avatar_url":"https://github.com/t184256.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"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) -\u003e 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).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ft184256%2Fmutants","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ft184256%2Fmutants","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ft184256%2Fmutants/lists"}