{"id":13458926,"url":"https://github.com/illuin-tech/opyoid","last_synced_at":"2025-04-04T20:14:24.927Z","repository":{"id":37823481,"uuid":"290037184","full_name":"illuin-tech/opyoid","owner":"illuin-tech","description":"Dependency injection library for Python","archived":false,"fork":false,"pushed_at":"2025-03-24T09:00:31.000Z","size":497,"stargazers_count":69,"open_issues_count":0,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-28T19:07:53.298Z","etag":null,"topics":["dependency-injection","injection","python"],"latest_commit_sha":null,"homepage":"","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/illuin-tech.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-24T20:51:50.000Z","updated_at":"2025-03-24T09:00:34.000Z","dependencies_parsed_at":"2023-01-21T13:19:51.805Z","dependency_job_id":"e757b7c6-3fe0-4e0c-81cb-dcf60107dbc2","html_url":"https://github.com/illuin-tech/opyoid","commit_stats":{"total_commits":62,"total_committers":3,"mean_commits":"20.666666666666668","dds":"0.11290322580645162","last_synced_commit":"e554854186e8945e5a9cf5b02a4ae89401534140"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/illuin-tech%2Fopyoid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/illuin-tech%2Fopyoid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/illuin-tech%2Fopyoid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/illuin-tech%2Fopyoid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/illuin-tech","download_url":"https://codeload.github.com/illuin-tech/opyoid/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247242680,"owners_count":20907134,"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","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":["dependency-injection","injection","python"],"created_at":"2024-07-31T09:00:59.841Z","updated_at":"2025-04-04T20:14:24.909Z","avatar_url":"https://github.com/illuin-tech.png","language":"Python","funding_links":[],"categories":["Software"],"sub_categories":["DI Frameworks / Containers"],"readme":"Opyoid\n======\n\n![CI](https://github.com/illuin-tech/opyoid/workflows/CI/badge.svg)\n[![codecov](https://codecov.io/gh/illuin-tech/opyoid/branch/master/graph/badge.svg)](https://codecov.io/gh/illuin-tech/opyoid)\n\nDependency injection library using typings, to easily manage large applications.\n\nThis project is inspired from [Guice](https://github.com/google/guice).\n\n# Installation\n\nRun `pip install opyoid` to install from PyPI.\n\nRun `pip install .` to install from sources.\n\nThis project follows the [Semantic Versioning Specification](https://semver.org/).\nAll breaking changes are described in the [Changelog](CHANGELOG.md).\n\n\n# Usage\n### Simple Injection\n```python\nfrom opyoid import Module, Injector\n\n\nclass MyClass:\n    pass\n\n\nclass MyParentClass:\n    def __init__(self, my_param: MyClass):\n        self.my_param = my_param\n\n\nclass MyModule(Module):\n    def configure(self) -\u003e None:\n        self.bind(MyClass)\n        self.bind(MyParentClass)\n\n\ninjector = Injector([MyModule])\nmy_instance = injector.inject(MyParentClass)\nassert isinstance(my_instance, MyParentClass)\nassert isinstance(my_instance.my_param, MyClass)\n```\nIf they are multiple bindings for the same class, the latest will be used.\n\n\n### Module\nThe module is used to group bindings related to a feature.\nYou can include a module in another with `install`:\n```python\nfrom opyoid import Module, Injector\n\n\nclass MyClass:\n    pass\n\n\nclass MyModule(Module):\n    def configure(self) -\u003e None:\n        self.bind(MyClass)\n\n\nclass MyParentClass:\n    def __init__(self, my_param: MyClass):\n        self.my_param = my_param\n\n\nclass MyParentModule(Module):\n    def configure(self) -\u003e None:\n        self.install(MyModule)\n        self.bind(MyParentClass)\n\n\ninjector = Injector([MyParentModule])\nmy_instance = injector.inject(MyParentClass)\nassert isinstance(my_instance, MyParentClass)\nassert isinstance(my_instance.my_param, MyClass)\n```\n\n\n### Binding Subclasses\n```python\nfrom opyoid import Module, Injector\n\n\nclass MyClass:\n    pass\n\n\nclass MySubClass(MyClass):\n    pass\n\n\nclass MyModule(Module):\n    def configure(self) -\u003e None:\n        self.bind(MyClass, to_class=MySubClass)\n\ninjector = Injector([MyModule])\nmy_instance = injector.inject(MyClass)\nassert isinstance(my_instance, MySubClass)\n```\n\n\n### Binding Instances\n```python\nfrom opyoid import Module, Injector\n\n\nclass MyClass:\n    def __init__(self, my_param: str):\n        self.my_param = my_param\n\nmy_instance = MyClass(\"hello\")\n\n\nclass MyModule(Module):\n    def configure(self) -\u003e None:\n        self.bind(MyClass, to_instance=my_instance)\n\n\ninjector = Injector([MyModule])\ninjected_instance = injector.inject(MyClass)\nassert my_instance is injected_instance\n```\n\n\n### Environment Variables\n\nYou can use environment variables to easily override bindings in your application.\n\n#### Supported types\n\nSupported types are `str`, `int`, `float`, and `bool`.\n\nEnvironment variables are only used when loading ClassBindings, ProviderBindings or SelfBindings, not InstanceBindings\n\nIf the corresponding environment variable exists, it will override the existing default value and bindings for the\nparameter.\n\n#### Environment variable name\n\nThe environment variable should be named `UPPER_CLASS_NAME_UPPER_PARAMETER_NAME`\nIn this example, the environment variable to set is `MY_CLASS_MY_PARAMETER`:\n```python\n@dataclass\nclass MyClass:\n    my_parameter: int\n```\n\n#### Value conversion\n\nFor types other than str, an automatic conversion is made:\n- ints and floats are converted using int() and float()\n- for booleans, authorized values are:\n  - \"0\", \"false\" and \"False\", will be converted to `False`\n  - \"1\", \"true\" and \"True\", will be converted to `True`\n\n\n### Binding scopes\nWhen binding a class, you can choose the scope in which it will be instantiated.\nThis will only have an effect when binding classes, not instances.\n\n\n#### Singleton Scope\nBy default, all classes are instantiated in a Singleton scope.\nThis means that only one instance of each class will be created, and it will be shared between all classes requiring it.\n\n```python\nfrom opyoid import Module, Injector, SingletonScope\n\n\nclass MyClass:\n    pass\n\n\nclass MyParentClass:\n    def __init__(self, my_param: MyClass):\n        self.my_param = my_param\n\n\nclass MyModule(Module):\n    def configure(self) -\u003e None:\n        self.bind(MyClass, scope=SingletonScope)\n        self.bind(MyParentClass, scope=SingletonScope)\n\ninjector = Injector([MyModule])\ninstance_1 = injector.inject(MyClass)\ninstance_2 = injector.inject(MyClass)\nparent_instance = injector.inject(MyParentClass)\nassert instance_1 is instance_2\nassert instance_1 is parent_instance.my_param\n```\n\n\n#### PerLookup Scope\nIf you use the per lookup scope, a new instance will be created every time each class is injected.\n```python\nfrom opyoid import Module, Injector, PerLookupScope\n\n\nclass MyClass:\n    pass\n\n\nclass MyParentClass:\n    def __init__(self, my_param: MyClass):\n        self.my_param = my_param\n\n\nclass MyModule(Module):\n    def configure(self) -\u003e None:\n        self.bind(MyClass, scope=PerLookupScope)\n        self.bind(MyParentClass)\n\ninjector = Injector([MyModule])\ninstance_1 = injector.inject(MyClass)\ninstance_2 = injector.inject(MyClass)\nparent_instance = injector.inject(MyParentClass)\nassert instance_1 is not instance_2\nassert instance_1 is not parent_instance.my_param\n```\n\n\n#### Thread Scope\nThis scope only creates a new instance the first time that the class is injected in the current thread.\nThere will only be one instance of each class in each thread, and two instances injected from different threads will be\ndifferent objects.\n\n```python\nfrom threading import Thread\n\nfrom opyoid import Module, Injector, ThreadScope\n\n\nclass MyClass:\n    pass\n\n\nclass MyModule(Module):\n    def configure(self) -\u003e None:\n        self.bind(MyClass, scope=ThreadScope)\n\ninjector = Injector([MyModule])\ninstance_1 = injector.inject(MyClass)\ninstance_2 = injector.inject(MyClass)\n\ndef thread_target():\n    instance_3 = injector.inject(MyClass)\n    assert instance_1 is not instance_3\n\nThread(target=thread_target).start()\n\nassert instance_1 is instance_2\n```\n\n\n### Bindings without Module\nIf you prefer, you can add bindings to your injector without creating a Module class (or using both).\n\n```python\nfrom opyoid import Module, Injector, SelfBinding\n\n\nclass MyClass:\n    pass\n\n\nclass MyParentClass:\n    def __init__(self, my_param: MyClass):\n        self.my_param = my_param\n\n\nclass MyModule(Module):\n    def configure(self) -\u003e None:\n        self.bind(MyClass)\n\n\ninjector = Injector([MyModule], [SelfBinding(MyParentClass)])\nmy_instance = injector.inject(MyParentClass)\nassert isinstance(my_instance, MyParentClass)\nassert isinstance(my_instance.my_param, MyClass)\n```\n\nThe same options of Module.bind are available when using bindings:\n```python\nfrom opyoid import ClassBinding, InstanceBinding, PerLookupScope, SelfBinding\n\n\nclass MyClass:\n    pass\n\n\nclass MySubClass(MyClass):\n    pass\n\nmy_instance = MyClass()\n\nSelfBinding(MyClass)  # binding a class to itself\nClassBinding(MyClass, MySubClass)  # binding a class to a subclass\nSelfBinding(MyClass, scope=PerLookupScope)  # specifying scope\nInstanceBinding(MyClass, my_instance)  # binding an instance\nSelfBinding(MyClass, named=\"my_name\")  # binding a class to itself with a specific name\nInstanceBinding(MyClass, my_instance, named=\"my_name\")  # binding an instance with a specific name\n```\n\n### Injecting Type\nIf no explicit binding is defined, the last class binding will be used to inject a type:\n\n```python\nfrom typing import Type\n\nfrom opyoid import Module, Injector\n\nclass MyClass:\n    pass\n\nclass SubClass(MyClass):\n    pass\n\nclass MyParentClass:\n    def __init__(self, my_param: Type[MyClass]):\n        self.my_param = my_param\n\nmy_instance = MyClass()\n\nclass MyModule(Module):\n    def configure(self) -\u003e None:\n        self.bind(MyClass)\n        self.bind(MyClass, to_instance=my_instance)\n        self.bind(MyClass, to_class=SubClass)\n        self.bind(MyParentClass)\n\n\ninjector = Injector([MyModule])\nparent_instance = injector.inject(MyParentClass)\nassert isinstance(parent_instance, MyParentClass)\nassert parent_instance.my_param is SubClass\n```\n\n\n## Dataclasses\n`opyoid` can inject classes and parameters defined with the `attrs` library and python data classes.\n\n\n##  Notes about Generics\n- The supported generic types are `List`, `Set`, `Tuple`, `Optional`, `Union` and `Type` (and any combination of them).\nOther generics must be bound explicitly (e.g. you must bind a dict to `Dict[str, MyClass]` if you want to inject it).\n- Be careful when using generics, the bindings will only be used if the type matches exactly. For example, you cannot\nimplicitly bind `MyClass[T]` to inject `MyClass`, or `MyClass[str]` to inject `MyClass[T]`. You need to bind something\nto `MyClass[str]` to be able to inject it.\n\n# Advanced usage\nMore advanced features and examples are available in the [./docs](docs) folder.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filluin-tech%2Fopyoid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Filluin-tech%2Fopyoid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filluin-tech%2Fopyoid/lists"}