forge-core-di 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 (86) hide show
  1. forge_core_di-0.2.0/.gitignore +9 -0
  2. forge_core_di-0.2.0/CHANGELOG.md +47 -0
  3. forge_core_di-0.2.0/CONTRIBUTING.md +21 -0
  4. forge_core_di-0.2.0/LICENSE +9 -0
  5. forge_core_di-0.2.0/PKG-INFO +58 -0
  6. forge_core_di-0.2.0/README.md +38 -0
  7. forge_core_di-0.2.0/daftar_test.txt +22 -0
  8. forge_core_di-0.2.0/examples/automation.py +75 -0
  9. forge_core_di-0.2.0/examples/event_driven.py +54 -0
  10. forge_core_di-0.2.0/examples/trading_bot.py +92 -0
  11. forge_core_di-0.2.0/grep_circular.txt +0 -0
  12. forge_core_di-0.2.0/grep_scope.txt +63 -0
  13. forge_core_di-0.2.0/pyproject.toml +54 -0
  14. forge_core_di-0.2.0/semua_kode.txt +1577 -0
  15. forge_core_di-0.2.0/src/forgecore/__init__.py +88 -0
  16. forge_core_di-0.2.0/src/forgecore/application/__init__.py +7 -0
  17. forge_core_di-0.2.0/src/forgecore/application/app.py +94 -0
  18. forge_core_di-0.2.0/src/forgecore/application/metadata.py +11 -0
  19. forge_core_di-0.2.0/src/forgecore/config/__init__.py +5 -0
  20. forge_core_di-0.2.0/src/forgecore/config/config.py +23 -0
  21. forge_core_di-0.2.0/src/forgecore/context/__init__.py +5 -0
  22. forge_core_di-0.2.0/src/forgecore/context/context.py +23 -0
  23. forge_core_di-0.2.0/src/forgecore/core/__init__.py +31 -0
  24. forge_core_di-0.2.0/src/forgecore/core/constants.py +7 -0
  25. forge_core_di-0.2.0/src/forgecore/core/exceptions.py +18 -0
  26. forge_core_di-0.2.0/src/forgecore/core/types.py +4 -0
  27. forge_core_di-0.2.0/src/forgecore/core/version.py +3 -0
  28. forge_core_di-0.2.0/src/forgecore/lifecycle/__init__.py +7 -0
  29. forge_core_di-0.2.0/src/forgecore/lifecycle/manager.py +40 -0
  30. forge_core_di-0.2.0/src/forgecore/lifecycle/state.py +11 -0
  31. forge_core_di-0.2.0/src/forgecore/logging/__init__.py +5 -0
  32. forge_core_di-0.2.0/src/forgecore/logging/logger.py +23 -0
  33. forge_core_di-0.2.0/src/forgecore/plugins/__init__.py +7 -0
  34. forge_core_di-0.2.0/src/forgecore/plugins/manager.py +31 -0
  35. forge_core_di-0.2.0/src/forgecore/plugins/plugin.py +21 -0
  36. forge_core_di-0.2.0/src/forgecore/providers/__init__.py +5 -0
  37. forge_core_di-0.2.0/src/forgecore/providers/provider.py +14 -0
  38. forge_core_di-0.2.0/src/forgecore/registry/__init__.py +7 -0
  39. forge_core_di-0.2.0/src/forgecore/registry/exceptions.py +2 -0
  40. forge_core_di-0.2.0/src/forgecore/registry/registry.py +31 -0
  41. forge_core_di-0.2.0/src/forgecore/runtime/__init__.py +9 -0
  42. forge_core_di-0.2.0/src/forgecore/runtime/bus.py +50 -0
  43. forge_core_di-0.2.0/src/forgecore/runtime/event.py +10 -0
  44. forge_core_di-0.2.0/src/forgecore/runtime/exceptions.py +2 -0
  45. forge_core_di-0.2.0/src/forgecore/services/__init__.py +20 -0
  46. forge_core_di-0.2.0/src/forgecore/services/autowire.py +27 -0
  47. forge_core_di-0.2.0/src/forgecore/services/container.py +103 -0
  48. forge_core_di-0.2.0/src/forgecore/services/descriptor.py +16 -0
  49. forge_core_di-0.2.0/src/forgecore/services/exceptions.py +6 -0
  50. forge_core_di-0.2.0/src/forgecore/services/factory.py +22 -0
  51. forge_core_di-0.2.0/src/forgecore/services/resolver.py +165 -0
  52. forge_core_di-0.2.0/src/forgecore/services/scope.py +7 -0
  53. forge_core_di-0.2.0/src/forgecore/services/scope_context.py +31 -0
  54. forge_core_di-0.2.0/src/forgecore/utils/__init__.py +9 -0
  55. forge_core_di-0.2.0/src/forgecore/utils/inspect.py +7 -0
  56. forge_core_di-0.2.0/src/forgecore/utils/system.py +15 -0
  57. forge_core_di-0.2.0/src/forgecore/validation/__init__.py +15 -0
  58. forge_core_di-0.2.0/src/forgecore/validation/validators.py +21 -0
  59. forge_core_di-0.2.0/src/forgecore/version.py +1 -0
  60. forge_core_di-0.2.0/struktur_proyek.txt +66 -0
  61. forge_core_di-0.2.0/tests/test_app_events.py +37 -0
  62. forge_core_di-0.2.0/tests/test_application.py +87 -0
  63. forge_core_di-0.2.0/tests/test_autowire.py +63 -0
  64. forge_core_di-0.2.0/tests/test_binding.py +17 -0
  65. forge_core_di-0.2.0/tests/test_binding_resolver.py +19 -0
  66. forge_core_di-0.2.0/tests/test_circular.py +50 -0
  67. forge_core_di-0.2.0/tests/test_config.py +12 -0
  68. forge_core_di-0.2.0/tests/test_context.py +12 -0
  69. forge_core_di-0.2.0/tests/test_descriptor.py +27 -0
  70. forge_core_di-0.2.0/tests/test_factory.py +56 -0
  71. forge_core_di-0.2.0/tests/test_lifecycle.py +61 -0
  72. forge_core_di-0.2.0/tests/test_metadata.py +36 -0
  73. forge_core_di-0.2.0/tests/test_optional_injection.py +59 -0
  74. forge_core_di-0.2.0/tests/test_plugin.py +27 -0
  75. forge_core_di-0.2.0/tests/test_plugin_manager.py +41 -0
  76. forge_core_di-0.2.0/tests/test_provider.py +58 -0
  77. forge_core_di-0.2.0/tests/test_registry.py +20 -0
  78. forge_core_di-0.2.0/tests/test_resolver.py +37 -0
  79. forge_core_di-0.2.0/tests/test_runtime.py +86 -0
  80. forge_core_di-0.2.0/tests/test_scope.py +9 -0
  81. forge_core_di-0.2.0/tests/test_scoped.py +97 -0
  82. forge_core_di-0.2.0/tests/test_service_descriptor_container.py +32 -0
  83. forge_core_di-0.2.0/tests/test_services.py +23 -0
  84. forge_core_di-0.2.0/tests/test_singleton.py +24 -0
  85. forge_core_di-0.2.0/tests/test_validation.py +28 -0
  86. forge_core_di-0.2.0/tests/test_version.py +13 -0
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .coverage
7
+ dist/
8
+ build/
9
+ .venv/
@@ -0,0 +1,47 @@
1
+ # Changelog
2
+
3
+ All notable changes to ForgeCore will be documented here.
4
+
5
+ ---
6
+
7
+ ## [0.2.0] - 2026-06-28
8
+
9
+ ### Added
10
+ - Scoped lifecycle (`ServiceScope.SCOPED`) — one instance per scope context
11
+ - Thread-safe scope via `threading.local()` — safe for concurrent applications
12
+ - Circular dependency detection with clear error messages (`CircularDependencyError`)
13
+ - Optional injection support (`Cache | None = None`)
14
+ - `ServiceProvider` system connected to `ForgeApp` boot pipeline
15
+ - `LifecycleManager` hooks — `on_start` and `on_stop` (LIFO order)
16
+ - `EventBus` connected to `ForgeApp` lifecycle — automatic lifecycle events
17
+ - `EventBus.unsubscribe()`, `has_listeners()`, and `clear()`
18
+ - `ForgeApp` boot guards — prevents double boot, double run, and stop without run
19
+ - Unified resolution pipeline — `get()` and `resolve()` now use the same path
20
+ - Public API — all core classes importable directly from `forgecore`
21
+ - Examples — `trading_bot.py`, `automation.py`, `event_driven.py`
22
+
23
+ ### Changed
24
+ - `ServiceContainer` now enforces explicit registration — no implicit auto-registration
25
+ - `ForgeApp.run()` now calls `boot()` automatically if not already booted
26
+ - `Development Status` classifier updated from Pre-Alpha to Alpha
27
+
28
+ ### Fixed
29
+ - `container.get()` now resolves bindings correctly (previously bypassed binding system)
30
+ - Duplicate `ServiceNotFoundError` definition in `exceptions.py`
31
+ - Forward reference string annotations now resolved correctly in autowiring
32
+
33
+ ---
34
+
35
+ ## [0.1.0] - 2025-01-01
36
+
37
+ ### Added
38
+ - Initial release
39
+ - DI container with singleton and transient lifecycle
40
+ - Constructor autowiring via type hints
41
+ - Service binding — abstraction to implementation mapping
42
+ - Custom factory support
43
+ - `ForgeApp` application kernel
44
+ - `EventBus` runtime event system
45
+ - `LifecycleManager` state machine
46
+ - `Registry` key-value store
47
+ - `PluginManager` runtime extension system
@@ -0,0 +1,21 @@
1
+ # Contributing to ForgeCore
2
+
3
+ Thank you for your interest in contributing to ForgeCore.
4
+
5
+ ---
6
+
7
+ ## Requirements
8
+
9
+ - Python 3.12+
10
+ - Git
11
+
12
+ ---
13
+
14
+ ## Setup
15
+
16
+ ```bash
17
+ git clone https://github.com/akmalmaulana/forgecore
18
+ cd forgecore
19
+ python -m venv .venv
20
+ source .venv/bin/activate
21
+ pip install -e ".[dev]"
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Akmal Maulana
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.
@@ -0,0 +1,58 @@
1
+ Metadata-Version: 2.4
2
+ Name: forge-core-di
3
+ Version: 0.2.0
4
+ Summary: Lightweight Dependency Injection and Application Runtime Core for Python.
5
+ Project-URL: Homepage, https://github.com/akmallmline/forgecore
6
+ Project-URL: Repository, https://github.com/akmallmline/forgecore
7
+ Author-email: Akmal Maulana <akmallmline@gmail.com>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: application-kernel,autowiring,dependency-injection,di-container,framework,lifecycle,plugin,python
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
18
+ Requires-Python: >=3.12
19
+ Description-Content-Type: text/markdown
20
+
21
+ # ForgeCore
22
+
23
+ Lightweight Dependency Injection and Application Runtime Core for Python.
24
+
25
+ ForgeCore is a framework engine — not just a DI container. It provides the
26
+ foundation for building web frameworks, CLI tools, bots, trading systems,
27
+ and AI agents in Python.
28
+
29
+ ---
30
+
31
+ ## Features
32
+
33
+ - Explicit DI container — no magic auto-registration
34
+ - Constructor autowiring via type hints
35
+ - Singleton, Transient, and Scoped lifecycles
36
+ - Thread-safe scoped instances via `threading.local()`
37
+ - Circular dependency detection with clear error messages
38
+ - Optional injection (`Cache | None = None`)
39
+ - Service binding — abstraction to implementation mapping
40
+ - Custom factory support
41
+ - Application kernel with boot pipeline
42
+ - Service provider system for modular registration
43
+ - Lifecycle hooks (`on_start`, `on_stop`)
44
+ - Event system with subscribe, emit, and unsubscribe
45
+ - Plugin system for runtime extension
46
+
47
+ ---
48
+
49
+ ## Requirements
50
+
51
+ - Python 3.12+
52
+
53
+ ---
54
+
55
+ ## Installation
56
+
57
+ ```bash
58
+ pip install forgecore
@@ -0,0 +1,38 @@
1
+ # ForgeCore
2
+
3
+ Lightweight Dependency Injection and Application Runtime Core for Python.
4
+
5
+ ForgeCore is a framework engine — not just a DI container. It provides the
6
+ foundation for building web frameworks, CLI tools, bots, trading systems,
7
+ and AI agents in Python.
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ - Explicit DI container — no magic auto-registration
14
+ - Constructor autowiring via type hints
15
+ - Singleton, Transient, and Scoped lifecycles
16
+ - Thread-safe scoped instances via `threading.local()`
17
+ - Circular dependency detection with clear error messages
18
+ - Optional injection (`Cache | None = None`)
19
+ - Service binding — abstraction to implementation mapping
20
+ - Custom factory support
21
+ - Application kernel with boot pipeline
22
+ - Service provider system for modular registration
23
+ - Lifecycle hooks (`on_start`, `on_stop`)
24
+ - Event system with subscribe, emit, and unsubscribe
25
+ - Plugin system for runtime extension
26
+
27
+ ---
28
+
29
+ ## Requirements
30
+
31
+ - Python 3.12+
32
+
33
+ ---
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install forgecore
@@ -0,0 +1,22 @@
1
+ ./tests/test_application.py
2
+ ./tests/test_autowire.py
3
+ ./tests/test_binding.py
4
+ ./tests/test_binding_resolver.py
5
+ ./tests/test_config.py
6
+ ./tests/test_context.py
7
+ ./tests/test_descriptor.py
8
+ ./tests/test_factory.py
9
+ ./tests/test_lifecycle.py
10
+ ./tests/test_metadata.py
11
+ ./tests/test_plugin.py
12
+ ./tests/test_plugin_manager.py
13
+ ./tests/test_provider.py
14
+ ./tests/test_registry.py
15
+ ./tests/test_resolver.py
16
+ ./tests/test_runtime.py
17
+ ./tests/test_scope.py
18
+ ./tests/test_service_descriptor_container.py
19
+ ./tests/test_services.py
20
+ ./tests/test_singleton.py
21
+ ./tests/test_validation.py
22
+ ./tests/test_version.py
@@ -0,0 +1,75 @@
1
+ from forgecore import (
2
+ ApplicationMetadata,
3
+ ForgeApp,
4
+ ServiceContainer,
5
+ ServiceProvider,
6
+ )
7
+
8
+
9
+ class Config:
10
+ def __init__(self) -> None:
11
+ self.base_url = "https://api.example.com"
12
+ self.hub_id = "prajekan"
13
+
14
+
15
+ class SessionManager:
16
+ def __init__(self, config: Config) -> None:
17
+ self.config = config
18
+ self.token = ""
19
+
20
+ def login(self) -> None:
21
+ print(f"Login ke {self.config.base_url}...")
22
+ self.token = "secret-token-123"
23
+ print("Login berhasil.")
24
+
25
+
26
+ class DataFetcher:
27
+ def __init__(self, config: Config, session: SessionManager) -> None:
28
+ self.config = config
29
+ self.session = session
30
+
31
+ def fetch(self, item_id: str) -> dict:
32
+ return {
33
+ "id": item_id,
34
+ "hub": self.config.hub_id,
35
+ "status": "FOUND",
36
+ "token_used": self.session.token,
37
+ }
38
+
39
+
40
+ class ReportGenerator:
41
+ def __init__(self, fetcher: DataFetcher) -> None:
42
+ self.fetcher = fetcher
43
+
44
+ def run(self, ids: list[str]) -> None:
45
+ print("\n=== REPORT ===")
46
+ for item_id in ids:
47
+ result = self.fetcher.fetch(item_id)
48
+ print(f"{result['id']} → {result['status']}")
49
+ print("==============")
50
+
51
+
52
+ class AppProvider(ServiceProvider):
53
+ def register(self, container: ServiceContainer) -> None:
54
+ container.singleton(Config)
55
+ container.singleton(SessionManager)
56
+ container.singleton(DataFetcher)
57
+ container.singleton(ReportGenerator)
58
+
59
+ def boot(self, container: ServiceContainer) -> None:
60
+ session = container.get(SessionManager)
61
+ session.login()
62
+
63
+
64
+ app = ForgeApp(
65
+ metadata=ApplicationMetadata(
66
+ name="Automation Example",
67
+ version="1.0.0",
68
+ )
69
+ )
70
+
71
+ app.register_provider(AppProvider())
72
+ app.boot()
73
+
74
+ report = app.services.get(ReportGenerator)
75
+ report.run(["ID-001", "ID-002", "ID-003"])
@@ -0,0 +1,54 @@
1
+ from forgecore import (
2
+ ApplicationMetadata,
3
+ Event,
4
+ EventBus,
5
+ ForgeApp,
6
+ ServiceContainer,
7
+ ServiceProvider,
8
+ )
9
+
10
+
11
+ class OrderService:
12
+ def __init__(self, bus: EventBus) -> None:
13
+ self.bus = bus
14
+
15
+ def place_order(self, item: str, qty: int) -> None:
16
+ print(f"Order ditempatkan: {qty}x {item}")
17
+ self.bus.emit(Event(
18
+ name="order.placed",
19
+ payload={"item": item, "qty": qty},
20
+ ))
21
+
22
+
23
+ class NotificationService:
24
+ def on_order_placed(self, event: Event) -> None:
25
+ item = event.payload["item"]
26
+ qty = event.payload["qty"]
27
+ print(f"[Notifikasi] Order baru: {qty}x {item}")
28
+
29
+
30
+ class AppProvider(ServiceProvider):
31
+ def register(self, container: ServiceContainer) -> None:
32
+ container.singleton(EventBus)
33
+ container.singleton(OrderService)
34
+ container.singleton(NotificationService)
35
+
36
+ def boot(self, container: ServiceContainer) -> None:
37
+ bus = container.get(EventBus)
38
+ notif = container.get(NotificationService)
39
+ bus.subscribe("order.placed", notif.on_order_placed)
40
+
41
+
42
+ app = ForgeApp(
43
+ metadata=ApplicationMetadata(
44
+ name="Event Driven Example",
45
+ version="1.0.0",
46
+ )
47
+ )
48
+
49
+ app.register_provider(AppProvider())
50
+ app.boot()
51
+
52
+ order_service = app.services.get(OrderService)
53
+ order_service.place_order("XAUUSD Contract", 2)
54
+ order_service.place_order("Bitcoin Futures", 1)
@@ -0,0 +1,92 @@
1
+ from forgecore import (
2
+ ApplicationMetadata,
3
+ Event,
4
+ ForgeApp,
5
+ ServiceContainer,
6
+ ServiceProvider,
7
+ )
8
+
9
+
10
+ class Config:
11
+ def __init__(self) -> None:
12
+ self.symbol = "XAUUSD"
13
+ self.timeframe = "M5"
14
+ self.risk_percent = 1.0
15
+
16
+
17
+ class Logger:
18
+ def __init__(self, config: Config) -> None:
19
+ self.config = config
20
+
21
+ def log(self, msg: str) -> None:
22
+ print(f"[{self.config.symbol}] {msg}")
23
+
24
+
25
+ class MarketData:
26
+ def __init__(self, config: Config, logger: Logger) -> None:
27
+ self.config = config
28
+ self.logger = logger
29
+
30
+ def fetch(self) -> dict:
31
+ self.logger.log("Fetching market data...")
32
+ return {"price": 2345.50, "trend": "bullish"}
33
+
34
+
35
+ class SignalEngine:
36
+ def __init__(self, data: MarketData, logger: Logger) -> None:
37
+ self.data = data
38
+ self.logger = logger
39
+
40
+ def analyze(self) -> str | None:
41
+ market = self.data.fetch()
42
+ if market["trend"] == "bullish":
43
+ self.logger.log(f"Signal: BUY at {market['price']}")
44
+ return "BUY"
45
+ return None
46
+
47
+
48
+ class TelegramNotifier:
49
+ def __init__(self, config: Config) -> None:
50
+ self.config = config
51
+
52
+ def send(self, message: str) -> None:
53
+ print(f"[Telegram] {message}")
54
+
55
+
56
+ class BotProvider(ServiceProvider):
57
+ def register(self, container: ServiceContainer) -> None:
58
+ container.singleton(Config)
59
+ container.singleton(Logger)
60
+ container.singleton(MarketData)
61
+ container.singleton(SignalEngine)
62
+ container.singleton(TelegramNotifier)
63
+
64
+ def boot(self, container: ServiceContainer) -> None:
65
+ pass
66
+
67
+
68
+ app = ForgeApp(
69
+ metadata=ApplicationMetadata(
70
+ name="XAUUSD Signal Bot",
71
+ version="1.0.0",
72
+ )
73
+ )
74
+
75
+ app.register_provider(BotProvider())
76
+
77
+ app.events.subscribe("app.running", lambda e: print("Bot aktif..."))
78
+ app.events.subscribe("app.stopped", lambda e: print("Bot dimatikan."))
79
+
80
+ app.lifecycle.on_start(lambda: print("Koneksi broker dibuka"))
81
+ app.lifecycle.on_stop(lambda: print("Koneksi broker ditutup"))
82
+
83
+ app.run()
84
+
85
+ engine = app.services.get(SignalEngine)
86
+ notifier = app.services.get(TelegramNotifier)
87
+
88
+ signal = engine.analyze()
89
+ if signal:
90
+ notifier.send(f"Signal: {signal} XAUUSD @ 2345.50")
91
+
92
+ app.stop()
File without changes
@@ -0,0 +1,63 @@
1
+ ./src/forgecore/services/__init__.py:7:from .scope import ServiceScope
2
+ ./src/forgecore/services/__init__.py:12: "ServiceScope",
3
+ ./src/forgecore/services/container.py:9:from .scope import ServiceScope
4
+ ./src/forgecore/services/container.py:22: scope: ServiceScope = ServiceScope.SINGLETON,
5
+ ./src/forgecore/services/container.py:29: scope=scope,
6
+ ./src/forgecore/services/container.py:48: scope=ServiceScope.SINGLETON,
7
+ ./src/forgecore/services/container.py:64: scope=ServiceScope.TRANSIENT,
8
+ ./src/forgecore/services/container.py:80: if descriptor.scope is ServiceScope.SINGLETON:
9
+ ./src/forgecore/services/scope.py:4:class ServiceScope(str, Enum):
10
+ ./src/forgecore/services/descriptor.py:7:from .scope import ServiceScope
11
+ ./src/forgecore/services/descriptor.py:14: scope: ServiceScope = ServiceScope.SINGLETON
12
+ ./src/forgecore/services/resolver.py:7:from .scope import ServiceScope
13
+ ./src/forgecore/services/resolver.py:33: and descriptor.scope is ServiceScope.SINGLETON
14
+ ./src/forgecore/services/resolver.py:72: scope=ServiceScope.SINGLETON,
15
+ ./src/forgecore/services/resolver.py:75: elif descriptor.scope is ServiceScope.SINGLETON:
16
+ ./src/forgecore/lifecycle/__init__.py:1:from .manager import LifecycleManager
17
+ ./src/forgecore/lifecycle/__init__.py:2:from .state import LifecycleState
18
+ ./src/forgecore/lifecycle/__init__.py:5: "LifecycleManager",
19
+ ./src/forgecore/lifecycle/__init__.py:6: "LifecycleState",
20
+ ./src/forgecore/lifecycle/manager.py:3:from .state import LifecycleState
21
+ ./src/forgecore/lifecycle/manager.py:6:class LifecycleManager:
22
+ ./src/forgecore/lifecycle/manager.py:8: self._state = LifecycleState.INITIALIZED
23
+ ./src/forgecore/lifecycle/manager.py:11: def state(self) -> LifecycleState:
24
+ ./src/forgecore/lifecycle/manager.py:15: self._state = LifecycleState.STARTING
25
+ ./src/forgecore/lifecycle/manager.py:18: self._state = LifecycleState.RUNNING
26
+ ./src/forgecore/lifecycle/manager.py:21: self._state = LifecycleState.STOPPING
27
+ ./src/forgecore/lifecycle/manager.py:24: self._state = LifecycleState.STOPPED
28
+ ./src/forgecore/lifecycle/state.py:6:class LifecycleState(str, Enum):
29
+ ./src/forgecore/application/app.py:38: def lifecycle(self):
30
+ ./src/forgecore/application/app.py:39: return self.context.lifecycle
31
+ ./src/forgecore/application/app.py:42: self.lifecycle.start()
32
+ ./src/forgecore/application/app.py:43: self.lifecycle.run()
33
+ ./src/forgecore/application/app.py:46: self.lifecycle.stop()
34
+ ./src/forgecore/application/app.py:47: self.lifecycle.shutdown()
35
+ ./src/forgecore/context/context.py:4:from forgecore.lifecycle import LifecycleManager
36
+ ./src/forgecore/context/context.py:23: self.lifecycle = LifecycleManager()
37
+ ./tests/test_lifecycle.py:1:from forgecore.lifecycle import LifecycleManager, LifecycleState
38
+ ./tests/test_lifecycle.py:4:def test_lifecycle():
39
+ ./tests/test_lifecycle.py:5: manager = LifecycleManager()
40
+ ./tests/test_lifecycle.py:7: assert manager.state is LifecycleState.INITIALIZED
41
+ ./tests/test_lifecycle.py:10: assert manager.state is LifecycleState.STARTING
42
+ ./tests/test_lifecycle.py:13: assert manager.state is LifecycleState.RUNNING
43
+ ./tests/test_lifecycle.py:16: assert manager.state is LifecycleState.STOPPING
44
+ ./tests/test_lifecycle.py:19: assert manager.state is LifecycleState.STOPPED
45
+ ./tests/test_application.py:2:from forgecore.lifecycle import LifecycleState
46
+ ./tests/test_application.py:8: assert app.lifecycle.state is LifecycleState.INITIALIZED
47
+ ./tests/test_application.py:11: assert app.lifecycle.state is LifecycleState.RUNNING
48
+ ./tests/test_application.py:14: assert app.lifecycle.state is LifecycleState.STOPPED
49
+ ./tests/test_context.py:12: assert app.lifecycle is app.context.lifecycle
50
+ ./tests/test_scope.py:1:from forgecore.services.scope import ServiceScope
51
+ ./tests/test_scope.py:4:def test_singleton_scope():
52
+ ./tests/test_scope.py:5: assert ServiceScope.SINGLETON.value == "singleton"
53
+ ./tests/test_scope.py:8:def test_transient_scope():
54
+ ./tests/test_scope.py:9: assert ServiceScope.TRANSIENT.value == "transient"
55
+ ./tests/test_descriptor.py:1:from forgecore.services import ServiceDescriptor, ServiceScope
56
+ ./tests/test_descriptor.py:16: assert descriptor.scope is ServiceScope.SINGLETON
57
+ ./tests/test_descriptor.py:20:def test_descriptor_custom_scope():
58
+ ./tests/test_descriptor.py:24: scope=ServiceScope.TRANSIENT,
59
+ ./tests/test_descriptor.py:27: assert descriptor.scope is ServiceScope.TRANSIENT
60
+ ./tests/test_service_descriptor_container.py:1:from forgecore.services import ServiceContainer, ServiceScope
61
+ ./tests/test_service_descriptor_container.py:8:def test_register_scope():
62
+ ./tests/test_service_descriptor_container.py:13: scope=ServiceScope.TRANSIENT,
63
+ ./tests/test_service_descriptor_container.py:18: assert descriptor.scope is ServiceScope.TRANSIENT
@@ -0,0 +1,54 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27.0"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "forge-core-di"
7
+ version = "0.2.0"
8
+ description = "Lightweight Dependency Injection and Application Runtime Core for Python."
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Akmal Maulana", email = "akmallmline@gmail.com" }
14
+ ]
15
+ keywords = [
16
+ "dependency-injection",
17
+ "di-container",
18
+ "framework",
19
+ "application-kernel",
20
+ "autowiring",
21
+ "lifecycle",
22
+ "plugin",
23
+ "python",
24
+ ]
25
+ classifiers = [
26
+ "Development Status :: 3 - Alpha",
27
+ "Intended Audience :: Developers",
28
+ "License :: OSI Approved :: MIT License",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3.12",
31
+ "Operating System :: OS Independent",
32
+ "Topic :: Software Development :: Libraries :: Application Frameworks",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/akmallmline/forgecore"
37
+ Repository = "https://github.com/akmallmline/forgecore"
38
+
39
+ [tool.hatch.build.targets.wheel]
40
+ packages = ["src/forgecore"]
41
+
42
+ [tool.pytest.ini_options]
43
+ testpaths = ["tests"]
44
+
45
+ [tool.ruff]
46
+ line-length = 88
47
+ target-version = "py312"
48
+
49
+ [tool.ruff.lint]
50
+ select = [
51
+ "E",
52
+ "F",
53
+ "I",
54
+ ]