python-neva 3.4.0__py3-none-any.whl → 3.5.1__py3-none-any.whl
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.
- neva/database/connection.py +41 -40
- neva/events/dispatcher.py +4 -5
- neva/support/facade/app.pyi +23 -1
- neva/support/facade/event.py +2 -2
- neva/support/facade/event.pyi +7 -2
- python_neva-3.5.1.dist-info/METADATA +106 -0
- {python_neva-3.4.0.dist-info → python_neva-3.5.1.dist-info}/RECORD +8 -8
- {python_neva-3.4.0.dist-info → python_neva-3.5.1.dist-info}/WHEEL +1 -1
- python_neva-3.4.0.dist-info/METADATA +0 -27
neva/database/connection.py
CHANGED
|
@@ -95,7 +95,7 @@ class ConnectionManager:
|
|
|
95
95
|
|
|
96
96
|
@asynccontextmanager
|
|
97
97
|
async def _scoped(self, tx: BoundTransaction) -> AsyncIterator[None]:
|
|
98
|
-
"""
|
|
98
|
+
"""Expose the transaction on the registry for the duration of the block.
|
|
99
99
|
|
|
100
100
|
Yields:
|
|
101
101
|
None
|
|
@@ -108,40 +108,37 @@ class ConnectionManager:
|
|
|
108
108
|
)
|
|
109
109
|
try:
|
|
110
110
|
yield
|
|
111
|
-
if tx.rollback_requested:
|
|
112
|
-
tx.state = TransactionState.ROLLED_BACK
|
|
113
|
-
if tx.is_root:
|
|
114
|
-
for result in await tx.execute_on_rollback_callbacks():
|
|
115
|
-
if result.is_err and self.logger is not None:
|
|
116
|
-
self.logger.error(
|
|
117
|
-
"rollback callback failed",
|
|
118
|
-
error=result.err().unwrap(),
|
|
119
|
-
connection=self.name,
|
|
120
|
-
)
|
|
121
|
-
else:
|
|
122
|
-
tx.state = TransactionState.COMMITTED
|
|
123
|
-
if tx.is_root:
|
|
124
|
-
for result in await tx.execute_on_commit_callbacks():
|
|
125
|
-
if result.is_err and self.logger is not None:
|
|
126
|
-
self.logger.error(
|
|
127
|
-
"commit callback failed",
|
|
128
|
-
error=result.err().unwrap(),
|
|
129
|
-
connection=self.name,
|
|
130
|
-
)
|
|
131
|
-
except BaseException:
|
|
132
|
-
tx.state = TransactionState.ROLLED_BACK
|
|
133
|
-
if tx.is_root:
|
|
134
|
-
for result in await tx.execute_on_rollback_callbacks():
|
|
135
|
-
if result.is_err and self.logger is not None:
|
|
136
|
-
self.logger.error(
|
|
137
|
-
"rollback callback failed",
|
|
138
|
-
error=result.err().unwrap(),
|
|
139
|
-
connection=self.name,
|
|
140
|
-
)
|
|
141
|
-
raise
|
|
142
111
|
finally:
|
|
143
112
|
_tx_registry.reset(token)
|
|
144
113
|
|
|
114
|
+
async def _settle(self, tx: BoundTransaction, *, committed: bool) -> None:
|
|
115
|
+
"""Mark the transaction settled and drain its callbacks.
|
|
116
|
+
|
|
117
|
+
Callers must have already committed or rolled back the underlying
|
|
118
|
+
session: callbacks observe a settled transaction, and the registry no
|
|
119
|
+
longer exposes it, so a callback touching the database opens its own
|
|
120
|
+
transaction rather than reusing the drained one.
|
|
121
|
+
"""
|
|
122
|
+
tx.state = (
|
|
123
|
+
TransactionState.COMMITTED if committed else TransactionState.ROLLED_BACK
|
|
124
|
+
)
|
|
125
|
+
if not tx.is_root:
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
results = (
|
|
129
|
+
await tx.execute_on_commit_callbacks()
|
|
130
|
+
if committed
|
|
131
|
+
else await tx.execute_on_rollback_callbacks()
|
|
132
|
+
)
|
|
133
|
+
label = "commit" if committed else "rollback"
|
|
134
|
+
for result in results:
|
|
135
|
+
if result.is_err and self.logger is not None:
|
|
136
|
+
self.logger.error(
|
|
137
|
+
f"{label} callback failed",
|
|
138
|
+
error=result.err().unwrap(),
|
|
139
|
+
connection=self.name,
|
|
140
|
+
)
|
|
141
|
+
|
|
145
142
|
@asynccontextmanager
|
|
146
143
|
async def begin(self) -> AsyncIterator[BoundTransaction]:
|
|
147
144
|
"""Open a new bound transaction with an active database session.
|
|
@@ -162,23 +159,27 @@ class ConnectionManager:
|
|
|
162
159
|
try:
|
|
163
160
|
async with self._scoped(tx):
|
|
164
161
|
yield tx
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
if tx.rollback_requested:
|
|
163
|
+
await sp.rollback()
|
|
164
|
+
else:
|
|
165
|
+
await sp.commit()
|
|
169
166
|
except BaseException:
|
|
170
167
|
await sp.rollback()
|
|
168
|
+
await self._settle(tx, committed=False)
|
|
171
169
|
raise
|
|
170
|
+
await self._settle(tx, committed=not tx.rollback_requested)
|
|
172
171
|
case _:
|
|
173
172
|
async with self.session_factory() as session:
|
|
174
173
|
tx = BoundTransaction(self.name, session)
|
|
175
174
|
try:
|
|
176
175
|
async with self._scoped(tx):
|
|
177
176
|
yield tx
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
if tx.rollback_requested:
|
|
178
|
+
await session.rollback()
|
|
179
|
+
else:
|
|
180
|
+
await session.commit()
|
|
182
181
|
except BaseException:
|
|
183
182
|
await session.rollback()
|
|
183
|
+
await self._settle(tx, committed=False)
|
|
184
184
|
raise
|
|
185
|
+
await self._settle(tx, committed=not tx.rollback_requested)
|
neva/events/dispatcher.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Base implementation of the event dispatcher."""
|
|
2
2
|
|
|
3
|
+
import inspect
|
|
3
4
|
from typing import override
|
|
4
5
|
|
|
5
6
|
from neva.arch.application import Application
|
|
@@ -35,11 +36,9 @@ class EventDispatcher(contracts.EventDispatcher):
|
|
|
35
36
|
event: The event about to be dispatched.
|
|
36
37
|
"""
|
|
37
38
|
for hook in self._before_dispatch_hooks:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
case contracts.SyncBeforeDispatchHook():
|
|
42
|
-
hook(event)
|
|
39
|
+
result = hook(event)
|
|
40
|
+
if inspect.isawaitable(result):
|
|
41
|
+
await result
|
|
43
42
|
|
|
44
43
|
@override
|
|
45
44
|
async def before_dispatch(self, hook: contracts.BeforeDispatchHook) -> None:
|
neva/support/facade/app.pyi
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
"""Type stub for App facade."""
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from contextlib import AbstractAsyncContextManager
|
|
4
|
+
from typing import Any, Self, override
|
|
4
5
|
|
|
5
6
|
from neva.arch import Facade
|
|
7
|
+
from neva.arch.scopes import BaseScope
|
|
6
8
|
from neva.support import Result
|
|
7
9
|
|
|
8
10
|
class App(Facade):
|
|
9
11
|
@classmethod
|
|
10
12
|
@override
|
|
11
13
|
def get_facade_accessor(cls) -> type: ...
|
|
14
|
+
@classmethod
|
|
15
|
+
async def make_async[T](cls, interface: type[T]) -> Result[T, str]:
|
|
16
|
+
"""Resolve and instanciate a type from the container.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
Result containing the resolved type instance or an error message.
|
|
20
|
+
"""
|
|
21
|
+
|
|
12
22
|
@classmethod
|
|
13
23
|
def make[T](cls, interface: type[T]) -> Result[T, str]:
|
|
14
24
|
"""Resolve an interface from the container by its alias.
|
|
@@ -23,3 +33,15 @@ class App(Facade):
|
|
|
23
33
|
Result containing the resolved service instance or an error message.
|
|
24
34
|
|
|
25
35
|
"""
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
async def scope(
|
|
39
|
+
cls,
|
|
40
|
+
scope: BaseScope | None = None,
|
|
41
|
+
context: dict[type, Any] | None = None,
|
|
42
|
+
) -> AbstractAsyncContextManager[Self]:
|
|
43
|
+
"""Enter a new scope.
|
|
44
|
+
|
|
45
|
+
Yields:
|
|
46
|
+
The application instance with the new scope.
|
|
47
|
+
"""
|
neva/support/facade/event.py
CHANGED
|
@@ -5,7 +5,7 @@ from contextlib import contextmanager
|
|
|
5
5
|
from typing import TYPE_CHECKING, override
|
|
6
6
|
|
|
7
7
|
from neva.arch import Facade
|
|
8
|
-
from neva.events import
|
|
8
|
+
from neva.events import contracts
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
@@ -23,7 +23,7 @@ class Event(Facade):
|
|
|
23
23
|
Returns:
|
|
24
24
|
EventDispatcher class.
|
|
25
25
|
"""
|
|
26
|
-
return EventDispatcher
|
|
26
|
+
return contracts.EventDispatcher
|
|
27
27
|
|
|
28
28
|
@classmethod
|
|
29
29
|
def fake(cls) -> "EventFake":
|
neva/support/facade/event.pyi
CHANGED
|
@@ -13,10 +13,15 @@ class Event(Facade):
|
|
|
13
13
|
@override
|
|
14
14
|
def get_facade_accessor(cls) -> type: ...
|
|
15
15
|
@classmethod
|
|
16
|
-
async def
|
|
16
|
+
async def before_dispatch(cls, hook: contracts.BeforeDispatchHook) -> None:
|
|
17
|
+
"""Register a hook to be called before listeners are invoked."""
|
|
18
|
+
@classmethod
|
|
19
|
+
async def dispatch(cls, event: contracts.Event) -> list[Result[None, str]]:
|
|
20
|
+
"""Dispatch an event to all registered listeners."""
|
|
17
21
|
@classmethod
|
|
18
22
|
def listen[T: contracts.Event](
|
|
19
23
|
cls,
|
|
20
24
|
event_cls: type[T],
|
|
21
25
|
listener_cls: type[contracts.EventListener[T]],
|
|
22
|
-
) -> None:
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Register a listener for an event."""
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: python-neva
|
|
3
|
+
Version: 3.5.1
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: aiosqlite>=0.20.0
|
|
7
|
+
Requires-Dist: asyncpg>=0.30.0
|
|
8
|
+
Requires-Dist: cryptography>=46.0.3
|
|
9
|
+
Requires-Dist: dishka>=1.10.0
|
|
10
|
+
Requires-Dist: fastapi[all]>=0.129.0
|
|
11
|
+
Requires-Dist: faststream>=0.6.6
|
|
12
|
+
Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.62b0
|
|
13
|
+
Requires-Dist: pwdlib[argon2,bcrypt]>=0.3.0
|
|
14
|
+
Requires-Dist: pyinstrument>=5.1.1
|
|
15
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.0
|
|
16
|
+
Requires-Dist: structlog>=25.5.0
|
|
17
|
+
Requires-Dist: typer>=0.21.1
|
|
18
|
+
Provides-Extra: fastapi
|
|
19
|
+
Requires-Dist: neva-fastapi>=1.0.0; extra == 'fastapi'
|
|
20
|
+
Provides-Extra: testing
|
|
21
|
+
Requires-Dist: pytest-asyncio>=0.25.3; extra == 'testing'
|
|
22
|
+
Requires-Dist: pytest>=9.0.2; extra == 'testing'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# python-neva
|
|
26
|
+
|
|
27
|
+
The core of the **Neva** framework — a Laravel-inspired toolkit for Python that
|
|
28
|
+
brings Laravel's philosophy, terminology, and conventions to the Python
|
|
29
|
+
ecosystem: service providers, facades, `bind`/`make` dependency injection (on
|
|
30
|
+
[dishka](https://github.com/reagento/dishka)), `Hash`/`Crypt`/`Config`/`Log`/`Event`
|
|
31
|
+
facades, a transaction-aware event system, and Result/Option error handling.
|
|
32
|
+
|
|
33
|
+
`python-neva` is the **framework-agnostic core**. Web- and protocol-specific
|
|
34
|
+
concerns live in separate integration packages (the plugins below) so the core
|
|
35
|
+
never depends on a particular HTTP or messaging framework.
|
|
36
|
+
|
|
37
|
+
## Plugins & ecosystem
|
|
38
|
+
|
|
39
|
+
Neva is split into one repository per package. The core is published as
|
|
40
|
+
[`python-neva`](https://pypi.org/project/python-neva/); each plugin is an
|
|
41
|
+
independent repo, independently versioned and published.
|
|
42
|
+
|
|
43
|
+
| Package | Repo / directory | Role | Status |
|
|
44
|
+
| ----------------- | ------------------ | ------------------------------------------------------------------------------------- | ------------------------------- |
|
|
45
|
+
| `python-neva` | `neva/` | **Core, framework-agnostic.** DI, service providers, facades, Result/Option, events, security, observability, SQLAlchemy database layer. | published ([PyPI](https://pypi.org/project/python-neva/)) |
|
|
46
|
+
| `neva-fastapi` | `neva-fastapi/` | FastAPI integration — `App` extends `FastAPI` and wires dishka into routes. Pulled in via the `python-neva[fastapi]` extra. | published ([PyPI](https://pypi.org/project/neva-fastapi/)) |
|
|
47
|
+
| `neva-faststream` | `neva-faststream/` | FastStream (messaging) integration. | scaffolded, early placeholder |
|
|
48
|
+
| `neva-auth` | `neva-auth/` | Authentication & identity toolkit — token-issuance engine, OAuth2 grants, guards, pluggable formats/backends. | core complete, OAuth-server slice in progress |
|
|
49
|
+
| `neva-example` | `neva-example/` | Reference application consuming `python-neva[fastapi]`. Not published; demonstration + integration test bed. | unpublished |
|
|
50
|
+
|
|
51
|
+
> When working across packages locally, each repo can be cloned as a sibling
|
|
52
|
+
> directory; integration packages depend on `python-neva` from PyPI (or an
|
|
53
|
+
> editable local path during development).
|
|
54
|
+
|
|
55
|
+
## Develop
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
uv sync # install/refresh deps from uv.lock
|
|
59
|
+
poe lint # ruff check
|
|
60
|
+
poe fmt # ruff format
|
|
61
|
+
poe tc # type-check (mypy)
|
|
62
|
+
poe test # pytest
|
|
63
|
+
poe test-cov # tests with coverage
|
|
64
|
+
|
|
65
|
+
# Run a single test
|
|
66
|
+
pytest tests/test_file.py::TestClass::test_method -v
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`asyncio_mode = "auto"` is set, so async tests need no `@pytest.mark.asyncio`.
|
|
70
|
+
|
|
71
|
+
## Contributing
|
|
72
|
+
|
|
73
|
+
**Commits** follow [Conventional Commits](https://www.conventionalcommits.org/)
|
|
74
|
+
with [gitmoji](https://gitmoji.dev/) prefixes, enforced by
|
|
75
|
+
[`cz_gitmoji`](https://github.com/ljnsn/cz-conventional-gitmoji). Commitizen is
|
|
76
|
+
provided as a dev dependency — no separate install needed. Run the guided
|
|
77
|
+
wizard:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
cz commit
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
or format manually as `:gitmoji: type(scope): subject`.
|
|
84
|
+
|
|
85
|
+
**Releases** are cut per-repo with commitizen, from the repo root:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
cz bump # bump version in pyproject, write CHANGELOG, tag v<version>
|
|
89
|
+
git push --follow-tags origin main
|
|
90
|
+
uv build && uv publish # build + publish the wheel/sdist
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`cz bump` derives the bump level (major/minor/patch) from the commits since the
|
|
94
|
+
last tag, updates `CHANGELOG.md`, and runs `scripts/retag-with-changelog.sh` to
|
|
95
|
+
rewrite the new tag with the rendered changelog as its annotation.
|
|
96
|
+
|
|
97
|
+
## Feature ideas
|
|
98
|
+
|
|
99
|
+
- Feature-parity FastStream integration (now scaffolded as `neva-faststream`)
|
|
100
|
+
- Finish cleaning up the core package (moving any remaining ASGI-dependent code into the appropriate integration packages)
|
|
101
|
+
- Improved router registration (auto-discovery OR provider-based? both?)
|
|
102
|
+
- Improved security tooling (performance improvements, better defaults, etc.)
|
|
103
|
+
- Better OpenTelemetry integration
|
|
104
|
+
- Improved factory module (based on Polyfactory)
|
|
105
|
+
- Queue/Jobs system
|
|
106
|
+
- CLI integration
|
|
@@ -15,13 +15,13 @@ neva/config/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
15
15
|
neva/config/repository.py,sha256=-6lG0LcAO30OoJ9vSS4U1xO2o8-EWhSib5_CVEiZkyk,4750
|
|
16
16
|
neva/database/__init__.py,sha256=3yYnEe8HQM86tURyAhTbMtE7AXubIEMN3GuwxkkT-bk,508
|
|
17
17
|
neva/database/config.py,sha256=bVKUqlrYDFrURqg_FbntPXyVkbOUPSVXQJTKjyucjL0,451
|
|
18
|
-
neva/database/connection.py,sha256=
|
|
18
|
+
neva/database/connection.py,sha256=zRN0AJHj2BTXC92EnE6UKSMOhlCbikCAT0W7yue11Qg,6211
|
|
19
19
|
neva/database/manager.py,sha256=VNvhVumZD2hoGKpkdXMAkT6KykE4H80WcG2DgShK5Hs,4240
|
|
20
20
|
neva/database/provider.py,sha256=l2be4Ri53RtQq1-qzohy3cqzJQpTaNzqXGVhXPKUCXc,1674
|
|
21
21
|
neva/database/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
neva/database/transaction.py,sha256=_0Dsao_vhCJT5YRUmrHOLb0uxvfdE-5k3n0yMPLC1o8,5167
|
|
23
23
|
neva/events/__init__.py,sha256=Gpi5q-pNlIi-q23U2ZOsNf8Y9rB6AQtsBbbBFU0tkFc,776
|
|
24
|
-
neva/events/dispatcher.py,sha256=
|
|
24
|
+
neva/events/dispatcher.py,sha256=KR5uDZbnNwrMCI6s9S_SoNrNHx2z2lugoHk1-g3fzXA,4288
|
|
25
25
|
neva/events/event.py,sha256=q-KyyxNkU3AN2YSaujuNPIoXQMXhGOwClTap5y8fU5I,282
|
|
26
26
|
neva/events/event_registry.py,sha256=IZnpR3oLyvt5K2pn9KMCBw5W4JP7Ok_zMKI2SgQoXVM,1945
|
|
27
27
|
neva/events/listener.py,sha256=2d5RHVKO0pU-eL_evLReTG0DIoX9tZyOcn8PWLeECZo,1435
|
|
@@ -73,15 +73,15 @@ neva/support/strconv.py,sha256=cvYRtJVG3IuhQzZCqJD1nVm3g0wxRu-IIIFK16Mq7d8,1296
|
|
|
73
73
|
neva/support/time.py,sha256=QYH1F38V33F1C-rlH1Xbrblnaue1-BnercFYUBMmq88,351
|
|
74
74
|
neva/support/facade/__init__.py,sha256=aysM4AyDAxAgv8uZCka49t2vLHeVraTNAHeCIpXLd-s,465
|
|
75
75
|
neva/support/facade/app.py,sha256=xdL9qpeQnJtAMomxfrImM82qM2YV2eQFsckmUNE2w7I,297
|
|
76
|
-
neva/support/facade/app.pyi,sha256=
|
|
76
|
+
neva/support/facade/app.pyi,sha256=gTAKp_r8DUqOj-oggAyAuK1WvR2AzX63-G2U5NixHbM,1304
|
|
77
77
|
neva/support/facade/config.py,sha256=cqmtwAekHE4qWH2LqzmY3BAbyAadvZYfPgLHyTcCnJE,358
|
|
78
78
|
neva/support/facade/config.pyi,sha256=LpI6xwqURRlWPcohXBxTL-iWTHq3MMMNdu670Q_5jnk,2549
|
|
79
79
|
neva/support/facade/crypt.py,sha256=BUx2woDla3TrvVOVRNzOg97zfCaXIOqIz5EdoN3BvlA,298
|
|
80
80
|
neva/support/facade/crypt.pyi,sha256=_MV_qXDATaCs1pZTOw_-qPx_jjH_nG4-tUBOMX4nZIE,857
|
|
81
81
|
neva/support/facade/db.py,sha256=mXMzuCKf390ICCBgzaub1ZoMqUBgOQByQYMEM3YnN_0,324
|
|
82
82
|
neva/support/facade/db.pyi,sha256=UQFMgBuw0BGquMnuUNULC8Pdo7lDCVTCNkDaUmIZJhw,1911
|
|
83
|
-
neva/support/facade/event.py,sha256=
|
|
84
|
-
neva/support/facade/event.pyi,sha256=
|
|
83
|
+
neva/support/facade/event.py,sha256=BkJoof1hYTxhMBOxLrq21NIgEPIiLBlj18Pttl0FHa8,1236
|
|
84
|
+
neva/support/facade/event.pyi,sha256=7R6osyTZbHt_zkCfQ-uZnTLfyZTeN1bi3exsgl3-36k,817
|
|
85
85
|
neva/support/facade/hash.py,sha256=tGhsvfGovt-mcRXSjDKf4jt1n7ib0eDPXFvRUfVxLUc,292
|
|
86
86
|
neva/support/facade/hash.pyi,sha256=jTs3E5ZF5cp76jrgH70DEog8gzfYIcIV2PrO9xskHyI,1656
|
|
87
87
|
neva/support/facade/log.py,sha256=_uLoHB9tkpHkiqEJXazbaqfiKUOtv3NS71ZCZAprzOI,347
|
|
@@ -91,6 +91,6 @@ neva/testing/fakes.py,sha256=w2dnFaO6x14l0_si7iBNELMCxaFi8VsVOSQ6PmTlclE,2936
|
|
|
91
91
|
neva/testing/fixtures.py,sha256=oiPa5ntUkW-SbySDvwEHXtti8NqSwI-R0CT1_ezTx_Y,1445
|
|
92
92
|
neva/testing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
93
93
|
neva/testing/test_case.py,sha256=zJBZJeKI-sv-EOaXNuSJ0V2Zp_6hdk64W4dOh0eP8RI,3290
|
|
94
|
-
python_neva-3.
|
|
95
|
-
python_neva-3.
|
|
96
|
-
python_neva-3.
|
|
94
|
+
python_neva-3.5.1.dist-info/METADATA,sha256=g3oinewGocjJnVZ2LztQQMtNLOCEJcsOwjDw-F6_o50,5026
|
|
95
|
+
python_neva-3.5.1.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
96
|
+
python_neva-3.5.1.dist-info/RECORD,,
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: python-neva
|
|
3
|
-
Version: 3.4.0
|
|
4
|
-
Summary: Add your description here
|
|
5
|
-
Requires-Python: >=3.12
|
|
6
|
-
Requires-Dist: aiosqlite>=0.20.0
|
|
7
|
-
Requires-Dist: asyncpg>=0.30.0
|
|
8
|
-
Requires-Dist: cryptography>=46.0.3
|
|
9
|
-
Requires-Dist: dishka>=1.10.0
|
|
10
|
-
Requires-Dist: fastapi[all]>=0.129.0
|
|
11
|
-
Requires-Dist: faststream>=0.6.6
|
|
12
|
-
Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.62b0
|
|
13
|
-
Requires-Dist: pwdlib[argon2,bcrypt]>=0.3.0
|
|
14
|
-
Requires-Dist: pyinstrument>=5.1.1
|
|
15
|
-
Requires-Dist: sqlalchemy[asyncio]>=2.0.0
|
|
16
|
-
Requires-Dist: structlog>=25.5.0
|
|
17
|
-
Requires-Dist: typer>=0.21.1
|
|
18
|
-
Provides-Extra: fastapi
|
|
19
|
-
Requires-Dist: neva-fastapi>=1.0.0; extra == 'fastapi'
|
|
20
|
-
Provides-Extra: testing
|
|
21
|
-
Requires-Dist: pytest-asyncio>=0.25.3; extra == 'testing'
|
|
22
|
-
Requires-Dist: pytest>=9.0.2; extra == 'testing'
|
|
23
|
-
Description-Content-Type: text/markdown
|
|
24
|
-
|
|
25
|
-
# The Neva framework
|
|
26
|
-
|
|
27
|
-
PLACEHOLDER
|