{"id":25269757,"url":"https://github.com/garciat/gean","last_synced_at":"2026-05-14T23:31:49.435Z","repository":{"id":57433355,"uuid":"268080661","full_name":"Garciat/gean","owner":"Garciat","description":"A minimal IOC container inspired by Spring.","archived":false,"fork":false,"pushed_at":"2020-06-02T18:07:46.000Z","size":81,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-01T20:25:22.803Z","etag":null,"topics":["ioc-container","python3","spring"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/gean/","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/Garciat.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":"2020-05-30T13:02:21.000Z","updated_at":"2022-09-04T21:50:46.000Z","dependencies_parsed_at":"2022-08-28T04:51:19.994Z","dependency_job_id":null,"html_url":"https://github.com/Garciat/gean","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/Garciat/gean","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Garciat%2Fgean","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Garciat%2Fgean/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Garciat%2Fgean/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Garciat%2Fgean/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Garciat","download_url":"https://codeload.github.com/Garciat/gean/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Garciat%2Fgean/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273377429,"owners_count":25094580,"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-09-03T02:00:09.631Z","response_time":76,"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":["ioc-container","python3","spring"],"created_at":"2025-02-12T11:19:34.347Z","updated_at":"2026-05-14T23:31:49.399Z","avatar_url":"https://github.com/Garciat.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![PyPI version](https://badge.fury.io/py/gean.svg)](https://badge.fury.io/py/gean)\n[![Build Status](https://travis-ci.org/Garciat/gean.svg?branch=master)](https://travis-ci.org/Garciat/gean)\n[![codecov](https://codecov.io/gh/Garciat/gean/branch/master/graph/badge.svg)](https://codecov.io/gh/Garciat/gean)\n\n# gean\n\nA minimal IOC container inspired by Spring.\n\n## Install\n\n```\npython3 -m pip install gean\n```\n\n## Requirements\n\n`gean`, like Spring, relies on types and signatures to build and resolve the dependency graph.\n\nRequired language features:\n  - [PEP 484 - Type Hints](https://www.python.org/dev/peps/pep-0484/) (Python 3.5+)\n  - [PEP 526 - Syntax for Variable Annotations](https://www.python.org/dev/peps/pep-0526/) (Python 3.6+)\n\n## Features\n\n### Type hierarchies\n\nA dependency of a given type `X` is exposed not only as `X` but also all of its super types, including generic interfaces. Variance is supported on generic types.\n\n#### Regular inheritance\n\n```python\nfrom abc import ABC\nfrom gean import Container\n\n# Works with or without ABC\nclass Worker(ABC): pass\nclass WorkerImpl(Worker): pass\n\ncontainer = Container()\ncontainer.register_class(WorkerImpl)\n\n# All of these return the same instance\nc1 = container.resolve(WorkerImpl)\nc2 = container.resolve(Worker)\nassert c1 is c2\nassert isinstance(c1, WorkerImpl)\n```\n\n#### Covariance\n\n```python\nfrom gean import Container\nfrom typing import Generic, TypeVar\n\n_Tco = TypeVar('_Tco', covariant=True)\n\nclass Person: pass\nclass Student(Person): pass\n\nclass Factory(Generic[_Tco]): pass\n\nclass StudentFactory(Factory[Student]): pass\n\ncontainer = Container()\ncontainer.register_class(StudentFactory)\n\n# All of these return the same instance\nc1 = container.resolve(StudentFactory)\nc2 = container.resolve(Factory[Student])\nc3 = container.resolve(Factory[Person])\nassert c1 is c2 is c3\nassert isinstance(c1, StudentFactory)\n```\n\n#### Contravariance\n\n```python\nfrom gean import Container\nfrom typing import Generic, TypeVar\n\n_Tcontra = TypeVar('_Tcontra', contravariant=True)\n\nclass Person: pass\nclass Student(Person): pass\n\nclass Validator(Generic[_Tcontra]): pass\n\nclass PersonValidator(Validator[Person]): pass\n\ncontainer = Container()\ncontainer.register_class(PersonValidator)\n\n# All of these return the same instance\nc1 = container.resolve(PersonValidator)\nc2 = container.resolve(Validator[Student])\nc3 = container.resolve(Validator[Person])\nassert c1 is c2 is c3\nassert isinstance(c1, PersonValidator)\n```\n\n### Caching\n\nAll dependencies are cached as they are constructed.\n\n```python\nfrom gean import Container\n\nclass A: pass\n\ncontainer = Container()\ncontainer.register_class(A)\n\na1 = container.resolve(A)\na2 = container.resolve(A)\nassert a1 is a2\n```\n\n### Autowiring\n\nDependencies can be autowired if a class does not declare an explicit constructor.\n\nField names can disambiguate same-type dependencies.\n\n```python\nfrom gean import Container\n\nclass Subject:\n  def work(self):\n    print('working')\n\nclass Manager:\n  subject: Subject  # will be autowired\n  def run(self):\n    self.subject.work()\n\ncontainer = Container()\n# Order of registration does not matter\ncontainer.register_class(Manager)\ncontainer.register_class(Subject)\n\n# This prints 'working'\ncontainer.resolve(Manager).run()\n```\n\n### Constructor wiring\n\nIf a class defines an explicit constructor, dependencies will be passed as arguments.\n\nParameter names can disambiguate same-type dependencies.\n\n```python\nfrom gean import Container\n\nclass Subject:\n  def work(self):\n    print('working')\n\nclass Manager:\n  def __init__(self, subject: Subject):\n    self.subject = subject\n  def run(self):\n    self.subject.work()\n\ncontainer = Container()\n# Order of registration does not matter\ncontainer.register_class(Manager)\ncontainer.register_class(Subject)\n\n# This prints 'working'\ncontainer.resolve(Manager).run()\n```\n\n### Modules\n\nA **module** is a class whose name ends in `Module`.\n\nA module may use `@includes` to declaratively register other classes or modules.\n\nA module may use public methods to create dependencies programmatically.\n\n```python\nfrom gean import Container, includes\n\nclass PingService:\n  def ping(self, addr): ...\n\nclass DNSService:\n  def resolve(self, name): ...\n\n@includes(\n  DNSService,\n  PingService,\n)\nclass NetworkModule: pass\n\nclass AppConfig: pass\n\nclass Application:\n  config: AppConfig\n  dns_service: DNSService\n  ping_service: PingService\n  def run(self):\n    print(self.config)\n    self.ping_service.ping(self.dns_service.resolve('garciat.com'))\n\ndef load_configuration() -\u003e AppConfig: ...\n\n@includes(\n  NetworkModule,\n  Application,\n)\nclass ApplicationModule:\n  # Create config programmatically\n  def config(self) -\u003e AppConfig:\n    return load_configuration()\n\ncontainer = Container()\n# No other dependencies need to be declared manually\n# Because the modules do so declaratively\ncontainer.register_module(ApplicationModule)\n\ncontainer.resolve(Application).run()\n```\n\n### Singletons\n\nDependencies can be explicitly named so that disambiguation is possible.\n\n```python\nfrom gean import Container\n\ncontainer = Container()\n# Both dependencies are of type `str`\ncontainer.register_instance('/tmp', name='tmp_dir')\ncontainer.register_instance('/home/garciat', name='user_dir')\n\n# Disambiguate with name\ncontainer.resolve(str, name='tmp_dir')\n```\n\n## Alternatives\n\nAs of June 1 2020, this is a non-exhaustive list of alternative solutions that also leverage Type Hints.\n\n### [injector](https://github.com/alecthomas/injector)\n\n  - Does not support hierarchy with generic interfaces\n\n\u003c!-- do not add syntax highlighting, otherwise it will be executed --\u003e\n```\nfrom typing import Generic, TypeVar\n\nfrom injector import Injector, Module, inject, provider, singleton\n\n\n_T = TypeVar('_T')\n\nclass A(Generic[_T]): pass\nclass B(A[int]): pass\n\nclass C:\n  @inject\n  def __init__(self, a: A[int]):\n    self.a = a\n\n\nclass MyModule(Module):\n  @singleton\n  @provider\n  def provide_b(self) -\u003e B:  # works if return type is A[int] explicitly\n    return B()\n\n\ni = Injector([MyModule])\n\n# injector.UnknownProvider: couldn't determine provider for __main__.A[int] to None\ni.get(C)\n```\n\n### [bobthemighty/punq](https://github.com/bobthemighty/punq)\n\n  - Does not support type hierarchies\n\n### [jbasko/auto-init](https://github.com/jbasko/auto-init)\n\n  - Performs default initialization. E.g. `0` for `int`, `None` for objects\n  - Does not support generic interfaces\n\n### [asyncee/wint](https://github.com/asyncee/wint)\n\n  - Global state\n\n## History\n\n`gean` started off as [a gist](https://gist.github.com/Garciat/ad8a3afbb3cef141fcc500ae6ba96bf4) I created to show @alexpizarroj how my team leverages Spring in our projects.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgarciat%2Fgean","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgarciat%2Fgean","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgarciat%2Fgean/lists"}