{"id":15474125,"url":"https://github.com/treyhunner/undataclass","last_synced_at":"2025-07-26T17:13:55.888Z","repository":{"id":38076672,"uuid":"501141164","full_name":"treyhunner/undataclass","owner":"treyhunner","description":"Turn dataclasses into not-dataclasses","archived":false,"fork":false,"pushed_at":"2022-06-18T15:44:02.000Z","size":28,"stargazers_count":22,"open_issues_count":2,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-07-26T13:53:57.887Z","etag":null,"topics":["dataclass","dataclasses","learning","python"],"latest_commit_sha":null,"homepage":"https://pym.dev/undataclass","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/treyhunner.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-06-08T07:17:16.000Z","updated_at":"2024-05-30T18:48:26.000Z","dependencies_parsed_at":"2022-09-01T11:30:44.033Z","dependency_job_id":null,"html_url":"https://github.com/treyhunner/undataclass","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/treyhunner/undataclass","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treyhunner%2Fundataclass","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treyhunner%2Fundataclass/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treyhunner%2Fundataclass/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treyhunner%2Fundataclass/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/treyhunner","download_url":"https://codeload.github.com/treyhunner/undataclass/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treyhunner%2Fundataclass/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267198711,"owners_count":24051559,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-26T02:00:08.937Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["dataclass","dataclasses","learning","python"],"created_at":"2024-10-02T03:01:28.946Z","updated_at":"2025-07-26T17:13:55.810Z","avatar_url":"https://github.com/treyhunner.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# undataclass\n\nTurn dataclasses into not-dataclasses\n\nYou can [convert a dataclass to a regular class in Python][app] right from your web browser.\n\n\n## Usage\n\nGiven a `my_module.py` file containing one or more dataclasses:\n\n```python\nfrom dataclasses import dataclass, field\nfrom decimal import Decimal\n\n\n@dataclass(frozen=True, slots=True)\nclass Item:\n    name: str\n    price: Decimal = Decimal(0)\n    colors: str = field(default_factory=list)\n```\n\nYou can run the `undataclass.py` script against your `my_module.py` file to output a new equivalent module with dataclasses replaced by non-dataclasses:\n\n```bash\n$ python3 undataclass.py my_module.py\nfrom decimal import Decimal\n\nclass Item:\n    __slots__ = ('name', 'price', 'colors')\n    __match_args__ = ('name', 'price', 'colors')\n\n    def __init__(self, name: str, price: Decimal=Decimal(0), colors: str=None) -\u003e None:\n        if colors is None:\n            colors = list()\n        object.__setattr__(self, 'name', name)\n        object.__setattr__(self, 'price', price)\n        object.__setattr__(self, 'colors', colors)\n\n    def __repr__(self):\n        cls = type(self).__name__\n        return f'{cls}(name={self.name!r}, price={self.price!r}, colors={self.colors!r})'\n\n    def __eq__(self, other):\n        if not isinstance(other, Item):\n            return NotImplemented\n        return (self.name, self.price, self.colors) == (other.name, other.price, other.colors)\n\n    def __hash__(self):\n        return hash((self.name, self.price, self.colors))\n\n    def __setattr__(self, name, value):\n        raise AttributeError(f\"Can't set attribute {name!r}\")\n\n    def __delattr__(self, name):\n        raise AttributeError(f\"Can't delete attribute {name!r}\")\n\n    def __getstate__(self):\n        return (self.name, self.price, self.colors)\n\n    def __setstate__(self, state):\n        fields = ('name', 'price', 'colors')\n        for (field, value) in zip(fields, state):\n            object.__setattr__(self, field, value)\n```\n\nNote that the generated code isn't PEP8 compliant, but it is fairly readable.\nYou can either fix up the formatting yourself or run an auto-formatter (like [Black][]) against your code.\n\n\n## Features \u0026 Known Limitations\n\nWhat (usually) works:\n\n- Pretty much all the arguments you can pass to the `dataclasses.dataclass` decorator\n- Type annotations, default values, `InitVar`, and `ClassVar`\n- Pretty much all the arguments you can pass to the `fields` helper\n\nWhat doesn't work:\n\n- Usages of fancy helpers like `dataclasses.fields`, `dataclasses.astuple`, the field `metadata` argument will result in broken output code that you'll need to fix up yourself\n- Using `as` imports (e.g. `import dataclasses as dc` doesn't work)\n- Lots of assumptions are made that you're using the `dataclasses` module in a pretty \"standard\" way\n\n\n## Testing\n\nYou can find examples of \"before\" and \"after\" code in the `test_files` directory.\n\nFeel free to run the validate these examples yourself to confirm that the `undataclass` script actually generates the expected results:\n\n```bash\n$ python test.py\ntest_from_import_no_args_no_fields_or_defaults (__main__.TestUndataclass)\nTests no-args dataclass, docstring, and no defaults. ... ok\ntest_inheritance_and_more_default_factories (__main__.TestUndataclass)\nTests dataclass inheritance and lambda factories. ... ok\ntest_kw_only_initvar_and_match_args (__main__.TestUndataclass)\nTests KW_ONLY pseudo-field, InitVar, and match_args. ... ok\ntest_post_init (__main__.TestUndataclass)\nTests dataclasses.dataclass, __post_init__ \u0026 manual __slots__. ... ok\ntest_slots_and_frozen_args_with_default_and_factory (__main__.TestUndataclass)\nTests slots, frozen, order, default value, \u0026 default_factory. ... ok\ntest_with_functions_and_regular_class (__main__.TestUndataclass)\nTests non-dataclass and also regular methods. ... ok\n\n----------------------------------------------------------------------\nRan 6 tests in 0.008s\n\nOK\n```\n\n\n[black]: https://black.readthedocs.io\n[app]: https://www.pythonmorsels.com/undataclass/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftreyhunner%2Fundataclass","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftreyhunner%2Fundataclass","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftreyhunner%2Fundataclass/lists"}