py-autowired 0.2.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 (35) hide show
  1. py_autowired-0.2.0/CHANGELOG.md +8 -0
  2. py_autowired-0.2.0/KULLANIM_KILAVUZU_TR.md +108 -0
  3. py_autowired-0.2.0/LICENSE +21 -0
  4. py_autowired-0.2.0/MANIFEST.in +6 -0
  5. py_autowired-0.2.0/PKG-INFO +78 -0
  6. py_autowired-0.2.0/README.md +47 -0
  7. py_autowired-0.2.0/USAGE_GUIDE_EN.md +102 -0
  8. py_autowired-0.2.0/examples/README.md +51 -0
  9. py_autowired-0.2.0/examples/console_app/main.py +56 -0
  10. py_autowired-0.2.0/examples/django_app/manage.py +25 -0
  11. py_autowired-0.2.0/examples/django_app/runtime_di_demo/settings.py +6 -0
  12. py_autowired-0.2.0/examples/django_app/runtime_di_demo/urls.py +9 -0
  13. py_autowired-0.2.0/examples/django_app/runtime_di_demo/views.py +45 -0
  14. py_autowired-0.2.0/examples/fastapi_app/app.py +78 -0
  15. py_autowired-0.2.0/examples/flask_app/app.py +64 -0
  16. py_autowired-0.2.0/examples/requirements.txt +4 -0
  17. py_autowired-0.2.0/examples/shared/application/use_cases/greetings/greeting_service.py +23 -0
  18. py_autowired-0.2.0/examples/shared/bootstrap/dependency_injection/composition.py +35 -0
  19. py_autowired-0.2.0/examples/shared/domain/contracts/formatting/message_formatter.py +7 -0
  20. py_autowired-0.2.0/examples/shared/domain/contracts/messaging/message_repository.py +7 -0
  21. py_autowired-0.2.0/examples/shared/domain/contracts/metadata/runtime_label_provider.py +7 -0
  22. py_autowired-0.2.0/examples/shared/infrastructure/persistence/adapters/memory/repositories/message_repository.py +26 -0
  23. py_autowired-0.2.0/examples/shared/infrastructure/presentation/formatting/turkish_message_formatter.py +27 -0
  24. py_autowired-0.2.0/examples/shared/infrastructure/runtime/environment/metadata/providers/runtime_label_provider.py +22 -0
  25. py_autowired-0.2.0/pyproject.toml +43 -0
  26. py_autowired-0.2.0/setup.cfg +4 -0
  27. py_autowired-0.2.0/src/py_autowired/autowired.py +775 -0
  28. py_autowired-0.2.0/src/py_autowired/container.py +521 -0
  29. py_autowired-0.2.0/src/py_autowired.egg-info/PKG-INFO +78 -0
  30. py_autowired-0.2.0/src/py_autowired.egg-info/SOURCES.txt +33 -0
  31. py_autowired-0.2.0/src/py_autowired.egg-info/dependency_links.txt +1 -0
  32. py_autowired-0.2.0/src/py_autowired.egg-info/requires.txt +11 -0
  33. py_autowired-0.2.0/src/py_autowired.egg-info/top_level.txt +1 -0
  34. py_autowired-0.2.0/tests/test_autowired.py +93 -0
  35. py_autowired-0.2.0/tests/test_examples.py +156 -0
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ - Restored the original runtime injection rule: self.x_instance = None.
6
+ - Removed provider-based and application-side resolve usage.
7
+ - Reduced the runtime package to autowired.py and container.py.
8
+ - Added layered Console, FastAPI, Flask and Django examples.
@@ -0,0 +1,108 @@
1
+ # py-autowired Türkçe Kullanım Kılavuzu
2
+
3
+ ## Temel kural
4
+
5
+ Runtime bağımlılığı constructor parametresi veya manuel container çağrısı değildir:
6
+
7
+ ```python
8
+ class SiparisServisi:
9
+ def __init__(self):
10
+ self.siparis_repository_instance = None
11
+ ```
12
+
13
+ `auto_inject()`, alan adındaki `siparis_repository` bölümünü kayıtlı
14
+ `ISiparisRepository` veya `SiparisRepository` tipiyle eşleştirir ve nesneyi
15
+ çalışma anında yerleştirir.
16
+
17
+ ## Kurulum
18
+
19
+ ```bash
20
+ pip install py-autowired
21
+ ```
22
+
23
+ ## Kayıt ve başlangıç
24
+
25
+ ```python
26
+ from py_autowired.autowired import auto_inject
27
+ from py_autowired.container import Container
28
+
29
+ container = Container()
30
+ container.register_singleton(IClock, SystemClock)
31
+ container.register_scoped(IUserRepository, SqliteUserRepository)
32
+ container.register_transient(UserService)
33
+
34
+ # Uygulama başlangıcında yalnız bir kez:
35
+ auto_inject(container, root_dir="/uygulamanin/mutlak/yolu")
36
+ ```
37
+
38
+ `auto_inject()` çağrısından önce ilgili soyut ve somut sınıflar import edilmiş
39
+ ve kayıtlar tamamlanmış olmalıdır. Enjekte edilecek uygulama nesnelerini bu
40
+ çağrıdan sonra oluşturun.
41
+
42
+ ## Yaşam süreleri
43
+
44
+ - `register_singleton`: Uygulama süresince aynı nesne.
45
+ - `register_scoped`: Bir scope içinde aynı, sonraki scope'ta yeni nesne.
46
+ - `register_transient`: Her enjeksiyonda yeni nesne.
47
+ - `register_instance`: Önceden oluşturulmuş nesneyi kullanır.
48
+ - `register_factory`: Parametresiz factory ile nesne oluşturur.
49
+
50
+ Console, Flask ve Django gibi senkron yollarda:
51
+
52
+ ```python
53
+ with container.create_scope():
54
+ controller = UserController()
55
+ result = controller.execute()
56
+ ```
57
+
58
+ FastAPI gibi asenkron yollarda:
59
+
60
+ ```python
61
+ async with container.create_scope():
62
+ controller = UserController()
63
+ result = await controller.execute()
64
+ ```
65
+
66
+ ## Katmanlı mimari
67
+
68
+ - Domain: soyut repository/port.
69
+ - Infrastructure: somut repository/adaptör.
70
+ - Application: `self.repository_instance = None` kullanan servis.
71
+ - Composition: kayıtlar ve tek `auto_inject()` çağrısı.
72
+ - Presentation: Console, FastAPI, Flask veya Django controller/view.
73
+
74
+ Sunum ve uygulama katmanlarında manuel bağımlılık çözümleme çağrısı kullanılmaz. Ayrıntılı, çalışan örnekler `examples/` klasöründedir.
75
+
76
+ ## İsim eşleştirme
77
+
78
+ Alan mutlaka küçük harfle başlamalı ve `_instance` ile bitmelidir:
79
+
80
+ - `user_repository_instance` → `IUserRepository`
81
+ - `payment_service_instance` → `PaymentService`
82
+ - `audit_instance` → `ABS_Audit`
83
+
84
+ Bir ad birden fazla kayda uyuyorsa modül yakınlığı kullanılır. Belirsiz kayıtları
85
+ önlemek için servis adlarını açık ve benzersiz tutun.
86
+
87
+ ## Kırmızı çizgi
88
+
89
+ Tek geçerli bağımlılık bildirimi: self.repository_instance = None.
90
+
91
+ ## IDLE ile tek tuşla çalıştırma
92
+
93
+ Terminal komutu yazmanız gerekmez. IDLE içinde aşağıdaki ana dosyalardan birini açın ve **Run > Run Module (F5)** seçin:
94
+
95
+ - Console: `examples/console_app/main.py`
96
+ - FastAPI: `examples/fastapi_app/app.py` — `http://127.0.0.1:8101/di-demo/Ayhan`
97
+ - Flask: `examples/flask_app/app.py` — `http://127.0.0.1:8102/di-demo/Ayhan`
98
+ - Django: `examples/django_app/manage.py` — `http://127.0.0.1:8103/di-demo/Ayhan`
99
+
100
+ Web örnekleri için `examples/requirements.txt` içindeki isteğe bağlı framework bağımlılıklarının bir kez kurulmuş olması gerekir. Kaynak klasöründen çalıştırırken ayrıca `PYTHONPATH` ayarlamanız gerekmez.
101
+
102
+ ## Derin klasör kanıtı
103
+
104
+ `examples/shared` bilinçli olarak düz tutulmamıştır. Domain sözleşmeleri, use-case, repository, formatter, runtime sağlayıcı ve composition root farklı ve iç içe klasörlerdedir. Çalışan enjeksiyon zinciri şöyledir:
105
+
106
+ `Controller -> GreetingService -> MemoryMessageRepository -> TurkishMessageFormatter -> RuntimeLabelProvider`
107
+
108
+ Bu zincirdeki her bağımlılık yalnız `self.<ad>_instance = None` bildirimiyle yerleştirilir. Böylece örnekler, klasör ve modül derinliği arttığında da `auto_inject()` mekanizmasının çalıştığını doğrular.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ayhan
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,6 @@
1
+ include README.md
2
+ include CHANGELOG.md
3
+ include KULLANIM_KILAVUZU_TR.md
4
+ include USAGE_GUIDE_EN.md
5
+ recursive-include examples *.py *.md *.txt
6
+ recursive-include tests *.py
@@ -0,0 +1,78 @@
1
+ Metadata-Version: 2.4
2
+ Name: py-autowired
3
+ Version: 0.2.0
4
+ Summary: Runtime dependency injection through self.x_instance = None
5
+ Author: Ayhan
6
+ License-Expression: MIT
7
+ Keywords: dependency-injection,autowiring,fastapi,flask,django
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Provides-Extra: dev
22
+ Requires-Dist: build>=1.2; extra == "dev"
23
+ Requires-Dist: pytest>=8; extra == "dev"
24
+ Requires-Dist: twine>=6; extra == "dev"
25
+ Provides-Extra: examples
26
+ Requires-Dist: django>=5.1; extra == "examples"
27
+ Requires-Dist: fastapi>=0.115; extra == "examples"
28
+ Requires-Dist: flask>=3.1; extra == "examples"
29
+ Requires-Dist: uvicorn>=0.30; extra == "examples"
30
+ Dynamic: license-file
31
+
32
+ # py-autowired
33
+
34
+ py-autowired injects runtime dependencies into fields declared with one rule:
35
+
36
+ ```python
37
+ class UserService:
38
+ def __init__(self):
39
+ self.user_repository_instance = None
40
+ ```
41
+
42
+ Application code contains no manual dependency-resolution calls. Register
43
+ the services once and call `auto_inject()` once during startup.
44
+
45
+ ```python
46
+ from py_autowired.autowired import auto_inject
47
+ from py_autowired.container import Container
48
+
49
+ container = Container()
50
+ container.register_scoped(IUserRepository, SqliteUserRepository)
51
+ container.register_transient(UserService)
52
+ auto_inject(container, root_dir="/absolute/path/to/project")
53
+
54
+ with container.create_scope():
55
+ service = UserService()
56
+ print(service.user_repository_instance)
57
+ ```
58
+
59
+ ## Runtime package
60
+
61
+ The installed runtime contains only:
62
+
63
+ ```text
64
+ py_autowired/
65
+ autowired.py
66
+ container.py
67
+ ```
68
+
69
+ Python namespace packages make `__init__.py` unnecessary.
70
+
71
+ ## Frameworks
72
+
73
+ The same core works with Console, FastAPI/ASGI, Flask/WSGI and Django. Framework
74
+ examples are under `examples/`; each uses domain, application, infrastructure,
75
+ composition and presentation layers without manual dependency resolution.
76
+
77
+ See [KULLANIM_KILAVUZU_TR.md](KULLANIM_KILAVUZU_TR.md) and
78
+ [USAGE_GUIDE_EN.md](USAGE_GUIDE_EN.md).
@@ -0,0 +1,47 @@
1
+ # py-autowired
2
+
3
+ py-autowired injects runtime dependencies into fields declared with one rule:
4
+
5
+ ```python
6
+ class UserService:
7
+ def __init__(self):
8
+ self.user_repository_instance = None
9
+ ```
10
+
11
+ Application code contains no manual dependency-resolution calls. Register
12
+ the services once and call `auto_inject()` once during startup.
13
+
14
+ ```python
15
+ from py_autowired.autowired import auto_inject
16
+ from py_autowired.container import Container
17
+
18
+ container = Container()
19
+ container.register_scoped(IUserRepository, SqliteUserRepository)
20
+ container.register_transient(UserService)
21
+ auto_inject(container, root_dir="/absolute/path/to/project")
22
+
23
+ with container.create_scope():
24
+ service = UserService()
25
+ print(service.user_repository_instance)
26
+ ```
27
+
28
+ ## Runtime package
29
+
30
+ The installed runtime contains only:
31
+
32
+ ```text
33
+ py_autowired/
34
+ autowired.py
35
+ container.py
36
+ ```
37
+
38
+ Python namespace packages make `__init__.py` unnecessary.
39
+
40
+ ## Frameworks
41
+
42
+ The same core works with Console, FastAPI/ASGI, Flask/WSGI and Django. Framework
43
+ examples are under `examples/`; each uses domain, application, infrastructure,
44
+ composition and presentation layers without manual dependency resolution.
45
+
46
+ See [KULLANIM_KILAVUZU_TR.md](KULLANIM_KILAVUZU_TR.md) and
47
+ [USAGE_GUIDE_EN.md](USAGE_GUIDE_EN.md).
@@ -0,0 +1,102 @@
1
+ # py-autowired English Usage Guide
2
+
3
+ ## Core rule
4
+
5
+ Declare every runtime dependency as a field ending in `_instance`:
6
+
7
+ ```python
8
+ class OrderService:
9
+ def __init__(self):
10
+ self.order_repository_instance = None
11
+ ```
12
+
13
+ `auto_inject()` matches `order_repository` with a registered
14
+ `IOrderRepository` or `OrderRepository` and assigns the object at runtime.
15
+ Application code does not resolve dependencies manually.
16
+
17
+ ## Setup
18
+
19
+ ```bash
20
+ pip install py-autowired
21
+ ```
22
+
23
+ ```python
24
+ from py_autowired.autowired import auto_inject
25
+ from py_autowired.container import Container
26
+
27
+ container = Container()
28
+ container.register_singleton(IClock, SystemClock)
29
+ container.register_scoped(IUserRepository, SqliteUserRepository)
30
+ container.register_transient(UserService)
31
+
32
+ # Exactly once during startup:
33
+ auto_inject(container, root_dir="/absolute/path/to/application")
34
+ ```
35
+
36
+ Import implementations and complete registrations before `auto_inject()`.
37
+ Create injectable application objects only after that call.
38
+
39
+ ## Lifetimes
40
+
41
+ - `register_singleton`: one object for the application lifetime.
42
+ - `register_scoped`: one object per active scope.
43
+ - `register_transient`: a new object per injection.
44
+ - `register_instance`: use an existing object.
45
+ - `register_factory`: create objects through a zero-argument factory.
46
+
47
+ Synchronous request or operation:
48
+
49
+ ```python
50
+ with container.create_scope():
51
+ result = UserController().execute()
52
+ ```
53
+
54
+ Asynchronous request or operation:
55
+
56
+ ```python
57
+ async with container.create_scope():
58
+ result = await UserController().execute()
59
+ ```
60
+
61
+ ## Layered architecture
62
+
63
+ - Domain: repository/port abstractions.
64
+ - Infrastructure: concrete repositories/adapters.
65
+ - Application: services declaring `self.repository_instance = None`.
66
+ - Composition: registrations and the single `auto_inject()` call.
67
+ - Presentation: Console, FastAPI, Flask or Django controller/view.
68
+
69
+ Presentation and application layers contain no manual dependency-resolution calls. Runnable examples are available under `examples/`.
70
+
71
+ ## Naming
72
+
73
+ Fields start with a lowercase letter and end with `_instance`:
74
+
75
+ - `user_repository_instance` → `IUserRepository`
76
+ - `payment_service_instance` → `PaymentService`
77
+ - `audit_instance` → `ABS_Audit`
78
+
79
+ Keep service names unique to avoid ambiguous name matching.
80
+
81
+ ## Non-negotiable pattern
82
+
83
+ The only valid dependency declaration is: self.repository_instance = None.
84
+
85
+ ## One-click run from IDLE
86
+
87
+ No terminal command is required. Open one of these entry-point files in IDLE and choose **Run > Run Module (F5)**:
88
+
89
+ - Console: `examples/console_app/main.py`
90
+ - FastAPI: `examples/fastapi_app/app.py` — `http://127.0.0.1:8101/di-demo/Ayhan`
91
+ - Flask: `examples/flask_app/app.py` — `http://127.0.0.1:8102/di-demo/Ayhan`
92
+ - Django: `examples/django_app/manage.py` — `http://127.0.0.1:8103/di-demo/Ayhan`
93
+
94
+ Install the optional framework dependencies listed in `examples/requirements.txt` once before running the web examples. No manual `PYTHONPATH` setting is needed when running from the source tree.
95
+
96
+ ## Deep-folder proof
97
+
98
+ `examples/shared` is deliberately not flat. Domain contracts, use case, repository, formatter, runtime provider, and composition root live in separate nested folders. The working injection chain is:
99
+
100
+ `Controller -> GreetingService -> MemoryMessageRepository -> TurkishMessageFormatter -> RuntimeLabelProvider`
101
+
102
+ Every dependency in this chain is populated only from a `self.<name>_instance = None` declaration. The examples therefore verify that `auto_inject()` continues to work as folder and module depth increases.
@@ -0,0 +1,51 @@
1
+ # Deep layered examples
2
+
3
+ All four presentation technologies use the same deliberately deep application tree. The depth is intentional: it proves that `auto_inject()` discovers and patches runtime dependencies across nested folders instead of working only when classes share one directory.
4
+
5
+ ```text
6
+ examples/
7
+ shared/
8
+ domain/contracts/
9
+ messaging/message_repository.py
10
+ formatting/message_formatter.py
11
+ metadata/runtime_label_provider.py
12
+ application/use_cases/greetings/
13
+ greeting_service.py
14
+ infrastructure/
15
+ persistence/adapters/memory/repositories/message_repository.py
16
+ presentation/formatting/turkish_message_formatter.py
17
+ runtime/environment/metadata/providers/runtime_label_provider.py
18
+ bootstrap/dependency_injection/
19
+ composition.py
20
+ console_app/main.py
21
+ fastapi_app/app.py
22
+ flask_app/app.py
23
+ django_app/manage.py
24
+ ```
25
+
26
+ The injected chain crosses all those layers:
27
+
28
+ ```text
29
+ Presentation controller
30
+ -> GreetingService
31
+ -> MemoryMessageRepository
32
+ -> TurkishMessageFormatter
33
+ -> RuntimeLabelProvider
34
+ ```
35
+
36
+ Every consumer declares dependencies only as `self.<name>_instance = None`. Application and presentation code contains no manual dependency-resolution calls. No `__init__.py` files are required for this namespace-package example.
37
+
38
+ ## Run directly from IDLE or an editor
39
+
40
+ Open one of these entry-point files and choose **Run > Run Module (F5)** in IDLE:
41
+
42
+ - `console_app/main.py`: prints the complete chain's result in the IDLE shell.
43
+ - `fastapi_app/app.py`: starts at `http://127.0.0.1:8101/di-demo/Ayhan`.
44
+ - `flask_app/app.py`: starts at `http://127.0.0.1:8102/di-demo/Ayhan`.
45
+ - `django_app/manage.py`: starts at `http://127.0.0.1:8103/di-demo/Ayhan`.
46
+
47
+ No terminal command or manual `PYTHONPATH` setting is required. Install the optional framework dependencies from `examples/requirements.txt` once before running the web examples.
48
+
49
+ ## Visible proof in every output
50
+
51
+ Console prints every chain level line by line. FastAPI, Flask, and Django return the same five entries in the `injection_trace` JSON field. Each entry includes `module`, `module_depth`, `class`, `injected_field`, `injected_type`, `method`, `result`, and `instance_id`, so successful deep auto-injection is directly observable instead of inferred from one greeting.
@@ -0,0 +1,56 @@
1
+ import sys
2
+ from pathlib import Path
3
+
4
+ PROJECT_ROOT = Path(__file__).resolve().parents[2]
5
+ if str(PROJECT_ROOT) not in sys.path:
6
+ sys.path.insert(0, str(PROJECT_ROOT))
7
+
8
+ from examples.shared.bootstrap.dependency_injection.composition import configure_dependencies
9
+
10
+
11
+ class ConsoleController:
12
+ def __init__(self):
13
+ self.greeting_service_instance = None
14
+
15
+ def execute(self, name: str) -> dict[str, object]:
16
+ message = self.greeting_service_instance.greet(name)
17
+ controller_trace = {
18
+ "chain_level": 1,
19
+ "module_depth": len(type(self).__module__.split(".")),
20
+ "module": type(self).__module__,
21
+ "class": type(self).__name__,
22
+ "injected_field": "greeting_service_instance",
23
+ "injected_type": type(self.greeting_service_instance).__name__,
24
+ "method": "execute()",
25
+ "result": message,
26
+ "instance_id": id(self),
27
+ }
28
+ return {
29
+ "message": message,
30
+ "injection_trace": [
31
+ controller_trace,
32
+ *self.greeting_service_instance.injection_trace(name),
33
+ ],
34
+ }
35
+
36
+
37
+ def main() -> None:
38
+ container = configure_dependencies()
39
+ with container.create_scope():
40
+ result = ConsoleController().execute("Console")
41
+ print(result["message"])
42
+ print("\nAUTO_INJECT DERINLIK ZINCIRI")
43
+ for step in result["injection_trace"]:
44
+ print(
45
+ f"[{step['chain_level']}] {step['module']} "
46
+ f"(modul derinligi={step['module_depth']})"
47
+ )
48
+ print(
49
+ f" {step['class']}.{step['method']} -> {step['result']} "
50
+ f"| inject: {step['injected_field']} = {step['injected_type']} "
51
+ f"| instance_id={step['instance_id']}"
52
+ )
53
+
54
+
55
+ if __name__ == "__main__":
56
+ main()
@@ -0,0 +1,25 @@
1
+ import os
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ PROJECT_ROOT = Path(__file__).resolve().parents[2]
6
+ if str(PROJECT_ROOT) not in sys.path:
7
+ sys.path.insert(0, str(PROJECT_ROOT))
8
+
9
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "examples.django_app.runtime_di_demo.settings")
10
+
11
+ from django.core.management import execute_from_command_line
12
+
13
+
14
+ def main() -> None:
15
+ arguments = sys.argv
16
+ if len(arguments) == 1:
17
+ arguments = [arguments[0], "runserver", "127.0.0.1:8103", "--noreload"]
18
+ print("py-autowired: 5 katmanli Runtime DI demosu")
19
+ print("Tarayicida acin: http://127.0.0.1:8103/di-demo/Ayhan")
20
+ print("JSON cevabinda injection_trace alanini inceleyin.")
21
+ execute_from_command_line(arguments)
22
+
23
+
24
+ if __name__ == "__main__":
25
+ main()
@@ -0,0 +1,6 @@
1
+ SECRET_KEY = "local-demo-only"
2
+ DEBUG = True
3
+ ROOT_URLCONF = "examples.django_app.runtime_di_demo.urls"
4
+ ALLOWED_HOSTS = ["127.0.0.1", "localhost", "testserver"]
5
+ MIDDLEWARE = []
6
+ INSTALLED_APPS = []
@@ -0,0 +1,9 @@
1
+ from django.urls import path
2
+ from examples.django_app.runtime_di_demo.views import di_demo, index
3
+
4
+
5
+ urlpatterns = [
6
+ path("", index),
7
+ path("di-demo/<str:name>", di_demo),
8
+ path("hello/<str:name>/", di_demo),
9
+ ]
@@ -0,0 +1,45 @@
1
+ from django.http import HttpResponse, JsonResponse
2
+
3
+ from examples.shared.bootstrap.dependency_injection.composition import configure_dependencies
4
+
5
+
6
+ DEMO_HOME_HTML = """<!doctype html>
7
+ <html lang="tr"><head><meta charset="utf-8"><title>py-autowired DI Demo</title></head>
8
+ <body><h1>py-autowired Runtime DI Demo</h1>
9
+ <p>Beş katmanlı auto-inject zincirini JSON olarak görmek için bağlantıyı açın.</p>
10
+ <p><a href="/di-demo/Ayhan">/di-demo/Ayhan</a></p></body></html>"""
11
+
12
+
13
+ class DjangoController:
14
+ def __init__(self):
15
+ self.greeting_service_instance = None
16
+
17
+ def execute(self, name: str) -> dict[str, object]:
18
+ message = self.greeting_service_instance.greet(name)
19
+ return {
20
+ "message": message,
21
+ "injection_trace": [
22
+ {
23
+ "chain_level": 1,
24
+ "module_depth": len(type(self).__module__.split(".")),
25
+ "module": type(self).__module__,
26
+ "class": type(self).__name__,
27
+ "injected_field": "greeting_service_instance",
28
+ "injected_type": type(self.greeting_service_instance).__name__,
29
+ "method": "execute()",
30
+ "result": message,
31
+ "instance_id": id(self),
32
+ },
33
+ *self.greeting_service_instance.injection_trace(name),
34
+ ],
35
+ }
36
+
37
+
38
+ def index(_request):
39
+ return HttpResponse(DEMO_HOME_HTML)
40
+
41
+
42
+ def di_demo(_request, name: str):
43
+ container = configure_dependencies()
44
+ with container.create_scope():
45
+ return JsonResponse(DjangoController().execute(name))
@@ -0,0 +1,78 @@
1
+ from contextlib import asynccontextmanager
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ PROJECT_ROOT = Path(__file__).resolve().parents[2]
6
+ if str(PROJECT_ROOT) not in sys.path:
7
+ sys.path.insert(0, str(PROJECT_ROOT))
8
+
9
+ from fastapi import FastAPI
10
+ from fastapi.responses import HTMLResponse
11
+ from examples.shared.bootstrap.dependency_injection.composition import configure_dependencies
12
+
13
+
14
+ DEMO_HOME_HTML = """<!doctype html>
15
+ <html lang="tr"><head><meta charset="utf-8"><title>py-autowired DI Demo</title></head>
16
+ <body><h1>py-autowired Runtime DI Demo</h1>
17
+ <p>Beş katmanlı auto-inject zincirini JSON olarak görmek için bağlantıyı açın.</p>
18
+ <p><a href="/di-demo/Ayhan">/di-demo/Ayhan</a></p></body></html>"""
19
+
20
+
21
+ class FastApiController:
22
+ def __init__(self):
23
+ self.greeting_service_instance = None
24
+
25
+ def execute(self, name: str) -> dict[str, object]:
26
+ message = self.greeting_service_instance.greet(name)
27
+ return {
28
+ "message": message,
29
+ "injection_trace": [
30
+ {
31
+ "chain_level": 1,
32
+ "module_depth": len(type(self).__module__.split(".")),
33
+ "module": type(self).__module__,
34
+ "class": type(self).__name__,
35
+ "injected_field": "greeting_service_instance",
36
+ "injected_type": type(self.greeting_service_instance).__name__,
37
+ "method": "execute()",
38
+ "result": message,
39
+ "instance_id": id(self),
40
+ },
41
+ *self.greeting_service_instance.injection_trace(name),
42
+ ],
43
+ }
44
+
45
+
46
+ @asynccontextmanager
47
+ async def lifespan(_app: FastAPI):
48
+ configure_dependencies()
49
+ yield
50
+
51
+
52
+ app = FastAPI(lifespan=lifespan)
53
+
54
+
55
+ @app.get("/", response_class=HTMLResponse)
56
+ async def index():
57
+ return HTMLResponse(DEMO_HOME_HTML)
58
+
59
+
60
+ @app.get("/di-demo/{name}")
61
+ async def di_demo(name: str):
62
+ container = configure_dependencies()
63
+ async with container.create_scope():
64
+ return FastApiController().execute(name)
65
+
66
+
67
+ @app.get("/hello/{name}", include_in_schema=False)
68
+ async def hello(name: str):
69
+ return await di_demo(name)
70
+
71
+
72
+ if __name__ == "__main__":
73
+ import uvicorn
74
+
75
+ print("py-autowired: 5 katmanli Runtime DI demosu")
76
+ print("Tarayicida acin: http://127.0.0.1:8101/di-demo/Ayhan")
77
+ print("JSON cevabinda injection_trace alanini inceleyin.")
78
+ uvicorn.run(app, host="127.0.0.1", port=8101)