nene2-python 1.0.0__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.
@@ -0,0 +1,211 @@
1
+ Metadata-Version: 2.4
2
+ Name: nene2-python
3
+ Version: 1.0.0
4
+ Summary: NENE2 Python — minimal API framework following NENE2's design philosophy
5
+ Project-URL: Homepage, https://github.com/hideyukiMORI/nene2-python
6
+ Project-URL: Repository, https://github.com/hideyukiMORI/nene2-python
7
+ Project-URL: Documentation, https://github.com/hideyukiMORI/nene2-python/tree/main/docs
8
+ Project-URL: Bug Tracker, https://github.com/hideyukiMORI/nene2-python/issues
9
+ Author-email: hideyukiMORI <info.xion.cc@gmail.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: api,clean-architecture,fastapi,framework,mcp,pydantic,sqlalchemy
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Framework :: FastAPI
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
22
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.12
25
+ Requires-Dist: alembic>=1.18.4
26
+ Requires-Dist: fastapi>=0.115
27
+ Requires-Dist: httpx>=0.27
28
+ Requires-Dist: mcp>=1.0
29
+ Requires-Dist: pydantic-settings>=2.6
30
+ Requires-Dist: pydantic>=2.9
31
+ Requires-Dist: python-multipart>=0.0.12
32
+ Requires-Dist: pyyaml>=6.0
33
+ Requires-Dist: sqlalchemy>=2.0.49
34
+ Requires-Dist: structlog>=24.0
35
+ Requires-Dist: uvicorn[standard]>=0.32
36
+ Provides-Extra: dev
37
+ Requires-Dist: httpx>=0.27; extra == 'dev'
38
+ Requires-Dist: mypy>=1.13; extra == 'dev'
39
+ Requires-Dist: pip-audit>=2.7; extra == 'dev'
40
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
41
+ Requires-Dist: pytest-cov>=6.0; extra == 'dev'
42
+ Requires-Dist: pytest>=8.3; extra == 'dev'
43
+ Requires-Dist: ruff>=0.9; extra == 'dev'
44
+ Description-Content-Type: text/markdown
45
+
46
+ # nene2-python
47
+
48
+ A Python reference framework implementing the [NENE2](https://github.com/hideyukiMORI/NENE2) design philosophy — clean architecture, security-first, and AI-readable code.
49
+
50
+ [![CI](https://github.com/hideyukiMORI/nene2-python/actions/workflows/ci.yml/badge.svg)](https://github.com/hideyukiMORI/nene2-python/actions/workflows/ci.yml)
51
+ [![Python](https://img.shields.io/badge/python-3.12%2B-blue)](https://www.python.org/)
52
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
53
+
54
+ ---
55
+
56
+ ## Features
57
+
58
+ - **FastAPI + Pydantic v2** — modern Python API stack with automatic OpenAPI docs
59
+ - **Clean Architecture** — UseCase / Domain layer fully decoupled from HTTP and DB
60
+ - **`mypy --strict`** — equivalent to PHPStan level 8 type safety
61
+ - **ruff** — lint and format in one tool (replaces flake8, isort, black, bandit)
62
+ - **RFC 9457 Problem Details** — uniform error responses across all endpoints
63
+ - **Bearer Token / API Key auth** — zero-config `LocalTokenVerifier`
64
+ - **MCP support** — expose UseCases as AI agent tools via `LocalMcpServer`
65
+ - **SQLAlchemy Core** — parameterised SQL without ORM overhead
66
+ - **Security middleware** — CSP, X-Frame-Options, rate limiting, request size limit, CORS
67
+ - **structlog** — structured JSON logging with request ID correlation
68
+
69
+ ---
70
+
71
+ ## Installation
72
+
73
+ ```bash
74
+ pip install nene2-python
75
+ # or
76
+ uv add nene2-python
77
+ ```
78
+
79
+ Requires Python 3.12+.
80
+
81
+ ---
82
+
83
+ ## Quick Start
84
+
85
+ ```python
86
+ from fastapi import FastAPI
87
+ from nene2.config import AppSettings
88
+ from nene2.middleware import (
89
+ ErrorHandlerMiddleware,
90
+ RequestIdMiddleware,
91
+ SecurityHeadersMiddleware,
92
+ ThrottleMiddleware,
93
+ )
94
+
95
+ cfg = AppSettings()
96
+ app = FastAPI()
97
+
98
+ app.add_middleware(ErrorHandlerMiddleware, debug=cfg.app_debug)
99
+ app.add_middleware(SecurityHeadersMiddleware)
100
+ app.add_middleware(RequestIdMiddleware)
101
+ app.add_middleware(ThrottleMiddleware, limit=cfg.throttle_limit, window=cfg.throttle_window)
102
+ ```
103
+
104
+ ### Define a domain
105
+
106
+ ```python
107
+ from dataclasses import dataclass
108
+ from abc import ABC, abstractmethod
109
+
110
+ @dataclass(frozen=True, slots=True)
111
+ class Note:
112
+ id: int
113
+ title: str
114
+ body: str
115
+
116
+ class NoteRepositoryInterface(ABC):
117
+ @abstractmethod
118
+ def find_by_id(self, note_id: int) -> Note | None: ...
119
+
120
+ @dataclass(frozen=True, slots=True)
121
+ class GetNoteInput:
122
+ note_id: int
123
+
124
+ class GetNoteUseCase:
125
+ def __init__(self, repository: NoteRepositoryInterface) -> None:
126
+ self._repository = repository
127
+
128
+ def execute(self, input_: GetNoteInput) -> Note:
129
+ note = self._repository.find_by_id(input_.note_id)
130
+ if note is None:
131
+ raise NoteNotFoundException(input_.note_id)
132
+ return note
133
+ ```
134
+
135
+ ### Wire to HTTP
136
+
137
+ ```python
138
+ from fastapi import APIRouter
139
+ from fastapi.responses import JSONResponse
140
+ from nene2.http import problem_details_response
141
+
142
+ router = APIRouter(prefix="/notes", tags=["notes"])
143
+
144
+ @router.get("/{note_id}")
145
+ async def get_note(note_id: int) -> JSONResponse:
146
+ note = get_use_case.execute(GetNoteInput(note_id))
147
+ return JSONResponse({"id": note.id, "title": note.title, "body": note.body})
148
+ ```
149
+
150
+ See the full working example in [`src/example/`](src/example/).
151
+
152
+ ---
153
+
154
+ ## Development Commands
155
+
156
+ ```bash
157
+ uv sync # install dependencies
158
+ uv run pytest # run tests (coverage enforced at 80%)
159
+ uv run mypy src/ # type check
160
+ uv run ruff check src/ tests/ # lint
161
+ uv run ruff format src/ tests/ # format
162
+ uv run uvicorn src.example.app:app --reload --port 8080 # dev server
163
+ ```
164
+
165
+ Full CI check (equivalent to GitHub Actions):
166
+
167
+ ```bash
168
+ uv run pytest && \
169
+ uv run mypy src/ && \
170
+ uv run ruff check src/ tests/ && \
171
+ uv run ruff format --check src/ tests/ && \
172
+ uv run pip-audit
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Framework Modules
178
+
179
+ | Module | Purpose |
180
+ |---|---|
181
+ | `nene2.http` | `PaginationQueryParser`, `PaginationResponse`, `problem_details_response()` |
182
+ | `nene2.middleware` | `ErrorHandlerMiddleware`, `SecurityHeadersMiddleware`, `RequestIdMiddleware`, `RequestLoggingMiddleware`, `RequestSizeLimitMiddleware`, `ThrottleMiddleware` |
183
+ | `nene2.auth` | `BearerTokenMiddleware`, `ApiKeyAuthMiddleware`, `LocalTokenVerifier`, `TokenVerifierProtocol` |
184
+ | `nene2.database` | `SqlAlchemyQueryExecutor`, `SqlAlchemyTransactionManager`, `DatabaseHealthCheck` |
185
+ | `nene2.config` | `AppSettings` (pydantic-settings, reads from env / `.env`) |
186
+ | `nene2.validation` | `ValidationException`, `ValidationError` |
187
+ | `nene2.mcp` | `LocalMcpServer`, `HttpxMcpClient` |
188
+ | `nene2.log` | `setup_logging()` (structlog, JSON in production) |
189
+ | `nene2.use_case` | `UseCaseProtocol[I, O]`, `AsyncUseCaseProtocol[I, O]` |
190
+
191
+ ---
192
+
193
+ ## PHP NENE2 Correspondence
194
+
195
+ | PHP | Python |
196
+ |---|---|
197
+ | `readonly class` | `dataclass(frozen=True, slots=True)` |
198
+ | `PHPStan level 8` | `mypy --strict` |
199
+ | `PHP-CS-Fixer` | `ruff format` |
200
+ | `composer check` | `uv run pytest && mypy && ruff check && ruff format --check && pip-audit` |
201
+ | `ValidationException` | `nene2.validation.ValidationException` |
202
+ | `PaginationQueryParser` | `nene2.http.PaginationQueryParser` |
203
+ | `ErrorHandlerMiddleware` | `nene2.middleware.ErrorHandlerMiddleware` |
204
+ | `LocalMcpServer` | `nene2.mcp.LocalMcpServer` |
205
+
206
+ ---
207
+
208
+ ## Related
209
+
210
+ - [NENE2 (PHP)](https://github.com/hideyukiMORI/NENE2) — PHP reference implementation
211
+ - [Documentation](https://hideyukimori.github.io/nene2-python/) — full docs (Diátaxis structure)
@@ -0,0 +1,40 @@
1
+ nene2/__init__.py,sha256=BbkkyxUGlvKbcfXFS6ZMO4y1SDwR7J1Zi0tK5C0Fm6A,46
2
+ nene2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ nene2/auth/__init__.py,sha256=6CL-QYTo-QqqTTWdcICkavd7LOsx7LYKMWlU78sgcU0,478
4
+ nene2/auth/api_key.py,sha256=lTvpwcfRT8mVS-iZk7VGU3hUtGK718XNfYoSDdzIHbk,1379
5
+ nene2/auth/bearer_token.py,sha256=hUdgjmYPT1330q2kv0R4WPJmm0Fav5wDgvwT_5q8h7o,1822
6
+ nene2/auth/exceptions.py,sha256=ksgMVCZhcI6C7TKOMZkNe3-G3VmYrNL66PsCf_uLUZM,240
7
+ nene2/auth/interfaces.py,sha256=_wEZ7FmjMpqHVKNY_rS4__v61Kn4mZ2-dn_byP6jnU0,570
8
+ nene2/auth/local_verifier.py,sha256=d7xLM3elJwm-i60Yb5mUJlVWlJRjoHTB9LqnxUaCDYs,588
9
+ nene2/config/__init__.py,sha256=VAAqpJPW1bC1TtTLvkx5aFTC0d0cRPS71Z3dbcjk_Cg,139
10
+ nene2/config/settings.py,sha256=LR5HwXHUumW0UZmZRAgXidvw_m71pKVMEakgOpH9sNo,2386
11
+ nene2/database/__init__.py,sha256=9mwmvhG3sjlF9qDkfXrItZI1Sv_twgwfpmRdtRjKh2c,537
12
+ nene2/database/exceptions.py,sha256=75X5b1Go9JT59KGRwn08pygJajecmGzpewodbBqzPUQ,142
13
+ nene2/database/health.py,sha256=-WJ1OxOjll0mDPIAfoBtSxyiT-el76U8f7XT-Syl8xo,793
14
+ nene2/database/interfaces.py,sha256=1uSV19Bq6VAQzQbiY5c-16XpslegB7P3uklhIHvudd8,1501
15
+ nene2/database/sqlalchemy_executor.py,sha256=-s-NmRyDhEdQPYeYJvcf2BJWLpqDqcbH1QhsTDM3tzs,5078
16
+ nene2/http/__init__.py,sha256=zRF4mrCD6582VHqtP6BhIiwFQQBrXzZ9SDFT2QaeOv8,440
17
+ nene2/http/health.py,sha256=zYAeXkEWWCITFmza9u8yqcSkD2sJx7AGm650HhvU9Fs,496
18
+ nene2/http/pagination.py,sha256=BmKyTcNBplQtGADYjqlSvWSGEih9bb3DG-rT_CyvOg8,2663
19
+ nene2/http/problem_details.py,sha256=-a4E6OV0caigcETf9YBupPEhjlYvqLEwZdCux1ujhPI,874
20
+ nene2/log/__init__.py,sha256=umsIJ2QH0d-CpnqEQCR0oWCjpe7wVoGYAYP35f1Nmbc,113
21
+ nene2/log/setup.py,sha256=JZJ3EnUjN9XcC1BB03gbgk4R4cpOYgu7it487pLCIb0,1407
22
+ nene2/mcp/__init__.py,sha256=KBJAAa2ewj5aAeUWzl-2DU-qujAb-EIyeCHG0U8FBjc,289
23
+ nene2/mcp/http_client.py,sha256=bMG49qZJgZGZtucJuSzAA4WPmmynQ-tDYtCElBDRFoI,3092
24
+ nene2/mcp/server.py,sha256=NJF5FOV5YoSS2IVwUonM0h4pYh2fINU18I7GqLmP8Wc,927
25
+ nene2/middleware/__init__.py,sha256=_FLy_xggx6iHCeKxlrawX_Z0tiQqirwWIbTvi4ii4GE,672
26
+ nene2/middleware/domain_exception.py,sha256=hnJhMaa9_p-Ptlh6BwjpDuyxFkDHeZSc5zy6I_ZuMW4,572
27
+ nene2/middleware/error_handler.py,sha256=Ms4tEJED1-C2nIDoDG5Dm_bYk623oHa6D3zvS0d6kGQ,4166
28
+ nene2/middleware/request_id.py,sha256=vj3H1ULai8EgzoCfaM-YIf-vUbMhSiGmnfuUDjSgdY0,1540
29
+ nene2/middleware/request_logging.py,sha256=knmZV23HmmIJA73QIgpunfMi1bO8JttwwAGORju8UF0,1204
30
+ nene2/middleware/request_size_limit.py,sha256=r1nuV7TOyJ6tFGFgjd1mS7xU0KHmSQv6gMV8Qp417lQ,1793
31
+ nene2/middleware/security_headers.py,sha256=wZvQbqfD82ZmOgA3yBBRkAchR1YL3G0R8TnB-wbjP7A,1468
32
+ nene2/middleware/throttle.py,sha256=jI3XCUDfitmaF-ACznXMhaq8KPdmdhL5wT3jAPs5dns,2633
33
+ nene2/use_case/__init__.py,sha256=xwdFxHsjfPORSw6sq6dUN8JkEX6X2CHmO3stdpjUNOU,196
34
+ nene2/use_case/protocols.py,sha256=F-R99vLad7XX6fHncTVBo5XLsKFsVceWqnE4QlSn9kg,710
35
+ nene2/validation/__init__.py,sha256=Nj4dMx4Re3l57B0raFSUPQWeHHFMJbBQaQcuvDSbwiE,205
36
+ nene2/validation/exceptions.py,sha256=qFaK-LAk1sNs90TV0mrQLvwNlfUruSohRqpqOaaG-lg,1036
37
+ nene2_python-1.0.0.dist-info/METADATA,sha256=ZMDcaQqIqEj-pyekXLnIo47Yzxxbs3J_ybrUqHtV5bQ,7263
38
+ nene2_python-1.0.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
39
+ nene2_python-1.0.0.dist-info/licenses/LICENSE,sha256=fzFjofg1algLQJI6DBIhxBDQTpry6HNLUcjrXMPTwIk,1069
40
+ nene2_python-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 hideyukiMORI
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.