pico-fastapi 0.1.0__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 (29) hide show
  1. pico_fastapi-0.1.0/.coveragerc +17 -0
  2. pico_fastapi-0.1.0/.github/workflows/ci.yml +102 -0
  3. pico_fastapi-0.1.0/.github/workflows/publish-to-pypi.yml +36 -0
  4. pico_fastapi-0.1.0/LICENSE +21 -0
  5. pico_fastapi-0.1.0/MANIFEST.in +24 -0
  6. pico_fastapi-0.1.0/PKG-INFO +214 -0
  7. pico_fastapi-0.1.0/README.md +162 -0
  8. pico_fastapi-0.1.0/docs/architecture.md +212 -0
  9. pico_fastapi-0.1.0/pyproject.toml +61 -0
  10. pico_fastapi-0.1.0/setup.cfg +4 -0
  11. pico_fastapi-0.1.0/src/pico_fastapi/__init__.py +21 -0
  12. pico_fastapi-0.1.0/src/pico_fastapi/_version.py +1 -0
  13. pico_fastapi-0.1.0/src/pico_fastapi/config.py +19 -0
  14. pico_fastapi-0.1.0/src/pico_fastapi/decorators.py +28 -0
  15. pico_fastapi-0.1.0/src/pico_fastapi/exceptions.py +11 -0
  16. pico_fastapi-0.1.0/src/pico_fastapi/factory.py +126 -0
  17. pico_fastapi-0.1.0/src/pico_fastapi/middleware.py +31 -0
  18. pico_fastapi-0.1.0/src/pico_fastapi.egg-info/PKG-INFO +214 -0
  19. pico_fastapi-0.1.0/src/pico_fastapi.egg-info/SOURCES.txt +27 -0
  20. pico_fastapi-0.1.0/src/pico_fastapi.egg-info/dependency_links.txt +1 -0
  21. pico_fastapi-0.1.0/src/pico_fastapi.egg-info/requires.txt +8 -0
  22. pico_fastapi-0.1.0/src/pico_fastapi.egg-info/top_level.txt +1 -0
  23. pico_fastapi-0.1.0/tests/__init__.py +0 -0
  24. pico_fastapi-0.1.0/tests/conftest.py +159 -0
  25. pico_fastapi-0.1.0/tests/test_http_admin.py +18 -0
  26. pico_fastapi-0.1.0/tests/test_session_cart.py +19 -0
  27. pico_fastapi-0.1.0/tests/test_settings_applied.py +6 -0
  28. pico_fastapi-0.1.0/tests/test_websocket_chat.py +11 -0
  29. pico_fastapi-0.1.0/tox.ini +33 -0
@@ -0,0 +1,17 @@
1
+ [run]
2
+ branch = True
3
+ source =
4
+ pico_fastapi
5
+ omit =
6
+ */_version.py
7
+
8
+ [paths]
9
+ pico_fastapi =
10
+ src/pico_fastapi
11
+ .tox/*/lib/*/site-packages/pico_fastapi
12
+ .tox/*/site-packages/pico_fastapi
13
+ */site-packages/pico_fastapi
14
+
15
+ [report]
16
+ show_missing = True
17
+
@@ -0,0 +1,102 @@
1
+ name: CI & Coverage
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ tests:
11
+ name: Tests (Python ${{ matrix.python-version }})
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ]
17
+
18
+ steps:
19
+ - name: Checkout
20
+ uses: actions/checkout@v4
21
+ with:
22
+ fetch-depth: 0
23
+
24
+ - name: Set up Python ${{ matrix.python-version }}
25
+ uses: actions/setup-python@v5
26
+ with:
27
+ python-version: ${{ matrix.python-version }}
28
+ cache: pip
29
+
30
+ - name: Install tox
31
+ run: |
32
+ python -m pip install --upgrade pip
33
+ pip install tox
34
+
35
+ - name: Run tests with coverage (writes to repo root)
36
+ shell: bash
37
+ run: |
38
+ set -euxo pipefail
39
+ tox -e cov
40
+ # Rename to per-version file for artifact + merge job
41
+ mv .coverage .coverage.${{ matrix.python-version }}
42
+ ls -la .coverage.${{ matrix.python-version }}
43
+
44
+ - name: Upload .coverage artifact
45
+ uses: actions/upload-artifact@v4
46
+ with:
47
+ name: coverage-${{ matrix.python-version }}
48
+ path: .coverage.${{ matrix.python-version }}
49
+ include-hidden-files: true
50
+ if-no-files-found: error
51
+
52
+ coverage-merge:
53
+ name: Merge coverage
54
+ runs-on: ubuntu-latest
55
+ needs: tests
56
+ steps:
57
+ - name: Checkout (for repo context)
58
+ uses: actions/checkout@v4
59
+
60
+ - name: Download all coverage artifacts
61
+ uses: actions/download-artifact@v4
62
+ with:
63
+ path: coverage-reports
64
+
65
+ - name: Combine coverage and generate reports
66
+ shell: bash
67
+ run: |
68
+ set -euxo pipefail
69
+ python -m pip install coverage
70
+ files=$(find coverage-reports -type f -name ".coverage.*" -print)
71
+ if [ -z "$files" ]; then
72
+ echo "No coverage data files found"; exit 1
73
+ fi
74
+ coverage combine $files
75
+ coverage report -m --rcfile=.coveragerc
76
+ coverage xml -o coverage.xml --rcfile=.coveragerc
77
+ coverage html -d htmlcov --rcfile=.coveragerc
78
+
79
+ - name: Upload combined coverage XML
80
+ uses: actions/upload-artifact@v4
81
+ with:
82
+ name: coverage-xml
83
+ path: coverage.xml
84
+ if-no-files-found: error
85
+
86
+ - name: Upload HTML coverage report
87
+ uses: actions/upload-artifact@v4
88
+ with:
89
+ name: coverage-html
90
+ path: htmlcov
91
+ if-no-files-found: error
92
+
93
+ - name: Upload to Codecov
94
+ if: always() && !cancelled()
95
+ uses: codecov/codecov-action@v5
96
+ continue-on-error: true
97
+ with:
98
+ files: coverage.xml
99
+ fail_ci_if_error: false
100
+ token: ${{ secrets.CODECOV_TOKEN }}
101
+ slug: dperezcabrera/pico-fastapi
102
+
@@ -0,0 +1,36 @@
1
+ name: Publish Python Package to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ deploy:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ id-token: write
12
+ contents: read
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ with:
17
+ fetch-depth: 0
18
+
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: '3.x'
23
+
24
+ - name: Install build deps
25
+ run: python -m pip install --upgrade pip build
26
+
27
+ - name: Build package
28
+ run: python -m build
29
+
30
+ - name: Publish to PyPI
31
+ uses: pypa/gh-action-pypi-publish@release/v1
32
+ with:
33
+ skip-existing: true
34
+ verify-metadata: true
35
+ attestations: false
36
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 David PΓ©rez Cabrera
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,24 @@
1
+ # Incluir ficheros importantes
2
+ include README.md
3
+ include LICENSE
4
+
5
+ # Incluir todo el cΓ³digo fuente
6
+ recursive-include src *.py
7
+
8
+ # Incluir datos de tests si quieres que otros puedan correrlos desde el sdist
9
+ # (opcional β€” puedes quitarlo si no quieres incluir tests en PyPI)
10
+ recursive-include tests *.py
11
+
12
+ # Excluir cosas innecesarias
13
+ exclude .gitignore
14
+ exclude Dockerfile*
15
+ exclude docker-compose*.yml
16
+ exclude Makefile
17
+
18
+ # Excluir carpetas de build, virtualenvs, caches, etc.
19
+ prune build
20
+ prune dist
21
+ prune .tox
22
+ prune .pytest_cache
23
+ prune __pycache__
24
+
@@ -0,0 +1,214 @@
1
+ Metadata-Version: 2.4
2
+ Name: pico-fastapi
3
+ Version: 0.1.0
4
+ Summary: Pico-ioc integration for FastAPI. Adds Spring Boot-style controllers, autoconfiguration, and scopes (request, websocket, session).
5
+ Author-email: David Perez Cabrera <dperezcabrera@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 David PΓ©rez Cabrera
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/dperezcabrera/pico-fastapi
29
+ Project-URL: Repository, https://github.com/dperezcabrera/pico-fastapi
30
+ Project-URL: Issue Tracker, https://github.com/dperezcabrera/pico-fastapi/issues
31
+ Keywords: ioc,di,dependency injection,fastapi,inversion of control,spring boot,controller
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Framework :: FastAPI
34
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3 :: Only
37
+ Classifier: Programming Language :: Python :: 3.10
38
+ Classifier: Programming Language :: Python :: 3.11
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: License :: OSI Approved :: MIT License
41
+ Classifier: Operating System :: OS Independent
42
+ Requires-Python: >=3.10
43
+ Description-Content-Type: text/markdown
44
+ License-File: LICENSE
45
+ Requires-Dist: pico-ioc>=2.0
46
+ Requires-Dist: fastapi>=0.100
47
+ Provides-Extra: session
48
+ Requires-Dist: starlette-session; extra == "session"
49
+ Provides-Extra: run
50
+ Requires-Dist: uvicorn[standard]; extra == "run"
51
+ Dynamic: license-file
52
+
53
+ # πŸ“¦ pico-fastapi
54
+
55
+ [![PyPI](https://img.shields.io/pypi/v/pico-fastapi.svg)](https://pypi.org/project/pico-fastapi/)
56
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/dperezcabrera/pico-fastapi)
57
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
58
+ ![CI (tox matrix)](https://github.com/dperezcabrera/pico-ioc/actions/workflows/ci.yml/badge.svg)
59
+ [![codecov](https://codecov.io/gh/dperezcabrera/pico-fastapi/branch/main/graph/badge.svg)](https://codecov.io/gh/dperezcabrera/pico-fastapi)
60
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-fastapi&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-fastapi)
61
+ [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-fastapi&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-fastapi)
62
+ [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-fastapi&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-fastapi)
63
+
64
+ **pico-fastapi** integrates **Pico-IoC** with **FastAPI**, enabling *constructor-based dependency injection*, scoped lifecycles, and clean architectural boundaries β€” without global state or FastAPI dependency functions.
65
+
66
+ > 🐍 Requires **Python 3.10+**
67
+ > βœ… Fully async-compatible
68
+ > βœ… Real IoC (constructor injection, not function injection)
69
+ > βœ… Works with request, session, and websocket scopes
70
+
71
+ ---
72
+
73
+ ## 🎯 Why pico-fastapi?
74
+
75
+ FastAPI’s built-in dependency system is function-based, which makes business logic tightly coupled to the framework.
76
+
77
+ `pico-fastapi` moves dependency resolution to the **IoC container**.
78
+
79
+ | Concern | FastAPI Default | pico-fastapi |
80
+ |--------|----------------|--------------|
81
+ | Dependency injection | Function-based | Constructor-based |
82
+ | Architecture | Framework-driven | Domain-driven |
83
+ | Testing | Must simulate DI functions | Component overrides at container init |
84
+ | Scopes | Manual or ad-hoc | `singleton`, `request`, `session`, `websocket` |
85
+
86
+ ---
87
+
88
+ ## 🧱 Core Features
89
+
90
+ - `@controller` class-based routing
91
+ - `@get`, `@post`, `@websocket`, etc.
92
+ - Constructor injection for controllers & services
93
+ - Automatic registration into FastAPI
94
+ - Scoped resolution via middleware (`request`, `session`, `websocket`)
95
+ - Full compatibility with Pico-IoC features: overrides, profiles, interceptors, cleanup
96
+
97
+ ---
98
+
99
+ ## πŸ“¦ Installation
100
+
101
+ ```bash
102
+ pip install pico-fastapi
103
+ ````
104
+
105
+ Also requires:
106
+
107
+ ```bash
108
+ pip install pico-ioc fastapi
109
+ ```
110
+
111
+ ---
112
+
113
+ ## πŸš€ Quick Example
114
+
115
+ ```python
116
+ # controllers.py
117
+ from pico_fastapi import controller, get
118
+
119
+ @controller(prefix="/api")
120
+ class ApiController:
121
+ def __init__(self, service: "MyService"):
122
+ self.service = service
123
+
124
+ @get("/hello")
125
+ async def hello(self):
126
+ return {"msg": self.service.greet()}
127
+ ```
128
+
129
+ ```python
130
+ # services.py
131
+ class MyService:
132
+ def greet(self) -> str:
133
+ return "hello from service"
134
+ ```
135
+
136
+ ```python
137
+ # main.py
138
+ from pico_ioc import init
139
+ from fastapi import FastAPI
140
+
141
+ container = init(
142
+ modules=[
143
+ "controllers",
144
+ "services",
145
+ "pico_fastapi.factory",
146
+ ]
147
+ )
148
+
149
+ app = container.get(FastAPI) # βœ… retrieve the fully configured app
150
+ ```
151
+
152
+ ---
153
+
154
+ ## πŸ’¬ WebSocket Example
155
+
156
+ ```python
157
+ from pico_fastapi import controller, websocket
158
+ from fastapi import WebSocket
159
+
160
+ @controller
161
+ class ChatController:
162
+ async def __init__(self):
163
+ pass
164
+
165
+ @websocket("/ws")
166
+ async def chat(self, websocket: WebSocket):
167
+ await websocket.accept()
168
+ while True:
169
+ message = await websocket.receive_text()
170
+ await websocket.send_text(f"Echo: {message}")
171
+ ```
172
+
173
+ ---
174
+
175
+ ## πŸ§ͺ Testing with Overrides
176
+
177
+ ```python
178
+ from pico_ioc import init
179
+ from fastapi import FastAPI
180
+ from fastapi.testclient import TestClient
181
+
182
+ class FakeService:
183
+ def greet(self) -> str:
184
+ return "test"
185
+
186
+ container = init(
187
+ modules=["controllers", "services", "pico_fastapi.factory"],
188
+ overrides={ "MyService": FakeService() }
189
+ )
190
+
191
+ app = container.get(FastAPI)
192
+ client = TestClient(app)
193
+
194
+ assert client.get("/api/hello").json() == {"msg": "test"}
195
+ ```
196
+
197
+ ---
198
+
199
+ ## βš™οΈ How It Works
200
+
201
+ * `@controller` classes are registered automatically
202
+ * HTTP/WebSocket handlers are wrapped in a request or websocket scope
203
+ * All dependencies (services, config, state) are resolved through Pico-IoC
204
+ * Cleanup happens at application shutdown via lifespan integration
205
+
206
+ No global state. No implicit singletons. No magic.
207
+
208
+ ---
209
+
210
+ ## πŸ“ License
211
+
212
+ MIT β€” See `LICENSE`.
213
+
214
+
@@ -0,0 +1,162 @@
1
+ # πŸ“¦ pico-fastapi
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/pico-fastapi.svg)](https://pypi.org/project/pico-fastapi/)
4
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/dperezcabrera/pico-fastapi)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
+ ![CI (tox matrix)](https://github.com/dperezcabrera/pico-ioc/actions/workflows/ci.yml/badge.svg)
7
+ [![codecov](https://codecov.io/gh/dperezcabrera/pico-fastapi/branch/main/graph/badge.svg)](https://codecov.io/gh/dperezcabrera/pico-fastapi)
8
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-fastapi&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-fastapi)
9
+ [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-fastapi&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-fastapi)
10
+ [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-fastapi&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-fastapi)
11
+
12
+ **pico-fastapi** integrates **Pico-IoC** with **FastAPI**, enabling *constructor-based dependency injection*, scoped lifecycles, and clean architectural boundaries β€” without global state or FastAPI dependency functions.
13
+
14
+ > 🐍 Requires **Python 3.10+**
15
+ > βœ… Fully async-compatible
16
+ > βœ… Real IoC (constructor injection, not function injection)
17
+ > βœ… Works with request, session, and websocket scopes
18
+
19
+ ---
20
+
21
+ ## 🎯 Why pico-fastapi?
22
+
23
+ FastAPI’s built-in dependency system is function-based, which makes business logic tightly coupled to the framework.
24
+
25
+ `pico-fastapi` moves dependency resolution to the **IoC container**.
26
+
27
+ | Concern | FastAPI Default | pico-fastapi |
28
+ |--------|----------------|--------------|
29
+ | Dependency injection | Function-based | Constructor-based |
30
+ | Architecture | Framework-driven | Domain-driven |
31
+ | Testing | Must simulate DI functions | Component overrides at container init |
32
+ | Scopes | Manual or ad-hoc | `singleton`, `request`, `session`, `websocket` |
33
+
34
+ ---
35
+
36
+ ## 🧱 Core Features
37
+
38
+ - `@controller` class-based routing
39
+ - `@get`, `@post`, `@websocket`, etc.
40
+ - Constructor injection for controllers & services
41
+ - Automatic registration into FastAPI
42
+ - Scoped resolution via middleware (`request`, `session`, `websocket`)
43
+ - Full compatibility with Pico-IoC features: overrides, profiles, interceptors, cleanup
44
+
45
+ ---
46
+
47
+ ## πŸ“¦ Installation
48
+
49
+ ```bash
50
+ pip install pico-fastapi
51
+ ````
52
+
53
+ Also requires:
54
+
55
+ ```bash
56
+ pip install pico-ioc fastapi
57
+ ```
58
+
59
+ ---
60
+
61
+ ## πŸš€ Quick Example
62
+
63
+ ```python
64
+ # controllers.py
65
+ from pico_fastapi import controller, get
66
+
67
+ @controller(prefix="/api")
68
+ class ApiController:
69
+ def __init__(self, service: "MyService"):
70
+ self.service = service
71
+
72
+ @get("/hello")
73
+ async def hello(self):
74
+ return {"msg": self.service.greet()}
75
+ ```
76
+
77
+ ```python
78
+ # services.py
79
+ class MyService:
80
+ def greet(self) -> str:
81
+ return "hello from service"
82
+ ```
83
+
84
+ ```python
85
+ # main.py
86
+ from pico_ioc import init
87
+ from fastapi import FastAPI
88
+
89
+ container = init(
90
+ modules=[
91
+ "controllers",
92
+ "services",
93
+ "pico_fastapi.factory",
94
+ ]
95
+ )
96
+
97
+ app = container.get(FastAPI) # βœ… retrieve the fully configured app
98
+ ```
99
+
100
+ ---
101
+
102
+ ## πŸ’¬ WebSocket Example
103
+
104
+ ```python
105
+ from pico_fastapi import controller, websocket
106
+ from fastapi import WebSocket
107
+
108
+ @controller
109
+ class ChatController:
110
+ async def __init__(self):
111
+ pass
112
+
113
+ @websocket("/ws")
114
+ async def chat(self, websocket: WebSocket):
115
+ await websocket.accept()
116
+ while True:
117
+ message = await websocket.receive_text()
118
+ await websocket.send_text(f"Echo: {message}")
119
+ ```
120
+
121
+ ---
122
+
123
+ ## πŸ§ͺ Testing with Overrides
124
+
125
+ ```python
126
+ from pico_ioc import init
127
+ from fastapi import FastAPI
128
+ from fastapi.testclient import TestClient
129
+
130
+ class FakeService:
131
+ def greet(self) -> str:
132
+ return "test"
133
+
134
+ container = init(
135
+ modules=["controllers", "services", "pico_fastapi.factory"],
136
+ overrides={ "MyService": FakeService() }
137
+ )
138
+
139
+ app = container.get(FastAPI)
140
+ client = TestClient(app)
141
+
142
+ assert client.get("/api/hello").json() == {"msg": "test"}
143
+ ```
144
+
145
+ ---
146
+
147
+ ## βš™οΈ How It Works
148
+
149
+ * `@controller` classes are registered automatically
150
+ * HTTP/WebSocket handlers are wrapped in a request or websocket scope
151
+ * All dependencies (services, config, state) are resolved through Pico-IoC
152
+ * Cleanup happens at application shutdown via lifespan integration
153
+
154
+ No global state. No implicit singletons. No magic.
155
+
156
+ ---
157
+
158
+ ## πŸ“ License
159
+
160
+ MIT β€” See `LICENSE`.
161
+
162
+