{"id":16417537,"url":"https://github.com/xrudelis/pytrait","last_synced_at":"2026-02-23T14:01:04.918Z","repository":{"id":45929926,"uuid":"430301153","full_name":"xrudelis/pytrait","owner":"xrudelis","description":"Traits for Python3","archived":false,"fork":false,"pushed_at":"2021-11-27T06:25:21.000Z","size":24,"stargazers_count":143,"open_issues_count":2,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-11-10T05:24:29.202Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xrudelis.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":"2021-11-21T07:28:10.000Z","updated_at":"2025-10-25T16:37:03.000Z","dependencies_parsed_at":"2022-08-28T19:51:20.110Z","dependency_job_id":null,"html_url":"https://github.com/xrudelis/pytrait","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/xrudelis/pytrait","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xrudelis%2Fpytrait","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xrudelis%2Fpytrait/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xrudelis%2Fpytrait/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xrudelis%2Fpytrait/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xrudelis","download_url":"https://codeload.github.com/xrudelis/pytrait/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xrudelis%2Fpytrait/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29745111,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-23T07:44:07.782Z","status":"ssl_error","status_checked_at":"2026-02-23T07:44:07.432Z","response_time":90,"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":[],"created_at":"2024-10-11T07:11:34.003Z","updated_at":"2026-02-23T14:01:04.816Z","avatar_url":"https://github.com/xrudelis.png","language":"Python","readme":"Find the package here: https://pypi.org/project/pytrait/\n\nPyTrait\n=======\n\nDo you like Python, but think that multiple inheritance is a bit too flexible? Are you\nlooking for a more constrained way to define interfaces and re-use code?\n\nTry using PyTraits!\n\nWe provide three metaclasses that aid writing code for shared behavior separately from\nconcrete types. For the most part, `Trait`s define interfaces, `Struct`s define state,\nand `Impl`s define implementation. `Trait`s must be defined before any `Impl`s which\nimplement them, and `Impl`s must be defined before the `Struct`s that use them.\n\nSee examples under `examples/`.\n\n\nTraits\n------\n\nTraits are abstract base classes (ABCs). There's really not much else to say, except\nthat these ABCs are always implemented in `Impl` classes, which themselves have no\nabstract methods, but are not concrete classes; instead an `Impl` is associated with\nanother type that it bestows implementation upon. This would be either a concrete class\n(always a `Struct`) or all such concrete classes implementing a given `Trait`.\n\n\n```python\nfrom pytrait import Trait, abstractmethod    \n\nclass MyTrait(metaclass=Trait):\n    @abstractmethod\n    def my_method(self) -\u003e str:\n        pass\n```\n\n\nStructs\n-------\n\nPython has _dataclasses_, and they're great. We're using them internally for our\nStructs, so whenever you see `metaclass=Struct`, the class is also a dataclass.\nDon't get confused with the existing Python module `struct` -- that one is lower-case.\n\n```python\nfrom pytrait import Struct\n\nclass MyStruct(metaclass=Struct):\n    my_message: str = \"this is a dataclass\"\n\n    def __post_init__(self):\n        assert my_message == \"this is a dataclass\"\n```\n\nImpls\n-----\n\n`Impl`s bring together `Trait`s and `Struct`s. They represent the implementation details\nthat satisfy one particular interface.\n\nWhy isn't the implementation just all together under the `Struct`? Organization,\nmostly. Also, \"blanket\" `Impl`s can provide implementation for any `Struct` implementing\na given `Trait`, so `Impl`s allow for greater code re-use.\n\n`Impl`s have to indicate which `Struct`s they bestow implementation upon. You can\nfollow a strict naming convention, like `ImplMyTraitForMyStruct`. This is sufficient.\nOr, you can use any name you want so long as you also provide a keyword argument\n`target=\"StructName\"` alongside the `metaclass` argument.\n\n```python\nfrom pytrait import Impl\n\nclass MyImpl(MyTrait, metaclass=Impl, target=\"MyStruct\"):\n    ...\n```\n\nor equivalently,\n\n```python\nfrom pytrait import Impl\n\nclass ImplMyTraitForMyStruct(MyTrait, metaclass=Impl):\n    ...\n```\n\nThis is used to automate the list of implementations for `MyStruct`; you don't need to\nexplicitly list any superclasses of `MyStruct`, just based on the `Impl` name it will\ninherit from all relevant `Impl`s.\n\n\nFAQ\n===\n\n\nThis reminds me of another programming language\n-----------------------------------------------\n\nThat is not a question, but you have indeed figured me out. This way of organizing\nPython code was heavily inspired by the Rust programming language. But beyond being an\nimitation, it's a testament to how powerful Python is. My philosophy is that if\nyou're not using the flexibility of Python to limit yourself, you're not making use of\nthe full flexibility of Python.\n\n\nWhat doesn't work?\n------------------\n\nA Struct can't have traits with overlapping method names. Rust can solve this\nwith its \"fully qualified syntax\", or by type constraints, but Python will\nby default only resolve to the method from the first listed superclass (see\nPython's \"Method Resolution Order\").\n\nI don't think there's any easy way around this, because in Python there's no clear way\nto choose which implementation to use based on type annotation. If you _really_ want to\nlet a `Struct` implement two traits that have the same method name, you can always wrap\nyour class definition in a try block and catch the `MultipleImplementationError`. Maybe\nyou can find a way to make it work.\n","funding_links":[],"categories":["Python"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxrudelis%2Fpytrait","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxrudelis%2Fpytrait","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxrudelis%2Fpytrait/lists"}