appctx 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.
- appctx-0.1.0/PKG-INFO +421 -0
- appctx-0.1.0/README.md +393 -0
- appctx-0.1.0/pyproject.toml +98 -0
- appctx-0.1.0/setup.cfg +4 -0
- appctx-0.1.0/src/appctx/__init__.py +32 -0
- appctx-0.1.0/src/appctx/container.py +103 -0
- appctx-0.1.0/src/appctx/decorators.py +33 -0
- appctx-0.1.0/src/appctx/py.typed +0 -0
- appctx-0.1.0/src/appctx.egg-info/PKG-INFO +421 -0
- appctx-0.1.0/src/appctx.egg-info/SOURCES.txt +13 -0
- appctx-0.1.0/src/appctx.egg-info/dependency_links.txt +1 -0
- appctx-0.1.0/src/appctx.egg-info/requires.txt +8 -0
- appctx-0.1.0/src/appctx.egg-info/top_level.txt +1 -0
- appctx-0.1.0/tests/test_container.py +134 -0
- appctx-0.1.0/tests/test_decorators.py +58 -0
appctx-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: appctx
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Spring style dependency injection for python
|
|
5
|
+
Author-email: wssccc <wssccc@qq.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/wssccc/appctx
|
|
8
|
+
Project-URL: Repository, https://github.com/wssccc/appctx
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/wssccc/appctx/issues
|
|
10
|
+
Project-URL: Documentation, https://github.com/wssccc/appctx#readme
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
24
|
+
Requires-Dist: black>=22.0; extra == "dev"
|
|
25
|
+
Requires-Dist: flake8>=5.0; extra == "dev"
|
|
26
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
27
|
+
Requires-Dist: isort>=5.0; extra == "dev"
|
|
28
|
+
|
|
29
|
+
# AppCtx
|
|
30
|
+
|
|
31
|
+
Spring-style dependency injection for Python
|
|
32
|
+
|
|
33
|
+
[](https://python.org)
|
|
34
|
+
[](https://github.com/wssccc/appctx/blob/main/LICENSE)
|
|
35
|
+
[](https://pypi.org/project/appctx/)
|
|
36
|
+
|
|
37
|
+
## Overview
|
|
38
|
+
|
|
39
|
+
AppCtx is a lightweight dependency injection container inspired by the Spring Framework, providing a clean and elegant dependency management solution for Python applications. It makes it easy to manage dependencies and create maintainable, testable code.
|
|
40
|
+
|
|
41
|
+
**Version**: 0.1.0
|
|
42
|
+
**Python Requirements**: 3.8+
|
|
43
|
+
**License**: MIT
|
|
44
|
+
|
|
45
|
+
### Features
|
|
46
|
+
|
|
47
|
+
- 🚀 **Easy to Use** - Register and inject dependencies with simple decorators
|
|
48
|
+
- 🔄 **Auto-wiring** - Automatic dependency resolution based on type annotations
|
|
49
|
+
- 🏗️ **Flexible Configuration** - Support for both function and class bean definitions
|
|
50
|
+
- 📦 **Lightweight** - Minimal dependencies, focused on core functionality
|
|
51
|
+
- 🐍 **Pythonic** - API design that follows Python conventions
|
|
52
|
+
- 🔧 **Python 3.8+** - Compatible with Python 3.8, 3.9, 3.10, and 3.11
|
|
53
|
+
- 🎯 **Decorator-based bean registration** - Simple `@bean` decorator for registration
|
|
54
|
+
- 🔍 **Circular dependency detection** - Detects and reports circular dependencies
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install appctx
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Development Installation
|
|
63
|
+
|
|
64
|
+
For development, clone the repository and install with development dependencies:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/wssccc/appctx.git
|
|
68
|
+
cd appctx
|
|
69
|
+
pip install -e .[dev]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This will install the following development tools:
|
|
73
|
+
- `pytest>=7.0` - Testing framework
|
|
74
|
+
- `pytest-cov>=4.0` - Coverage reporting
|
|
75
|
+
- `black>=22.0` - Code formatting
|
|
76
|
+
- `flake8>=5.0` - Linting
|
|
77
|
+
- `mypy>=1.0` - Type checking
|
|
78
|
+
- `isort>=5.0` - Import sorting
|
|
79
|
+
|
|
80
|
+
## Basic Concepts
|
|
81
|
+
|
|
82
|
+
AppCtx provides a simple way to manage dependencies in your Python applications:
|
|
83
|
+
|
|
84
|
+
- **Beans**: Objects managed by the container
|
|
85
|
+
- **Container**: The `ApplicationContext` that manages beans
|
|
86
|
+
- **Dependency Injection**: Automatic wiring of dependencies based on type annotations
|
|
87
|
+
|
|
88
|
+
## Quick Start
|
|
89
|
+
|
|
90
|
+
### Basic Usage
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from appctx import bean, get_bean, refresh
|
|
94
|
+
|
|
95
|
+
# Define service classes
|
|
96
|
+
class DatabaseService:
|
|
97
|
+
def __init__(self, connection_string: str = "sqlite:///default.db"):
|
|
98
|
+
self.connection_string = connection_string
|
|
99
|
+
|
|
100
|
+
def connect(self):
|
|
101
|
+
return f"Connected to {self.connection_string}"
|
|
102
|
+
|
|
103
|
+
class UserService:
|
|
104
|
+
def __init__(self, db: DatabaseService):
|
|
105
|
+
self.db = db
|
|
106
|
+
|
|
107
|
+
def get_user(self, user_id: int):
|
|
108
|
+
connection = self.db.connect()
|
|
109
|
+
return f"User {user_id} from {connection}"
|
|
110
|
+
|
|
111
|
+
# Register beans using decorators
|
|
112
|
+
@bean
|
|
113
|
+
def database_service():
|
|
114
|
+
return DatabaseService("postgresql://localhost/myapp")
|
|
115
|
+
|
|
116
|
+
@bean
|
|
117
|
+
def user_service(db: DatabaseService): # Auto-inject DatabaseService
|
|
118
|
+
return UserService(db)
|
|
119
|
+
|
|
120
|
+
# Initialize the container
|
|
121
|
+
refresh()
|
|
122
|
+
|
|
123
|
+
# Get and use beans
|
|
124
|
+
user_svc = get_bean(UserService)
|
|
125
|
+
print(user_svc.get_user(123))
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Class Decorator Usage
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from appctx import bean, get_bean, refresh
|
|
132
|
+
|
|
133
|
+
@bean
|
|
134
|
+
class EmailService:
|
|
135
|
+
def __init__(self):
|
|
136
|
+
self.server = "smtp.example.com"
|
|
137
|
+
|
|
138
|
+
def send_email(self, to: str, subject: str):
|
|
139
|
+
return f"Email sent to {to} via {self.server}"
|
|
140
|
+
|
|
141
|
+
@bean
|
|
142
|
+
class NotificationService:
|
|
143
|
+
def __init__(self, email: EmailService):
|
|
144
|
+
self.email = email
|
|
145
|
+
|
|
146
|
+
def notify(self, user: str, message: str):
|
|
147
|
+
return self.email.send_email(user, "Notification", message)
|
|
148
|
+
|
|
149
|
+
refresh()
|
|
150
|
+
|
|
151
|
+
notification_svc = get_bean(NotificationService)
|
|
152
|
+
print(notification_svc.notify("user@example.com", "Hello World!"))
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### How It Works
|
|
156
|
+
|
|
157
|
+
1. **Bean Registration**: Use the `@bean` decorator to register functions that create beans
|
|
158
|
+
2. **Type Annotations**: Use type annotations to declare dependencies
|
|
159
|
+
3. **Container Initialization**: Call `refresh()` to initialize the container and resolve dependencies
|
|
160
|
+
4. **Bean Retrieval**: Use `get_bean()` to retrieve beans by type or name
|
|
161
|
+
|
|
162
|
+
### Advanced Usage
|
|
163
|
+
|
|
164
|
+
#### Custom Application Context
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from appctx import ApplicationContext
|
|
168
|
+
|
|
169
|
+
# Create custom context
|
|
170
|
+
ctx = ApplicationContext()
|
|
171
|
+
|
|
172
|
+
@ctx.bean
|
|
173
|
+
def my_service():
|
|
174
|
+
return MyService()
|
|
175
|
+
|
|
176
|
+
ctx.refresh()
|
|
177
|
+
service = ctx.get_bean(MyService)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
#### Multiple Beans of Same Type
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
@bean
|
|
184
|
+
def primary_db():
|
|
185
|
+
return DatabaseService("primary://db")
|
|
186
|
+
|
|
187
|
+
@bean
|
|
188
|
+
def secondary_db():
|
|
189
|
+
return DatabaseService("secondary://db")
|
|
190
|
+
|
|
191
|
+
refresh()
|
|
192
|
+
|
|
193
|
+
# Get all database services
|
|
194
|
+
dbs = get_beans(DatabaseService)
|
|
195
|
+
print(f"Found {len(dbs)} database services")
|
|
196
|
+
|
|
197
|
+
# Get all beans of a specific type
|
|
198
|
+
databases = get_beans(DatabaseService)
|
|
199
|
+
print(len(databases)) # 2
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
#### Named Bean Retrieval
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
@bean
|
|
206
|
+
def database_service():
|
|
207
|
+
return DatabaseService("app.db")
|
|
208
|
+
|
|
209
|
+
refresh()
|
|
210
|
+
|
|
211
|
+
# Get bean by name (function name)
|
|
212
|
+
db = get_bean("database_service")
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## API Reference
|
|
216
|
+
|
|
217
|
+
### Core Decorators
|
|
218
|
+
|
|
219
|
+
#### `@bean`
|
|
220
|
+
|
|
221
|
+
Register a function or class as a bean.
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
@bean
|
|
225
|
+
def my_service():
|
|
226
|
+
return MyService()
|
|
227
|
+
|
|
228
|
+
@bean
|
|
229
|
+
class MyComponent:
|
|
230
|
+
def __init__(self, dependency: SomeDependency):
|
|
231
|
+
self.dependency = dependency
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Container Operations
|
|
235
|
+
|
|
236
|
+
#### `refresh()`
|
|
237
|
+
|
|
238
|
+
Initialize the container and instantiate all beans. Must be called before getting beans.
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
refresh()
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### `get_bean(key)`
|
|
245
|
+
|
|
246
|
+
Get a bean by type or name.
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
# Get by type
|
|
250
|
+
service = get_bean(MyService)
|
|
251
|
+
|
|
252
|
+
# Get by name
|
|
253
|
+
service = get_bean("my_service")
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
#### `get_beans(type)`
|
|
257
|
+
|
|
258
|
+
Get all beans of a specific type.
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
services = get_beans(MyService)
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Dependency Resolution
|
|
265
|
+
|
|
266
|
+
AppCtx uses the following rules to resolve dependencies:
|
|
267
|
+
|
|
268
|
+
1. **Type Annotation Priority** - If a parameter has type annotation, find bean by type
|
|
269
|
+
2. **Name Matching** - If no type annotation, find bean by parameter name
|
|
270
|
+
3. **Auto-wiring** - Container automatically resolves and injects dependencies
|
|
271
|
+
4. **Circular Dependency Detection** - Detects and reports circular dependency issues
|
|
272
|
+
|
|
273
|
+
## Error Handling
|
|
274
|
+
|
|
275
|
+
### Common Errors
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
# Bean not found
|
|
279
|
+
try:
|
|
280
|
+
service = get_bean(UnknownService)
|
|
281
|
+
except KeyError as e:
|
|
282
|
+
print(f"Bean not found: {e}")
|
|
283
|
+
|
|
284
|
+
# Multiple beans of same type conflict
|
|
285
|
+
try:
|
|
286
|
+
refresh()
|
|
287
|
+
except RuntimeError as e:
|
|
288
|
+
print(f"Bean instantiation failed: {e}")
|
|
289
|
+
|
|
290
|
+
# Circular dependency
|
|
291
|
+
try:
|
|
292
|
+
refresh()
|
|
293
|
+
except RuntimeError as e:
|
|
294
|
+
print(f"Circular dependency detected: {e}")
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Best Practices
|
|
298
|
+
|
|
299
|
+
1. **Use Type Annotations** - Specify dependency types clearly for better code readability
|
|
300
|
+
2. **Single Responsibility** - Each bean should have a clear responsibility
|
|
301
|
+
3. **Interface Abstraction** - Use abstract base classes to define service interfaces
|
|
302
|
+
4. **Configuration Separation** - Centralize bean configuration management
|
|
303
|
+
5. **Test-Friendly** - Design beans that are easy to test
|
|
304
|
+
|
|
305
|
+
## Development
|
|
306
|
+
|
|
307
|
+
### Requirements
|
|
308
|
+
|
|
309
|
+
- Python 3.8 or higher
|
|
310
|
+
- pip
|
|
311
|
+
|
|
312
|
+
### Running Tests
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
pytest tests/
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Running Tests with Coverage
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
pytest --cov=src/appctx tests/
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Code Formatting
|
|
325
|
+
|
|
326
|
+
Format code with Black (line length: 88):
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
black src/ tests/
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Import Sorting
|
|
333
|
+
|
|
334
|
+
Sort imports with isort (Black profile):
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
isort src/ tests/
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Linting
|
|
341
|
+
|
|
342
|
+
Check code quality with flake8:
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
flake8 src/ tests/
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Type Checking
|
|
349
|
+
|
|
350
|
+
Run type checking with mypy:
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
mypy src/
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Run All Quality Checks
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
# Format code
|
|
360
|
+
black src/ tests/
|
|
361
|
+
isort src/ tests/
|
|
362
|
+
|
|
363
|
+
# Run linting and type checking
|
|
364
|
+
flake8 src/ tests/
|
|
365
|
+
mypy src/
|
|
366
|
+
|
|
367
|
+
# Run tests with coverage
|
|
368
|
+
pytest --cov=src/appctx tests/
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## License
|
|
372
|
+
|
|
373
|
+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/wssccc/appctx/blob/main/LICENSE) file for details.
|
|
374
|
+
|
|
375
|
+
## Contributing
|
|
376
|
+
|
|
377
|
+
We welcome contributions! Please see our contributing guidelines below.
|
|
378
|
+
|
|
379
|
+
### Development Setup
|
|
380
|
+
|
|
381
|
+
1. Fork the project
|
|
382
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
383
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
384
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
385
|
+
5. Create a Pull Request
|
|
386
|
+
|
|
387
|
+
### Running Tests
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
# Run all tests
|
|
391
|
+
pytest
|
|
392
|
+
|
|
393
|
+
# Run tests with coverage
|
|
394
|
+
pytest --cov=appctx
|
|
395
|
+
|
|
396
|
+
# Run linting
|
|
397
|
+
black --check src/ tests/
|
|
398
|
+
flake8 src/ tests/
|
|
399
|
+
mypy src/
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Release Process
|
|
403
|
+
|
|
404
|
+
For maintainers, see [RELEASE.md](RELEASE.md) for detailed release instructions.
|
|
405
|
+
|
|
406
|
+
## Links
|
|
407
|
+
|
|
408
|
+
- **Homepage**: [https://github.com/wssccc/appctx](https://github.com/wssccc/appctx)
|
|
409
|
+
- **Repository**: [https://github.com/wssccc/appctx](https://github.com/wssccc/appctx)
|
|
410
|
+
- **PyPI**: [https://pypi.org/project/appctx/](https://pypi.org/project/appctx/)
|
|
411
|
+
- **Issues**: [https://github.com/wssccc/appctx/issues](https://github.com/wssccc/appctx/issues)
|
|
412
|
+
|
|
413
|
+
## Changelog
|
|
414
|
+
|
|
415
|
+
### v0.1.0
|
|
416
|
+
|
|
417
|
+
- Initial release
|
|
418
|
+
- Basic dependency injection functionality
|
|
419
|
+
- Decorator API
|
|
420
|
+
- Auto-wiring support
|
|
421
|
+
- Python 3.8+ support
|