wireup 0.16.0__tar.gz → 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. wireup-1.0.1/PKG-INFO +272 -0
  2. {wireup-0.16.0 → wireup-1.0.1}/pyproject.toml +6 -7
  3. wireup-1.0.1/readme.md +234 -0
  4. wireup-1.0.1/wireup/__init__.py +25 -0
  5. wireup-1.0.1/wireup/_annotations.py +133 -0
  6. wireup-1.0.1/wireup/_async_to_sync.py +34 -0
  7. wireup-1.0.1/wireup/_decorators.py +95 -0
  8. wireup-1.0.1/wireup/_discovery.py +68 -0
  9. {wireup-0.16.0 → wireup-1.0.1}/wireup/errors.py +12 -19
  10. wireup-1.0.1/wireup/integration/django/__init__.py +3 -0
  11. wireup-1.0.1/wireup/integration/django/apps.py +164 -0
  12. wireup-1.0.1/wireup/integration/fastapi.py +141 -0
  13. wireup-1.0.1/wireup/integration/flask.py +49 -0
  14. wireup-1.0.1/wireup/integration/util.py +7 -0
  15. {wireup-0.16.0 → wireup-1.0.1}/wireup/ioc/_exit_stack.py +13 -11
  16. wireup-1.0.1/wireup/ioc/container/__init__.py +110 -0
  17. wireup-1.0.1/wireup/ioc/container/async_container.py +55 -0
  18. wireup-1.0.1/wireup/ioc/container/base_container.py +281 -0
  19. wireup-1.0.1/wireup/ioc/container/sync_container.py +33 -0
  20. {wireup-0.16.0 → wireup-1.0.1}/wireup/ioc/override_manager.py +2 -2
  21. wireup-1.0.1/wireup/ioc/parameter.py +60 -0
  22. wireup-1.0.1/wireup/ioc/service_registry.py +168 -0
  23. {wireup-0.16.0 → wireup-1.0.1}/wireup/ioc/types.py +25 -19
  24. {wireup-0.16.0 → wireup-1.0.1}/wireup/ioc/util.py +11 -41
  25. wireup-1.0.1/wireup/ioc/validation.py +126 -0
  26. wireup-0.16.0/PKG-INFO +0 -242
  27. wireup-0.16.0/readme.md +0 -204
  28. wireup-0.16.0/wireup/__init__.py +0 -53
  29. wireup-0.16.0/wireup/annotation/__init__.py +0 -189
  30. wireup-0.16.0/wireup/integration/django/__init__.py +0 -46
  31. wireup-0.16.0/wireup/integration/django/apps.py +0 -98
  32. wireup-0.16.0/wireup/integration/fastapi.py +0 -58
  33. wireup-0.16.0/wireup/integration/fastapi_integration.py +0 -45
  34. wireup-0.16.0/wireup/integration/flask.py +0 -28
  35. wireup-0.16.0/wireup/integration/flask_integration.py +0 -49
  36. wireup-0.16.0/wireup/integration/util.py +0 -17
  37. wireup-0.16.0/wireup/ioc/base_container.py +0 -96
  38. wireup-0.16.0/wireup/ioc/dependency_container.py +0 -429
  39. wireup-0.16.0/wireup/ioc/initialization_context.py +0 -75
  40. wireup-0.16.0/wireup/ioc/parameter.py +0 -105
  41. wireup-0.16.0/wireup/ioc/service_registry.py +0 -235
  42. wireup-0.16.0/wireup/util.py +0 -181
  43. {wireup-0.16.0 → wireup-1.0.1}/wireup/integration/__init__.py +0 -0
  44. {wireup-0.16.0 → wireup-1.0.1}/wireup/ioc/__init__.py +0 -0
  45. {wireup-0.16.0 → wireup-1.0.1}/wireup/py.typed +0 -0
wireup-1.0.1/PKG-INFO ADDED
@@ -0,0 +1,272 @@
1
+ Metadata-Version: 2.1
2
+ Name: wireup
3
+ Version: 1.0.1
4
+ Summary: Python Dependency Injection Library
5
+ Home-page: https://github.com/maldoinc/wireup
6
+ License: MIT
7
+ Keywords: flask,django,injector,dependency injection,dependency injection container,dependency injector
8
+ Author: Aldo Mateli
9
+ Author-email: aldo.mateli@gmail.com
10
+ Requires-Python: >=3.8,<4.0
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Environment :: Console
13
+ Classifier: Environment :: Web Environment
14
+ Classifier: Framework :: Django
15
+ Classifier: Framework :: FastAPI
16
+ Classifier: Framework :: Flask
17
+ Classifier: Framework :: aiohttp
18
+ Classifier: Intended Audience :: Developers
19
+ Classifier: License :: OSI Approved :: MIT License
20
+ Classifier: Operating System :: OS Independent
21
+ Classifier: Programming Language :: Python
22
+ Classifier: Programming Language :: Python :: 3
23
+ Classifier: Programming Language :: Python :: 3.8
24
+ Classifier: Programming Language :: Python :: 3.9
25
+ Classifier: Programming Language :: Python :: 3.10
26
+ Classifier: Programming Language :: Python :: 3.11
27
+ Classifier: Programming Language :: Python :: 3.12
28
+ Classifier: Programming Language :: Python :: 3.13
29
+ Classifier: Programming Language :: Python :: 3 :: Only
30
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
31
+ Classifier: Typing :: Typed
32
+ Requires-Dist: typing_extensions (>=4.7,<5.0)
33
+ Project-URL: Changelog, https://github.com/maldoinc/wireup/releases
34
+ Project-URL: Documentation, https://maldoinc.github.io/wireup/
35
+ Project-URL: Repository, https://github.com/maldoinc/wireup
36
+ Description-Content-Type: text/markdown
37
+
38
+ <div align="center">
39
+ <h1>Wireup</h1>
40
+ <p>Performant, concise and type-safe Dependency Injection for Python 3.8+</p>
41
+
42
+ [![GitHub](https://img.shields.io/github/license/maldoinc/wireup)](https://github.com/maldoinc/wireup)
43
+ [![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/maldoinc/wireup/run_all.yml)](https://github.com/maldoinc/wireup)
44
+ [![Coverage](https://img.shields.io/codeclimate/coverage/maldoinc/wireup?label=Coverage)](https://codeclimate.com/github/maldoinc/wireup)
45
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/wireup)](https://pypi.org/project/wireup/)
46
+ [![PyPI - Version](https://img.shields.io/pypi/v/wireup)](https://pypi.org/project/wireup/)
47
+
48
+ <p><a target="_blank" href="https://maldoinc.github.io/wireup">📚 Documentation</a> | <a target="_blank" href="https://github.com/maldoinc/wireup-demo">🎮 Demo Application</a></p>
49
+ </div>
50
+
51
+
52
+ > [!NOTE]
53
+ > Wireup 1.0 has been released, featuring support for scoped lifetimes, a simplified API, enhanced type safety, and improved documentation.
54
+ > Refer to the [Upgrading Guide](https://maldoinc.github.io/wireup/latest/upgrading/) for instructions on upgrading from version 0.x to 1.0.
55
+ ---
56
+
57
+ Dependency Injection (DI) is a design pattern where dependencies are provided externally rather than created within objects. Wireup automates dependency management using Python's type system, with support for async, generators and modern Python features.
58
+
59
+ ## Features
60
+
61
+ ### ✨ Simple & Type-Safe DI
62
+
63
+ Inject services and configuration using a clean and intuitive syntax.
64
+
65
+ ```python
66
+ @service
67
+ class Database:
68
+ pass
69
+
70
+ @service
71
+ class UserService:
72
+ def __init__(self, db: Database) -> None:
73
+ self.db = db
74
+
75
+ container = wireup.create_sync_container(services=[Database, UserService])
76
+ user_service = container.get(UserService) # ✅ Dependencies resolved.
77
+ ```
78
+
79
+ <details>
80
+ <summary>Example With Configuration</summary>
81
+
82
+ ```python
83
+ @service
84
+ class Database:
85
+ def __init__(self, db_url: Annotated[str, Inject(param="db_url")]) -> None:
86
+ self.db_url = db_url
87
+
88
+ container = wireup.create_sync_container(
89
+ services=[Database],
90
+ parameters={"db_url": os.environ["APP_DB_URL"]}
91
+ )
92
+ database = container.get(Database) # ✅ Dependencies resolved.
93
+ ```
94
+
95
+ </details>
96
+
97
+ ### 🎯 Function Injection
98
+
99
+ Inject dependencies directly into functions with a simple decorator.
100
+
101
+ ```python
102
+ @inject_from_container(container)
103
+ def process_users(service: Injected[UserService]):
104
+ # ✅ UserService injected.
105
+ pass
106
+ ```
107
+
108
+ ### 📝 Interfaces & Abstract Classes
109
+
110
+ Define abstract types and have the container automatically inject the implementation.
111
+
112
+ ```python
113
+ @abstract
114
+ class Notifier(abc.ABC):
115
+ pass
116
+
117
+ @service
118
+ class SlackNotifier(Notifier):
119
+ pass
120
+
121
+ notifier = container.get(Notifier)
122
+ # ✅ SlackNotifier instance.
123
+ ```
124
+
125
+
126
+ ### 🔄 Managed Service Lifetimes
127
+
128
+ Declare dependencies as singletons, scoped, or transient to control whether to inject a fresh copy or reuse existing instances.
129
+
130
+
131
+ ```python
132
+ # Singleton: One instance per application. `@service(lifetime="singleton")` is the default.
133
+ @service
134
+ class Database:
135
+ pass
136
+
137
+ # Scoped: One instance per scope/request, shared within that scope/request.
138
+ @service(lifetime="scoped")
139
+ class RequestContext:
140
+ def __init__(self) -> None:
141
+ self.request_id = uuid4()
142
+
143
+ # Transient: When full isolation and clean state is required.
144
+ # Every request to create transient services results in a new instance.
145
+ @service(lifetime="transient")
146
+ class OrderProcessor:
147
+ pass
148
+ ```
149
+
150
+
151
+ ### 🏭 Flexible Creation Patterns
152
+
153
+ Defer instantiation to specialized factories when complex initialization or cleanup is required.
154
+ Full support for async and generators. Wireup handles cleanup at the correct time depending on the service lifetime.
155
+
156
+ **Synchronous**
157
+
158
+ ```python
159
+ class WeatherClient:
160
+ def __init__(self, client: requests.Session) -> None:
161
+ self.client = client
162
+
163
+ @service
164
+ def weather_client_factory() -> Iterator[WeatherClient]:
165
+ with requests.Session() as session:
166
+ yield WeatherClient(client=session)
167
+ ```
168
+
169
+ **Async**
170
+
171
+ ```python
172
+ class WeatherClient:
173
+ def __init__(self, client: aiohttp.ClientSession) -> None:
174
+ self.client = client
175
+
176
+ @service
177
+ async def weather_client_factory() -> AsyncIterator[WeatherClient]:
178
+ async with aiohttp.ClientSession() as session:
179
+ yield WeatherClient(client=session)
180
+ ```
181
+
182
+
183
+ ### 🛡️ Improved Safety
184
+
185
+ Wireup is mypy strict compliant and will not introduce type errors in your code. It will also warn you at the earliest possible stage about configuration errors to avoid surprises.
186
+
187
+ **Container Creation**
188
+
189
+ The container will raise errors at creation time about missing dependencies or other issues.
190
+
191
+ ```python
192
+ @service
193
+ class Foo:
194
+ def __init__(self, unknown: NotManagedByWireup) -> None:
195
+ pass
196
+
197
+ container = wireup.create_sync_container(services=[Foo])
198
+ # ❌ Parameter 'unknown' of 'Foo' depends on an unknown service 'NotManagedByWireup'.
199
+ ```
200
+
201
+ **Function Injection**
202
+
203
+ Injected functions will raise errors at module import time rather than when called.
204
+
205
+ ```python
206
+ @inject_from_container(container)
207
+ def my_function(oops: Injected[NotManagedByWireup]):
208
+ pass
209
+
210
+ # ❌ Parameter 'oops' of 'my_function' depends on an unknown service 'NotManagedByWireup'.
211
+ ```
212
+
213
+ **Integrations**
214
+
215
+ Wireup integrations assert that requested injections in the framework are valid.
216
+
217
+ ```python
218
+ @app.get("/")
219
+ def home(foo: Injected[NotManagedByWireup]):
220
+ pass
221
+
222
+ wireup.integration.flask.setup(container, app)
223
+ # ❌ Parameter 'foo' of 'home' depends on an unknown service 'NotManagedByWireup'.
224
+ ```
225
+
226
+ ### 📍 Framework-Agnostic
227
+
228
+ Wireup provides its own Dependency Injection mechanism and is not tied to specific frameworks. Use it anywhere you like.
229
+
230
+ ### 🔗 Share Services Between Application and CLI
231
+
232
+ Share the service layer between your web application and its accompanying CLI using Wireup.
233
+
234
+ ### 🔌 Native Integration with Django, FastAPI, or Flask
235
+
236
+ Integrate with popular frameworks for a smoother developer experience.
237
+ Integrations manage request scopes, injection in endpoints, and lifecycle of services.
238
+
239
+ ```python
240
+ app = FastAPI()
241
+ container = wireup.create_async_container(services=[UserService, Database])
242
+
243
+ @app.get("/")
244
+ def users_list(user_service: Injected[UserService]):
245
+ pass
246
+
247
+ wireup.integration.fastapi.setup(container, app)
248
+ ```
249
+
250
+ ### 🧪 Simplified Testing
251
+
252
+ Wireup does not patch your services and lets you test them in isolation.
253
+
254
+ If you need to use the container in your tests, you can have it create parts of your services
255
+ or perform dependency substitution.
256
+
257
+ ```python
258
+ with container.override.service(target=Database, new=in_memory_database):
259
+ # The /users endpoint depends on Database.
260
+ # During the lifetime of this context manager, requests to inject `Database`
261
+ # will result in `in_memory_database` being injected instead.
262
+ response = client.get("/users")
263
+ ```
264
+
265
+ ## 📚 Documentation
266
+
267
+ For more information [check out the documentation](https://maldoinc.github.io/wireup)
268
+
269
+ ## 🎮 Demo application
270
+
271
+ A demo flask application is available at [maldoinc/wireup-demo](https://github.com/maldoinc/wireup-demo)
272
+
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "wireup"
3
- version = "0.16.0"
3
+ version = "1.0.1"
4
4
  description = "Python Dependency Injection Library"
5
5
  authors = ["Aldo Mateli <aldo.mateli@gmail.com>"]
6
6
  license = "MIT"
@@ -45,10 +45,10 @@ Changelog = "https://github.com/maldoinc/wireup/releases"
45
45
 
46
46
  [tool.poetry.dependencies]
47
47
  python = "^3.8"
48
- graphlib2 = { version = "^0.4.7", python = ">=3.8,<3.9" }
48
+ typing_extensions = "^4.7"
49
49
 
50
50
  [tool.poetry.group.dev.dependencies]
51
- ruff = "0.8.6"
51
+ ruff = "0.11.0"
52
52
  setuptools = "^68.0.0"
53
53
  mkdocs = "^1.5.2"
54
54
  mkdocs-material = "^9.4.14"
@@ -74,14 +74,12 @@ lint.ignore = [
74
74
  "PT009", # Prefer using assertEqual instead of plain asserts
75
75
  "TD003", # Exclude "missing issue link for todos",
76
76
  "FIX002", # Disable "Line contains to do, consider resolving the issue". It will be done, in due time.
77
- "D100", # Disable undocumented public module. The definitions themselves will be documented
78
- "D101",
79
- "D102",
80
- "D104", # Same as above, disable missing docstring in public package,
77
+ "D",
81
78
  "D203", # Ignore "one blank line before class". Using "no blank lines before class rule".
82
79
  "D213", # Disable "Summary must go into next line"
83
80
  "D107", # Disable required docs for __init. Can be redundant if class also has them.
84
81
  "A003", # Disable "shadows builtin". OverrideManager.set was flagged by this
82
+ "SLF001", # Allow usage of _fields.
85
83
  "FA100", # Don't recommend __future__ annotations.
86
84
  # Disable as they may cause conflicts with ruff formatter
87
85
  "COM812",
@@ -103,6 +101,7 @@ lint.ignore = [
103
101
  "SIM117",
104
102
  "S101",
105
103
  "PLR2004",
104
+ "PLR0913",
106
105
  ]
107
106
 
108
107
 
wireup-1.0.1/readme.md ADDED
@@ -0,0 +1,234 @@
1
+ <div align="center">
2
+ <h1>Wireup</h1>
3
+ <p>Performant, concise and type-safe Dependency Injection for Python 3.8+</p>
4
+
5
+ [![GitHub](https://img.shields.io/github/license/maldoinc/wireup)](https://github.com/maldoinc/wireup)
6
+ [![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/maldoinc/wireup/run_all.yml)](https://github.com/maldoinc/wireup)
7
+ [![Coverage](https://img.shields.io/codeclimate/coverage/maldoinc/wireup?label=Coverage)](https://codeclimate.com/github/maldoinc/wireup)
8
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/wireup)](https://pypi.org/project/wireup/)
9
+ [![PyPI - Version](https://img.shields.io/pypi/v/wireup)](https://pypi.org/project/wireup/)
10
+
11
+ <p><a target="_blank" href="https://maldoinc.github.io/wireup">📚 Documentation</a> | <a target="_blank" href="https://github.com/maldoinc/wireup-demo">🎮 Demo Application</a></p>
12
+ </div>
13
+
14
+
15
+ > [!NOTE]
16
+ > Wireup 1.0 has been released, featuring support for scoped lifetimes, a simplified API, enhanced type safety, and improved documentation.
17
+ > Refer to the [Upgrading Guide](https://maldoinc.github.io/wireup/latest/upgrading/) for instructions on upgrading from version 0.x to 1.0.
18
+ ---
19
+
20
+ Dependency Injection (DI) is a design pattern where dependencies are provided externally rather than created within objects. Wireup automates dependency management using Python's type system, with support for async, generators and modern Python features.
21
+
22
+ ## Features
23
+
24
+ ### ✨ Simple & Type-Safe DI
25
+
26
+ Inject services and configuration using a clean and intuitive syntax.
27
+
28
+ ```python
29
+ @service
30
+ class Database:
31
+ pass
32
+
33
+ @service
34
+ class UserService:
35
+ def __init__(self, db: Database) -> None:
36
+ self.db = db
37
+
38
+ container = wireup.create_sync_container(services=[Database, UserService])
39
+ user_service = container.get(UserService) # ✅ Dependencies resolved.
40
+ ```
41
+
42
+ <details>
43
+ <summary>Example With Configuration</summary>
44
+
45
+ ```python
46
+ @service
47
+ class Database:
48
+ def __init__(self, db_url: Annotated[str, Inject(param="db_url")]) -> None:
49
+ self.db_url = db_url
50
+
51
+ container = wireup.create_sync_container(
52
+ services=[Database],
53
+ parameters={"db_url": os.environ["APP_DB_URL"]}
54
+ )
55
+ database = container.get(Database) # ✅ Dependencies resolved.
56
+ ```
57
+
58
+ </details>
59
+
60
+ ### 🎯 Function Injection
61
+
62
+ Inject dependencies directly into functions with a simple decorator.
63
+
64
+ ```python
65
+ @inject_from_container(container)
66
+ def process_users(service: Injected[UserService]):
67
+ # ✅ UserService injected.
68
+ pass
69
+ ```
70
+
71
+ ### 📝 Interfaces & Abstract Classes
72
+
73
+ Define abstract types and have the container automatically inject the implementation.
74
+
75
+ ```python
76
+ @abstract
77
+ class Notifier(abc.ABC):
78
+ pass
79
+
80
+ @service
81
+ class SlackNotifier(Notifier):
82
+ pass
83
+
84
+ notifier = container.get(Notifier)
85
+ # ✅ SlackNotifier instance.
86
+ ```
87
+
88
+
89
+ ### 🔄 Managed Service Lifetimes
90
+
91
+ Declare dependencies as singletons, scoped, or transient to control whether to inject a fresh copy or reuse existing instances.
92
+
93
+
94
+ ```python
95
+ # Singleton: One instance per application. `@service(lifetime="singleton")` is the default.
96
+ @service
97
+ class Database:
98
+ pass
99
+
100
+ # Scoped: One instance per scope/request, shared within that scope/request.
101
+ @service(lifetime="scoped")
102
+ class RequestContext:
103
+ def __init__(self) -> None:
104
+ self.request_id = uuid4()
105
+
106
+ # Transient: When full isolation and clean state is required.
107
+ # Every request to create transient services results in a new instance.
108
+ @service(lifetime="transient")
109
+ class OrderProcessor:
110
+ pass
111
+ ```
112
+
113
+
114
+ ### 🏭 Flexible Creation Patterns
115
+
116
+ Defer instantiation to specialized factories when complex initialization or cleanup is required.
117
+ Full support for async and generators. Wireup handles cleanup at the correct time depending on the service lifetime.
118
+
119
+ **Synchronous**
120
+
121
+ ```python
122
+ class WeatherClient:
123
+ def __init__(self, client: requests.Session) -> None:
124
+ self.client = client
125
+
126
+ @service
127
+ def weather_client_factory() -> Iterator[WeatherClient]:
128
+ with requests.Session() as session:
129
+ yield WeatherClient(client=session)
130
+ ```
131
+
132
+ **Async**
133
+
134
+ ```python
135
+ class WeatherClient:
136
+ def __init__(self, client: aiohttp.ClientSession) -> None:
137
+ self.client = client
138
+
139
+ @service
140
+ async def weather_client_factory() -> AsyncIterator[WeatherClient]:
141
+ async with aiohttp.ClientSession() as session:
142
+ yield WeatherClient(client=session)
143
+ ```
144
+
145
+
146
+ ### 🛡️ Improved Safety
147
+
148
+ Wireup is mypy strict compliant and will not introduce type errors in your code. It will also warn you at the earliest possible stage about configuration errors to avoid surprises.
149
+
150
+ **Container Creation**
151
+
152
+ The container will raise errors at creation time about missing dependencies or other issues.
153
+
154
+ ```python
155
+ @service
156
+ class Foo:
157
+ def __init__(self, unknown: NotManagedByWireup) -> None:
158
+ pass
159
+
160
+ container = wireup.create_sync_container(services=[Foo])
161
+ # ❌ Parameter 'unknown' of 'Foo' depends on an unknown service 'NotManagedByWireup'.
162
+ ```
163
+
164
+ **Function Injection**
165
+
166
+ Injected functions will raise errors at module import time rather than when called.
167
+
168
+ ```python
169
+ @inject_from_container(container)
170
+ def my_function(oops: Injected[NotManagedByWireup]):
171
+ pass
172
+
173
+ # ❌ Parameter 'oops' of 'my_function' depends on an unknown service 'NotManagedByWireup'.
174
+ ```
175
+
176
+ **Integrations**
177
+
178
+ Wireup integrations assert that requested injections in the framework are valid.
179
+
180
+ ```python
181
+ @app.get("/")
182
+ def home(foo: Injected[NotManagedByWireup]):
183
+ pass
184
+
185
+ wireup.integration.flask.setup(container, app)
186
+ # ❌ Parameter 'foo' of 'home' depends on an unknown service 'NotManagedByWireup'.
187
+ ```
188
+
189
+ ### 📍 Framework-Agnostic
190
+
191
+ Wireup provides its own Dependency Injection mechanism and is not tied to specific frameworks. Use it anywhere you like.
192
+
193
+ ### 🔗 Share Services Between Application and CLI
194
+
195
+ Share the service layer between your web application and its accompanying CLI using Wireup.
196
+
197
+ ### 🔌 Native Integration with Django, FastAPI, or Flask
198
+
199
+ Integrate with popular frameworks for a smoother developer experience.
200
+ Integrations manage request scopes, injection in endpoints, and lifecycle of services.
201
+
202
+ ```python
203
+ app = FastAPI()
204
+ container = wireup.create_async_container(services=[UserService, Database])
205
+
206
+ @app.get("/")
207
+ def users_list(user_service: Injected[UserService]):
208
+ pass
209
+
210
+ wireup.integration.fastapi.setup(container, app)
211
+ ```
212
+
213
+ ### 🧪 Simplified Testing
214
+
215
+ Wireup does not patch your services and lets you test them in isolation.
216
+
217
+ If you need to use the container in your tests, you can have it create parts of your services
218
+ or perform dependency substitution.
219
+
220
+ ```python
221
+ with container.override.service(target=Database, new=in_memory_database):
222
+ # The /users endpoint depends on Database.
223
+ # During the lifetime of this context manager, requests to inject `Database`
224
+ # will result in `in_memory_database` being injected instead.
225
+ response = client.get("/users")
226
+ ```
227
+
228
+ ## 📚 Documentation
229
+
230
+ For more information [check out the documentation](https://maldoinc.github.io/wireup)
231
+
232
+ ## 🎮 Demo application
233
+
234
+ A demo flask application is available at [maldoinc/wireup-demo](https://github.com/maldoinc/wireup-demo)
@@ -0,0 +1,25 @@
1
+ from wireup._annotations import Inject, Injected, abstract, service
2
+ from wireup._decorators import inject_from_container
3
+ from wireup.ioc.container import (
4
+ create_async_container,
5
+ create_sync_container,
6
+ )
7
+ from wireup.ioc.container.async_container import AsyncContainer
8
+ from wireup.ioc.container.sync_container import SyncContainer
9
+ from wireup.ioc.parameter import ParameterBag
10
+ from wireup.ioc.types import ParameterReference, ServiceOverride
11
+
12
+ __all__ = [
13
+ "AsyncContainer",
14
+ "Inject",
15
+ "Injected",
16
+ "ParameterBag",
17
+ "ParameterReference",
18
+ "ServiceOverride",
19
+ "SyncContainer",
20
+ "abstract",
21
+ "create_async_container",
22
+ "create_sync_container",
23
+ "inject_from_container",
24
+ "service",
25
+ ]