python-neva 3.3.0__tar.gz → 3.4.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.
- python_neva-3.4.0/CHANGELOG.md +20 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/PKG-INFO +1 -1
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/arch/service_provider.py +4 -0
- python_neva-3.4.0/neva/events/contracts/__init__.py +20 -0
- python_neva-3.4.0/neva/events/contracts/dispatcher.py +47 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/events/dispatcher.py +6 -18
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/event.pyi +4 -5
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/testing/fakes.py +17 -9
- {python_neva-3.3.0 → python_neva-3.4.0}/pyproject.toml +1 -1
- python_neva-3.4.0/tests/arch/test_context.py +60 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/arch/test_extends.py +0 -1
- {python_neva-3.3.0 → python_neva-3.4.0}/uv.lock +1 -1
- python_neva-3.3.0/CHANGELOG.md +0 -115
- python_neva-3.3.0/neva/events/contracts/__init__.py +0 -7
- python_neva-3.3.0/neva/events/contracts/dispatcher.py +0 -24
- {python_neva-3.3.0 → python_neva-3.4.0}/.envrc +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/.gitignore +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/.pre-commit-config.yaml +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/.python-version +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/README.md +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/arch/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/arch/application.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/arch/config.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/arch/facade.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/arch/integrations/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/arch/integrations/faststream.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/arch/markers.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/arch/py.typed +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/arch/scopes.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/config/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/config/base_providers.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/config/loader.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/config/py.typed +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/config/repository.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/database/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/database/config.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/database/connection.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/database/manager.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/database/provider.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/database/py.typed +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/database/transaction.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/events/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/events/contracts/event.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/events/contracts/handler.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/events/contracts/listener.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/events/event.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/events/event_registry.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/events/listener.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/events/policy.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/events/provider.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/events/py.typed +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/obs/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/obs/instrumentation/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/obs/instrumentation/sqlalchemy.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/obs/logging/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/obs/logging/manager.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/obs/logging/provider.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/obs/middleware/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/obs/middleware/correlation.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/obs/middleware/profiler.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/obs/py.typed +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/polyfactory/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/polyfactory/factories.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/polyfactory/persistence.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/polyfactory/py.typed +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/encryption/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/encryption/encrypter.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/encryption/protocol.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/hashing/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/hashing/config.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/hashing/hash_manager.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/hashing/hashers/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/hashing/hashers/argon2.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/hashing/hashers/bcrypt.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/hashing/hashers/protocol.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/provider.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/py.typed +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/tokens/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/tokens/generate_token.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/tokens/hash_token.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/security/tokens/verify_token.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/accessors.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/app.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/app.pyi +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/config.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/config.pyi +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/crypt.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/crypt.pyi +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/db.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/db.pyi +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/event.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/hash.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/hash.pyi +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/log.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/facade/log.pyi +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/py.typed +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/results.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/strategy.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/strconv.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/support/time.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/testing/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/testing/fixtures.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/testing/py.typed +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/neva/testing/test_case.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/ruff.toml +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/scripts/retag-with-changelog.sh +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/arch/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/arch/test_cache.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/arch/test_scope.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/config/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/config/test_loader.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/config/test_repository.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/conftest.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/database/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/database/test_connection_manager.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/database/test_database_manager.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/database/test_edge_cases.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/database/test_multi_connection.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/database/test_sqlalchemy_integration.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/database/test_transaction.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/database/test_transaction_context.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/database/test_transaction_registry.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/events/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/events/conftest.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/events/test_binding.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/events/test_deferred.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/events/test_dispatch.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/events/test_event.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/events/test_function_listener.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/events/test_immediate.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/events/test_listen_on_parent_class.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/obs/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/obs/test_correlation.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/obs/test_profiler.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/security/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/security/test_encrypter.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/security/test_hash_manager.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/testing/__init__.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/testing/test_event_fake.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/testing/test_facade_restore.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/testing/test_fixtures.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/testing/test_refresh_database.py +0 -0
- {python_neva-3.3.0 → python_neva-3.4.0}/tests/testing/test_test_case.py +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## 3.4.0 (2026-06-10)
|
|
2
|
+
|
|
3
|
+
### ✨ Features
|
|
4
|
+
|
|
5
|
+
- **arch**: new from_context method
|
|
6
|
+
- **tooling**: placeholder commit
|
|
7
|
+
|
|
8
|
+
### 💚👷 CI & Build
|
|
9
|
+
|
|
10
|
+
- **tooling**: default to base tag version for commitizen
|
|
11
|
+
|
|
12
|
+
### 📝💡 Documentation
|
|
13
|
+
|
|
14
|
+
- **project**: update doc
|
|
15
|
+
- **core**: placeholde readme
|
|
16
|
+
|
|
17
|
+
### 🔧🔨📦️ Configuration, Scripts, Packages
|
|
18
|
+
|
|
19
|
+
- **tooling**: update changelog script
|
|
20
|
+
- **project**: update versioning config
|
|
@@ -175,6 +175,10 @@ class ServiceProvider(abc.ABC):
|
|
|
175
175
|
_ = self.provider.decorate(source, provides=interface, scope=scope, when=when)
|
|
176
176
|
return self
|
|
177
177
|
|
|
178
|
+
def from_context(self, interface: type, scope: Scope | None = None) -> None:
|
|
179
|
+
"""Declares an interface as provided by the current context."""
|
|
180
|
+
_ = self.provider.from_context(provides=interface, scope=scope)
|
|
181
|
+
|
|
178
182
|
@abc.abstractmethod
|
|
179
183
|
def register(self) -> Result[Self, str]:
|
|
180
184
|
"""Register services into the application container.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from neva.events.contracts.dispatcher import (
|
|
2
|
+
AsyncBeforeDispatchHook,
|
|
3
|
+
BeforeDispatchHook,
|
|
4
|
+
EventDispatcher,
|
|
5
|
+
SyncBeforeDispatchHook,
|
|
6
|
+
)
|
|
7
|
+
from neva.events.contracts.event import Event
|
|
8
|
+
from neva.events.contracts.handler import EventHandler
|
|
9
|
+
from neva.events.contracts.listener import EventListener
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"AsyncBeforeDispatchHook",
|
|
14
|
+
"BeforeDispatchHook",
|
|
15
|
+
"Event",
|
|
16
|
+
"EventDispatcher",
|
|
17
|
+
"EventHandler",
|
|
18
|
+
"EventListener",
|
|
19
|
+
"SyncBeforeDispatchHook",
|
|
20
|
+
]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from typing import Protocol, runtime_checkable
|
|
2
|
+
|
|
3
|
+
from neva.events.contracts.event import Event
|
|
4
|
+
from neva.events.contracts.listener import EventListener
|
|
5
|
+
from neva.support import Result
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@runtime_checkable
|
|
9
|
+
class AsyncBeforeDispatchHook(Protocol):
|
|
10
|
+
"""Asynchronous hook to be called before listeners are invoked."""
|
|
11
|
+
|
|
12
|
+
async def __call__(self, context: Event) -> None:
|
|
13
|
+
"""Execute the hook."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@runtime_checkable
|
|
17
|
+
class SyncBeforeDispatchHook(Protocol):
|
|
18
|
+
"""Synchronous hook to be called before listeners are invoked."""
|
|
19
|
+
|
|
20
|
+
def __call__(self, context: Event) -> None:
|
|
21
|
+
"""Execute the hook."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
BeforeDispatchHook = AsyncBeforeDispatchHook | SyncBeforeDispatchHook
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class EventDispatcher(Protocol):
|
|
28
|
+
"""Event dispatcher protocol."""
|
|
29
|
+
|
|
30
|
+
async def dispatch(
|
|
31
|
+
self,
|
|
32
|
+
event: Event,
|
|
33
|
+
) -> list[Result[None, str]]:
|
|
34
|
+
"""Dispatch an event to all registered listeners."""
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
async def before_dispatch(self, hook: BeforeDispatchHook) -> None:
|
|
38
|
+
"""Register a hook to be called before listeners are invoked."""
|
|
39
|
+
...
|
|
40
|
+
|
|
41
|
+
def listen[T: Event](
|
|
42
|
+
self,
|
|
43
|
+
event_cls: type[T],
|
|
44
|
+
listener_cls: type[EventListener[T]],
|
|
45
|
+
) -> None:
|
|
46
|
+
"""Register a listener for an event."""
|
|
47
|
+
...
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Base implementation of the event dispatcher."""
|
|
2
2
|
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import override
|
|
4
4
|
|
|
5
5
|
from neva.arch.application import Application
|
|
6
6
|
from neva.database.manager import DatabaseManager
|
|
@@ -10,19 +10,6 @@ from neva.events.event_registry import EventRegistry
|
|
|
10
10
|
from neva.support import Err, Nothing, Result, Some
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
@runtime_checkable
|
|
14
|
-
class AsyncBeforeDispatchHook(Protocol):
|
|
15
|
-
async def __call__(self, context: contracts.Event) -> None: ...
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@runtime_checkable
|
|
19
|
-
class SyncBeforeDispatchHook(Protocol):
|
|
20
|
-
def __call__(self, context: contracts.Event) -> None: ...
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
BeforeDispatchHook = AsyncBeforeDispatchHook | SyncBeforeDispatchHook
|
|
24
|
-
|
|
25
|
-
|
|
26
13
|
class EventDispatcher(contracts.EventDispatcher):
|
|
27
14
|
"""Event dispatcher implementation."""
|
|
28
15
|
|
|
@@ -35,7 +22,7 @@ class EventDispatcher(contracts.EventDispatcher):
|
|
|
35
22
|
self._registry: EventRegistry = registry
|
|
36
23
|
self._app: Application = app
|
|
37
24
|
self._db: DatabaseManager = db
|
|
38
|
-
self._before_dispatch_hooks: list[BeforeDispatchHook] = []
|
|
25
|
+
self._before_dispatch_hooks: list[contracts.BeforeDispatchHook] = []
|
|
39
26
|
|
|
40
27
|
async def _apply_before_dispatch(self, event: contracts.Event) -> None:
|
|
41
28
|
"""Extension hook called before listeners are invoked.
|
|
@@ -49,12 +36,13 @@ class EventDispatcher(contracts.EventDispatcher):
|
|
|
49
36
|
"""
|
|
50
37
|
for hook in self._before_dispatch_hooks:
|
|
51
38
|
match hook:
|
|
52
|
-
case AsyncBeforeDispatchHook():
|
|
39
|
+
case contracts.AsyncBeforeDispatchHook():
|
|
53
40
|
await hook(event)
|
|
54
|
-
case SyncBeforeDispatchHook():
|
|
41
|
+
case contracts.SyncBeforeDispatchHook():
|
|
55
42
|
hook(event)
|
|
56
43
|
|
|
57
|
-
|
|
44
|
+
@override
|
|
45
|
+
async def before_dispatch(self, hook: contracts.BeforeDispatchHook) -> None:
|
|
58
46
|
"""Register a hook to be called before listeners are invoked."""
|
|
59
47
|
self._before_dispatch_hooks.append(hook)
|
|
60
48
|
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import override
|
|
4
4
|
|
|
5
|
-
from neva import events
|
|
6
5
|
from neva.arch import Facade
|
|
7
|
-
from neva.events import
|
|
6
|
+
from neva.events import contracts
|
|
8
7
|
from neva.support import Result
|
|
9
8
|
|
|
10
9
|
class Event(Facade):
|
|
@@ -14,10 +13,10 @@ class Event(Facade):
|
|
|
14
13
|
@override
|
|
15
14
|
def get_facade_accessor(cls) -> type: ...
|
|
16
15
|
@classmethod
|
|
17
|
-
async def dispatch(cls, event:
|
|
16
|
+
async def dispatch(cls, event: contracts.Event) -> list[Result[None, str]]: ...
|
|
18
17
|
@classmethod
|
|
19
|
-
def listen[T:
|
|
18
|
+
def listen[T: contracts.Event](
|
|
20
19
|
cls,
|
|
21
20
|
event_cls: type[T],
|
|
22
|
-
listener_cls: type[EventListener[T]],
|
|
21
|
+
listener_cls: type[contracts.EventListener[T]],
|
|
23
22
|
) -> None: ...
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
"""Testing fakes for Neva facades."""
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import override
|
|
5
5
|
|
|
6
|
-
from neva.events
|
|
6
|
+
from neva.events import contracts
|
|
7
7
|
from neva.support import Result
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class EventFake:
|
|
10
|
+
class EventFake(contracts.EventDispatcher):
|
|
11
11
|
"""Recording fake for the Event facade. No listeners are dispatched."""
|
|
12
12
|
|
|
13
13
|
def __init__(self) -> None:
|
|
14
|
-
self._dispatched: list[
|
|
14
|
+
self._dispatched: list[contracts.Event] = []
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
@override
|
|
17
|
+
async def dispatch(self, event: contracts.Event) -> list[Result[None, str]]:
|
|
17
18
|
"""Record the event without invoking any listeners.
|
|
18
19
|
|
|
19
20
|
Returns:
|
|
@@ -22,10 +23,17 @@ class EventFake:
|
|
|
22
23
|
self._dispatched.append(event)
|
|
23
24
|
return []
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
@override
|
|
27
|
+
def listen[T: contracts.Event](
|
|
28
|
+
self, event_cls: type[T], listener_cls: type[contracts.EventListener[T]]
|
|
29
|
+
) -> None:
|
|
26
30
|
"""No-op."""
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
@override
|
|
33
|
+
async def before_dispatch(self, hook: contracts.BeforeDispatchHook) -> None:
|
|
34
|
+
"""Register a hook to be called before listeners are invoked."""
|
|
35
|
+
|
|
36
|
+
def dispatched[E: contracts.Event](self, event_cls: type[E]) -> list[E]:
|
|
29
37
|
"""Return all recorded events of the given type.
|
|
30
38
|
|
|
31
39
|
Returns:
|
|
@@ -33,7 +41,7 @@ class EventFake:
|
|
|
33
41
|
"""
|
|
34
42
|
return [e for e in self._dispatched if isinstance(e, event_cls)]
|
|
35
43
|
|
|
36
|
-
def assert_dispatched[E:
|
|
44
|
+
def assert_dispatched[E: contracts.Event](
|
|
37
45
|
self,
|
|
38
46
|
event_cls: type[E],
|
|
39
47
|
*,
|
|
@@ -61,7 +69,7 @@ class EventFake:
|
|
|
61
69
|
if match is not None and not any(match(e) for e in matching):
|
|
62
70
|
raise AssertionError(f"No {event_cls.__name__} matched the predicate")
|
|
63
71
|
|
|
64
|
-
def assert_not_dispatched[E:
|
|
72
|
+
def assert_not_dispatched[E: contracts.Event](self, event_cls: type[E]) -> None:
|
|
65
73
|
"""Assert that no event of the given type was dispatched.
|
|
66
74
|
|
|
67
75
|
Args:
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Self, override
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from neva import arch
|
|
6
|
+
from neva.arch.scopes import Scope
|
|
7
|
+
from neva.support import Ok, Result
|
|
8
|
+
from neva.support.facade import Log
|
|
9
|
+
from neva.testing import TestCase
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RequestService:
|
|
13
|
+
"""A service scoped to REQUEST."""
|
|
14
|
+
|
|
15
|
+
def __init__(self) -> None:
|
|
16
|
+
self.value: int = id(self)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class RequestScopedProvider(arch.ServiceProvider):
|
|
20
|
+
"""Registers a REQUEST-scoped service."""
|
|
21
|
+
|
|
22
|
+
@override
|
|
23
|
+
def register(self) -> Result[Self, str]:
|
|
24
|
+
self.from_context(RequestService, scope=Scope.REQUEST)
|
|
25
|
+
return Ok(self)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _make_config_dir(tmp_path: Path) -> Path:
|
|
29
|
+
config_dir = tmp_path / "config"
|
|
30
|
+
config_dir.mkdir()
|
|
31
|
+
|
|
32
|
+
_ = (config_dir / "app.py").write_text(
|
|
33
|
+
'config = {"name": "TestApp", "debug": True}'
|
|
34
|
+
)
|
|
35
|
+
_ = (config_dir / "providers.py").write_text(
|
|
36
|
+
"""
|
|
37
|
+
from tests.arch.test_context import RequestScopedProvider
|
|
38
|
+
|
|
39
|
+
config = {"providers": [RequestScopedProvider]}
|
|
40
|
+
"""
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
return config_dir
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class TestScopeEntersChildScope(TestCase):
|
|
47
|
+
@override
|
|
48
|
+
def create_config(self, tmp_path: Path) -> Path:
|
|
49
|
+
return _make_config_dir(tmp_path)
|
|
50
|
+
|
|
51
|
+
async def test_request_scoped_service_resolved_in_scope(self) -> None:
|
|
52
|
+
test_service = RequestService()
|
|
53
|
+
async with self.app.scope(
|
|
54
|
+
scope=Scope.REQUEST,
|
|
55
|
+
context={RequestService: test_service},
|
|
56
|
+
):
|
|
57
|
+
new_service_result = self.app.make(RequestService)
|
|
58
|
+
new_service = new_service_result.unwrap()
|
|
59
|
+
|
|
60
|
+
assert new_service.value == test_service.value
|
python_neva-3.3.0/CHANGELOG.md
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
## 3.3.0 (2026-06-05)
|
|
2
|
-
|
|
3
|
-
### ✨ Features
|
|
4
|
-
|
|
5
|
-
- **tooling**: placeholder commit
|
|
6
|
-
|
|
7
|
-
### 💚👷 CI & Build
|
|
8
|
-
|
|
9
|
-
- **tooling**: default to base tag version for commitizen
|
|
10
|
-
|
|
11
|
-
### 📝💡 Documentation
|
|
12
|
-
|
|
13
|
-
- **project**: update doc
|
|
14
|
-
- **core**: placeholde readme
|
|
15
|
-
|
|
16
|
-
### 🔧🔨📦️ Configuration, Scripts, Packages
|
|
17
|
-
|
|
18
|
-
- **tooling**: update changelog script
|
|
19
|
-
- **project**: update versioning config
|
|
20
|
-
|
|
21
|
-
## 3.2.0 (2026-06-05)
|
|
22
|
-
|
|
23
|
-
### ✨ Features
|
|
24
|
-
|
|
25
|
-
- **tooling**: placeholder commit
|
|
26
|
-
|
|
27
|
-
### 🔧🔨📦️ Configuration, Scripts, Packages
|
|
28
|
-
|
|
29
|
-
- **tooling**: update changelog script
|
|
30
|
-
- **project**: update versioning config
|
|
31
|
-
|
|
32
|
-
### 📝💡 Documentation
|
|
33
|
-
|
|
34
|
-
- **core**: placeholde readme
|
|
35
|
-
|
|
36
|
-
## 3.1.1 (2026-05-11)
|
|
37
|
-
|
|
38
|
-
### 📌➕⬇️➖⬆️ Dependencies
|
|
39
|
-
|
|
40
|
-
- bump opt dep on neva-fastapi
|
|
41
|
-
|
|
42
|
-
## 3.1.0 (2026-05-11)
|
|
43
|
-
|
|
44
|
-
### ✨ Features
|
|
45
|
-
|
|
46
|
-
- fixing db facade
|
|
47
|
-
- Add eq method to Some / Ok
|
|
48
|
-
- Deprecate register_engine, add register_connection
|
|
49
|
-
- RefreshDatabase now properly use the testcase inner app
|
|
50
|
-
- Add neva-fastapi as optional dependency
|
|
51
|
-
- renaming of make / make_async for retrocompatibility
|
|
52
|
-
|
|
53
|
-
### 🐛🚑️ Fixes
|
|
54
|
-
|
|
55
|
-
- Fix provider registration ordering
|
|
56
|
-
|
|
57
|
-
### ♻️ Refactorings
|
|
58
|
-
|
|
59
|
-
- refactor of results / db toolkit
|
|
60
|
-
|
|
61
|
-
## 3.1.0a1 (2026-05-05)
|
|
62
|
-
|
|
63
|
-
### build
|
|
64
|
-
|
|
65
|
-
- add commitizen + versioningit
|
|
66
|
-
|
|
67
|
-
### 💚👷 CI & Build
|
|
68
|
-
|
|
69
|
-
- update perms on tag script
|
|
70
|
-
- tweaking cz tags
|
|
71
|
-
- remove auto-annotated tags
|
|
72
|
-
- configure versioningit + cz
|
|
73
|
-
- Fix cz config >>> ⏰ 1
|
|
74
|
-
- add and configure cz_gitmoji >>> ⏰ 5m
|
|
75
|
-
|
|
76
|
-
### 📝💡 Documentation
|
|
77
|
-
|
|
78
|
-
- clear changelog
|
|
79
|
-
|
|
80
|
-
### 🔧🔨📦️ Configuration, Scripts, Packages
|
|
81
|
-
|
|
82
|
-
- improve auto-annotation of tags
|
|
83
|
-
- Fix tagging script
|
|
84
|
-
|
|
85
|
-
## python-neva-v3.2.0 (2026-06-04)
|
|
86
|
-
|
|
87
|
-
### ✨ Features
|
|
88
|
-
|
|
89
|
-
- **core**: add optional activator on all binding functions
|
|
90
|
-
- **core**: remove scoping option from scoped, default to request scope
|
|
91
|
-
- **core**: introduce conditional activation
|
|
92
|
-
- **core**: add specifying interface in extends method
|
|
93
|
-
- **core**: add extends feature
|
|
94
|
-
|
|
95
|
-
### build
|
|
96
|
-
|
|
97
|
-
- **core**: remove redundant .envrc files
|
|
98
|
-
- **core**: fixing version derivation
|
|
99
|
-
|
|
100
|
-
### docs
|
|
101
|
-
|
|
102
|
-
- **core,-fastapi**: add contributing documentation
|
|
103
|
-
|
|
104
|
-
### feat
|
|
105
|
-
|
|
106
|
-
- **core**: allow passing context data to scope method
|
|
107
|
-
- **core**: add some utility functions for binding
|
|
108
|
-
- **core**: add some utility functions for binding
|
|
109
|
-
- **core**: add the possibility to turn off dependency caching
|
|
110
|
-
- **core,-fastapi**: add .envrc file
|
|
111
|
-
|
|
112
|
-
### refactor
|
|
113
|
-
|
|
114
|
-
- **core**: cleaning up type hints
|
|
115
|
-
- **core**: update type hints on main application
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
from neva.events.contracts.dispatcher import EventDispatcher
|
|
2
|
-
from neva.events.contracts.event import Event
|
|
3
|
-
from neva.events.contracts.handler import EventHandler
|
|
4
|
-
from neva.events.contracts.listener import EventListener
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
__all__ = ["Event", "EventDispatcher", "EventHandler", "EventListener"]
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
from typing import Protocol
|
|
2
|
-
|
|
3
|
-
from neva.events.contracts.event import Event
|
|
4
|
-
from neva.events.contracts.listener import EventListener
|
|
5
|
-
from neva.support import Result
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class EventDispatcher(Protocol):
|
|
9
|
-
"""Event dispatcher protocol."""
|
|
10
|
-
|
|
11
|
-
async def dispatch(
|
|
12
|
-
self,
|
|
13
|
-
event: Event,
|
|
14
|
-
) -> list[Result[None, str]]:
|
|
15
|
-
"""Dispatch an event to all registered listeners."""
|
|
16
|
-
...
|
|
17
|
-
|
|
18
|
-
def listen[T: Event](
|
|
19
|
-
self,
|
|
20
|
-
event_cls: type[T],
|
|
21
|
-
listener_cls: type[EventListener[T]],
|
|
22
|
-
) -> None:
|
|
23
|
-
"""Register a listener for an event."""
|
|
24
|
-
...
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|