nene2-python 1.8.66__tar.gz → 1.8.164__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.
- {nene2_python-1.8.66 → nene2_python-1.8.164}/.env.example +5 -0
- nene2_python-1.8.164/.github/workflows/ci.yml +128 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/AGENTS.md +18 -2
- {nene2_python-1.8.66 → nene2_python-1.8.164}/CHANGELOG.md +51 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/CLAUDE.md +25 -12
- {nene2_python-1.8.66 → nene2_python-1.8.164}/PKG-INFO +63 -31
- {nene2_python-1.8.66 → nene2_python-1.8.164}/README.md +60 -29
- nene2_python-1.8.164/docs/explanation/field-trial-methodology.md +106 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-195.md +345 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-196.md +357 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-197.md +205 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-198.md +314 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-199.md +220 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-200.md +300 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-201.md +300 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-202.md +202 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-203.md +213 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-204.md +518 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-205.md +277 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-206.md +240 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-207.md +299 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-208.md +295 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-209.md +272 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-210.md +220 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-211.md +172 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-212.md +189 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-213.md +210 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-214.md +160 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-215.md +151 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-216.md +178 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-217.md +139 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-218.md +138 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-219.md +167 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-220.md +245 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-221.md +162 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-222.md +164 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-223.md +124 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-224.md +0 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-225.md +149 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-226.md +119 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-227.md +128 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-228.md +163 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-229.md +118 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-230.md +121 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-231.md +138 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-232.md +153 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-233.md +121 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-234.md +150 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-235.md +119 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-236.md +155 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-237.md +139 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-238.md +119 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-239.md +119 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-240.md +152 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-241.md +122 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-242.md +121 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-243.md +138 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-244.md +154 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-245.md +117 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-246.md +145 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-247.md +119 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-248.md +155 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-249.md +139 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-250.md +120 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-251.md +119 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-252.md +149 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-253.md +116 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-254.md +120 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-255.md +139 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-256.md +150 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-257.md +118 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-258.md +136 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-259.md +117 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-260.md +153 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-261.md +139 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-262.md +116 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-263.md +116 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-264.md +146 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-265.md +119 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-266.md +114 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-267.md +136 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-268.md +151 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-269.md +117 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-270.md +134 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-271.md +117 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-272.md +148 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-273.md +132 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-274.md +117 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-275.md +118 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-276.md +143 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-277.md +117 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-278.md +118 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-279.md +135 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-280.md +142 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-281.md +121 -0
- nene2_python-1.8.164/docs/field-trials/2026-05-field-trial-282.md +136 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/INDEX.md +96 -4
- nene2_python-1.8.164/docs/how-to/concurrency-patterns.md +68 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/middleware-stack.md +29 -1
- nene2_python-1.8.164/docs/how-to/release-and-publish.md +72 -0
- nene2_python-1.8.164/docs/how-to/run-integration-tests.md +51 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/run-tests.md +8 -4
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/index.md +4 -0
- nene2_python-1.8.164/docs/ja/explanation/field-trial-methodology.md +104 -0
- nene2_python-1.8.164/docs/ja/how-to/release-and-publish.md +68 -0
- nene2_python-1.8.164/docs/ja/how-to/run-integration-tests.md +48 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/how-to/run-tests.md +6 -4
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/reference/framework-modules.md +2 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/reference/framework-modules.md +122 -0
- nene2_python-1.8.164/docs/review/2026-05-22.md +94 -0
- nene2_python-1.8.164/docs/review/2026-05-23.md +83 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/roadmap.md +48 -44
- nene2_python-1.8.164/docs/todo/current.md +180 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/pyproject.toml +7 -3
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/app.py +83 -6
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/comment/handler.py +37 -35
- nene2_python-1.8.164/src/example/note/handler.py +97 -0
- nene2_python-1.8.164/src/example/tag/handler.py +89 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/auth/__init__.py +17 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/auth/api_key.py +1 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/auth/bearer_token.py +14 -0
- nene2_python-1.8.164/src/nene2/auth/composite.py +129 -0
- nene2_python-1.8.164/src/nene2/auth/local_bearer_jwt.py +60 -0
- nene2_python-1.8.164/src/nene2/auth/local_issuer.py +70 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/database/sqlalchemy_executor.py +24 -4
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/http/__init__.py +11 -1
- nene2_python-1.8.164/src/nene2/http/context.py +44 -0
- nene2_python-1.8.164/src/nene2/http/etag.py +128 -0
- nene2_python-1.8.164/src/nene2/http/query.py +67 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/middleware/__init__.py +3 -1
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/middleware/throttle.py +77 -33
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/comment/test_comment_http.py +28 -25
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/note/test_list_notes.py +24 -15
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/tag/test_tags.py +16 -16
- nene2_python-1.8.164/tests/example/test_examples_protected.py +53 -0
- nene2_python-1.8.164/tests/example/test_local_throttle_default.py +15 -0
- nene2_python-1.8.164/tests/example/test_system_routes.py +33 -0
- nene2_python-1.8.164/tests/integration/conftest.py +58 -0
- nene2_python-1.8.164/tests/integration/test_repository_real_db.py +65 -0
- nene2_python-1.8.164/tests/nene2/auth/test_composite_auth.py +134 -0
- nene2_python-1.8.164/tests/nene2/auth/test_local_bearer_jwt.py +60 -0
- nene2_python-1.8.164/tests/nene2/auth/test_local_issuer.py +116 -0
- nene2_python-1.8.164/tests/nene2/http/test_context.py +68 -0
- nene2_python-1.8.164/tests/nene2/http/test_etag.py +173 -0
- nene2_python-1.8.164/tests/nene2/http/test_query.py +117 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/middleware/test_throttle.py +28 -9
- nene2_python-1.8.164/tests/scripts/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/scripts/test_export_openapi.py +2 -1
- {nene2_python-1.8.66 → nene2_python-1.8.164}/uv.lock +15 -4
- nene2_python-1.8.66/.github/workflows/ci.yml +0 -52
- nene2_python-1.8.66/docs/todo/current.md +0 -77
- nene2_python-1.8.66/src/example/note/handler.py +0 -89
- nene2_python-1.8.66/src/example/tag/handler.py +0 -85
- nene2_python-1.8.66/src/nene2/http/etag.py +0 -23
- nene2_python-1.8.66/tests/nene2/http/test_etag.py +0 -51
- {nene2_python-1.8.66 → nene2_python-1.8.164}/.github/workflows/docs.yml +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/.github/workflows/publish.yml +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/.gitignore +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/.vitepress/config.mts +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/.vitepress/theme/custom.css +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/.vitepress/theme/index.ts +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/Dockerfile +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/LICENSE +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/alembic/README +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/alembic/env.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/alembic/script.py.mako +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/alembic/versions/001_create_notes_and_tags_tables.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/alembic.ini +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/compose.yaml +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/adr/0001-toolchain.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/adr/0002-clean-architecture.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/adr/0003-security-first.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/adr/0004-ai-first-design.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/adr/0005-logging.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/adr/0006-rate-limiting.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/adr/0009-mcp-design.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/adr/0010-async-use-case.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/adr/0011-mcp-as-core-dependency.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/de/index.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/de/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/explanation/architecture.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/explanation/design-philosophy.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-1.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-10.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-100.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-101.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-102.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-103.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-104.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-105.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-106.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-107.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-108.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-109.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-11.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-110.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-111.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-112.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-113.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-114.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-115.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-116.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-117.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-118.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-119.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-12.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-120.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-121.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-122.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-123.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-124.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-125.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-126.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-127.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-128.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-129.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-13.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-130.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-131.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-132.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-133.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-134.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-135.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-136.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-137.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-138.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-139.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-14.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-140.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-141.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-142.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-143.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-144.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-145.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-146.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-147.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-148.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-149.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-15.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-150.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-151.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-152.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-153.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-154.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-155.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-156.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-157.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-158.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-159.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-16.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-160.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-161.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-162.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-163.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-164.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-165.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-166.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-167.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-168.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-169.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-17.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-170.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-171.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-172.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-173.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-174.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-175.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-176.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-177.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-178.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-179.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-18.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-180.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-181.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-182.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-183.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-184.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-185.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-186.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-187.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-188.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-189.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-19.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-190.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-191.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-192.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-193.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-194.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-2.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-20.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-21.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-22.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-23.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-24.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-25.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-26.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-27.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-28.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-29.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-3.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-30.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-31.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-32.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-33.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-34.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-35.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-36.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-37.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-38.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-39.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-4.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-40.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-41.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-42.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-43.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-44.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-45.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-46.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-47.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-48.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-49.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-5.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-50.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-51.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-52.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-53.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-54.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-55.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-56.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-57.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-58.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-59.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-6.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-60.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-61.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-62.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-63.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-64.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-65.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-66.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-67.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-68.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-69.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-7.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-70.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-71.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-72.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-73.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-74.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-75.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-76.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-77.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-78.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-79.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-8.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-80.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-81.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-82.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-83.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-84.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-85.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-86.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-87.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-88.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-89.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-9.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-90.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-91.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-92.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-93.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-94.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-95.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-96.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-97.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-98.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/field-trials/2026-05-field-trial-99.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/fr/index.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/fr/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/add-new-domain.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/api-versioning.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/async-use-case.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/background-tasks.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/configure-auth.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/cors.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/custom-auth-middleware.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/decimal-unicode-input.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/dependency-injection.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/domain-events.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/email-address-parsing.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/file-upload.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/lifespan-and-app-state.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/new-project.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/problem-details.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/response-patterns.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/soft-delete.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/sqlalchemy-repository.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/streaming.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/structured-logging.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/validation.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/how-to/webhook.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/howto/mcp-setup.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/explanation/architecture.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/explanation/design-philosophy.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/how-to/add-new-domain.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/how-to/configure-auth.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/how-to/new-project.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/how-to/sqlalchemy-repository.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/howto/mcp-setup.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/index.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/reference/api.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/reference/configuration.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/tutorials/first-domain.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/ja/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/pt-br/index.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/pt-br/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/reference/api.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/reference/configuration.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/templates/field-trial-report.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/tutorials/first-domain.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/zh/index.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/docs/zh/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/package-lock.json +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/package.json +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/__main__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/comment/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/comment/entity.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/comment/exceptions.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/comment/repository.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/comment/sqlalchemy_repository.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/comment/use_case.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/mcp.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/note/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/note/async_use_case.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/note/entity.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/note/exceptions.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/note/repository.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/note/sqlalchemy_repository.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/note/use_case.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/schema.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/tag/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/tag/entity.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/tag/exceptions.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/tag/repository.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/tag/sqlalchemy_repository.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/example/tag/use_case.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/auth/deps.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/auth/exceptions.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/auth/interfaces.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/auth/local_verifier.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/cache/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/cache/ttl.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/config/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/config/settings.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/database/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/database/exceptions.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/database/health.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/database/interfaces.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/database/utils.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/http/health.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/http/pagination.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/http/problem_details.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/log/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/log/setup.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/mcp/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/mcp/http_client.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/mcp/server.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/middleware/domain_exception.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/middleware/error_handler.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/middleware/request_id.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/middleware/request_logging.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/middleware/request_size_limit.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/middleware/security_headers.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/middleware/setup.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/py.typed +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/security/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/security/webhook.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/use_case/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/use_case/protocols.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/validation/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/nene2/validation/exceptions.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/scripts/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/src/scripts/export_openapi.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/conftest.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/comment/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/comment/test_comment_repository.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/comment/test_comment_use_case.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/conftest.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/note/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/note/test_async_note_use_case.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/note/test_note_repository.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/tag/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/tag/test_tag_repository.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/test_cors.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/example/test_mcp.py +0 -0
- {nene2_python-1.8.66/tests/nene2 → nene2_python-1.8.164/tests/integration}/__init__.py +0 -0
- {nene2_python-1.8.66/tests/nene2/auth → nene2_python-1.8.164/tests/nene2}/__init__.py +0 -0
- {nene2_python-1.8.66/tests/nene2/cache → nene2_python-1.8.164/tests/nene2/auth}/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/auth/test_api_key.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/auth/test_bearer_token.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/auth/test_make_require_auth.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/auth/test_token_issuer.py +0 -0
- {nene2_python-1.8.66/tests/nene2/config → nene2_python-1.8.164/tests/nene2/cache}/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/cache/test_ttl.py +0 -0
- {nene2_python-1.8.66/tests/nene2/database → nene2_python-1.8.164/tests/nene2/config}/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/config/test_settings.py +0 -0
- {nene2_python-1.8.66/tests/nene2/http → nene2_python-1.8.164/tests/nene2/database}/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/database/test_transaction.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/database/test_utils.py +0 -0
- {nene2_python-1.8.66/tests/nene2/log → nene2_python-1.8.164/tests/nene2/http}/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/http/test_health.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/http/test_pagination.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/http/test_problem_details.py +0 -0
- {nene2_python-1.8.66/tests/nene2/mcp → nene2_python-1.8.164/tests/nene2/log}/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/log/test_setup.py +0 -0
- {nene2_python-1.8.66/tests/nene2/middleware → nene2_python-1.8.164/tests/nene2/mcp}/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/mcp/test_http_client.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/mcp/test_server.py +0 -0
- {nene2_python-1.8.66/tests/nene2/security → nene2_python-1.8.164/tests/nene2/middleware}/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/middleware/test_error_handler.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/middleware/test_request_id.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/middleware/test_request_logging.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/middleware/test_request_size_limit.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/middleware/test_security_headers.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/middleware/test_setup_middlewares.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/middleware/test_simple_domain_handler.py +0 -0
- {nene2_python-1.8.66/tests/nene2/use_case → nene2_python-1.8.164/tests/nene2/security}/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/security/test_webhook.py +0 -0
- {nene2_python-1.8.66/tests/nene2/validation → nene2_python-1.8.164/tests/nene2/use_case}/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/use_case/test_protocols.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/use_case/test_run_in_threadpool.py +0 -0
- {nene2_python-1.8.66/tests/scripts → nene2_python-1.8.164/tests/nene2/validation}/__init__.py +0 -0
- {nene2_python-1.8.66 → nene2_python-1.8.164}/tests/nene2/validation/test_exceptions.py +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
check:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.12", "3.14"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v5
|
|
21
|
+
with:
|
|
22
|
+
version: "latest"
|
|
23
|
+
enable-cache: true
|
|
24
|
+
|
|
25
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
26
|
+
run: uv python install ${{ matrix.python-version }}
|
|
27
|
+
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: uv sync --all-extras
|
|
30
|
+
|
|
31
|
+
- name: pytest (with coverage)
|
|
32
|
+
run: uv run pytest
|
|
33
|
+
|
|
34
|
+
- name: coverage gate — domain/use_case layers (90%)
|
|
35
|
+
run: |
|
|
36
|
+
uv run coverage report \
|
|
37
|
+
--include="src/example/*/use_case.py,src/example/*/async_use_case.py,src/example/*/entity.py" \
|
|
38
|
+
--fail-under=90
|
|
39
|
+
|
|
40
|
+
- name: mypy
|
|
41
|
+
run: uv run mypy src/
|
|
42
|
+
|
|
43
|
+
- name: ruff check
|
|
44
|
+
run: uv run ruff check src/ tests/
|
|
45
|
+
|
|
46
|
+
- name: ruff format
|
|
47
|
+
run: uv run ruff format --check src/ tests/
|
|
48
|
+
|
|
49
|
+
- name: pip-audit
|
|
50
|
+
# PYSEC-2025-183: pyjwt weak-key-length — disputed by supplier, no fix version available.
|
|
51
|
+
# Transitive via mcp>=1.0. Re-evaluate when pyjwt releases a fix. (#280)
|
|
52
|
+
run: uv run pip-audit --ignore-vuln PYSEC-2025-183
|
|
53
|
+
|
|
54
|
+
integration-db:
|
|
55
|
+
name: Real-DB integration tests
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
# 実 PostgreSQL / MySQL に対してリポジトリ層を検証する(#747)。
|
|
58
|
+
# SQLite だけでは露見しなかった lastrowid 由来の採番バグを CI で恒常的に防ぐ。
|
|
59
|
+
services:
|
|
60
|
+
postgres:
|
|
61
|
+
image: postgres:16-alpine
|
|
62
|
+
env:
|
|
63
|
+
POSTGRES_PASSWORD: nene2
|
|
64
|
+
POSTGRES_DB: nene2_test
|
|
65
|
+
ports:
|
|
66
|
+
- 5432:5432
|
|
67
|
+
options: >-
|
|
68
|
+
--health-cmd "pg_isready -U postgres"
|
|
69
|
+
--health-interval 5s --health-timeout 5s --health-retries 10
|
|
70
|
+
mysql:
|
|
71
|
+
image: mysql:8
|
|
72
|
+
env:
|
|
73
|
+
MYSQL_ROOT_PASSWORD: nene2
|
|
74
|
+
MYSQL_DATABASE: nene2_test
|
|
75
|
+
ports:
|
|
76
|
+
- 3306:3306
|
|
77
|
+
options: >-
|
|
78
|
+
--health-cmd "mysqladmin ping -uroot -pnene2"
|
|
79
|
+
--health-interval 5s --health-timeout 5s --health-retries 20
|
|
80
|
+
|
|
81
|
+
steps:
|
|
82
|
+
- uses: actions/checkout@v4
|
|
83
|
+
|
|
84
|
+
- name: Install uv
|
|
85
|
+
uses: astral-sh/setup-uv@v5
|
|
86
|
+
with:
|
|
87
|
+
version: "latest"
|
|
88
|
+
enable-cache: true
|
|
89
|
+
|
|
90
|
+
- name: Set up Python
|
|
91
|
+
run: uv python install 3.14
|
|
92
|
+
|
|
93
|
+
- name: Install dependencies
|
|
94
|
+
run: uv sync --all-extras
|
|
95
|
+
|
|
96
|
+
- name: integration tests (PostgreSQL + MySQL)
|
|
97
|
+
env:
|
|
98
|
+
NENE2_TEST_POSTGRES_URL: postgresql+psycopg2://postgres:nene2@127.0.0.1:5432/nene2_test
|
|
99
|
+
NENE2_TEST_MYSQL_URL: mysql+pymysql://root:nene2@127.0.0.1:3306/nene2_test
|
|
100
|
+
run: uv run pytest tests/integration/ -v --no-cov
|
|
101
|
+
|
|
102
|
+
package-build:
|
|
103
|
+
name: Package build verification
|
|
104
|
+
runs-on: ubuntu-latest
|
|
105
|
+
steps:
|
|
106
|
+
- uses: actions/checkout@v4
|
|
107
|
+
|
|
108
|
+
- name: Install uv
|
|
109
|
+
uses: astral-sh/setup-uv@v5
|
|
110
|
+
with:
|
|
111
|
+
version: "latest"
|
|
112
|
+
|
|
113
|
+
# publish.yml と同じ uv build を PR ごとに走らせ、配布物の壊れを早期検出する(#541)。
|
|
114
|
+
- name: Build sdist + wheel
|
|
115
|
+
run: uv build
|
|
116
|
+
|
|
117
|
+
- name: Validate distribution metadata (twine check)
|
|
118
|
+
run: uvx twine check dist/*
|
|
119
|
+
|
|
120
|
+
- name: Verify clean install + import (no example/tests leakage)
|
|
121
|
+
run: |
|
|
122
|
+
uv venv /tmp/verify
|
|
123
|
+
uv pip install --python /tmp/verify/bin/python dist/*.whl
|
|
124
|
+
/tmp/verify/bin/python -c "import nene2; from nene2.http import PaginationResponse; print('import OK')"
|
|
125
|
+
# フレームワーク以外(example/tests)が配布物に混入していないことを保証
|
|
126
|
+
if /tmp/verify/bin/python -c "import example" 2>/dev/null; then
|
|
127
|
+
echo "ERROR: example package leaked into wheel"; exit 1
|
|
128
|
+
fi
|
|
@@ -10,7 +10,8 @@ NENE2 の設計哲学を Python で実装したリファレンスフレームワ
|
|
|
10
10
|
- DTO / バリデーション: Pydantic v2 + `dataclass(frozen=True)`
|
|
11
11
|
- 型チェック: `mypy --strict`
|
|
12
12
|
- Lint / Format: `ruff`
|
|
13
|
-
- テスト: `pytest` + `httpx
|
|
13
|
+
- テスト: `pytest` + `httpx`(466 tests、カバレッジ 80% 以上)
|
|
14
|
+
- 現状: **v1.8.97** / FT219 完了 / [Field Trial INDEX](docs/field-trials/INDEX.md)
|
|
14
15
|
|
|
15
16
|
## 設計原則(PHP 版 NENE2 と共通)
|
|
16
17
|
|
|
@@ -19,13 +20,28 @@ NENE2 の設計哲学を Python で実装したリファレンスフレームワ
|
|
|
19
20
|
3. ハンドラーは薄く: parse → use-case → response
|
|
20
21
|
4. エラーは RFC 9457 Problem Details(application/problem+json)
|
|
21
22
|
5. `ValidationException` → 422 自動マッピング
|
|
23
|
+
6. FastAPI アプリは `APIRouter` + `create_app()` をファイル末尾に配置([CLAUDE.md](CLAUDE.md))
|
|
22
24
|
|
|
23
25
|
## 全チェックコマンド(CI と同等)
|
|
24
26
|
|
|
25
27
|
```bash
|
|
26
|
-
uv run pytest &&
|
|
28
|
+
uv run pytest && \
|
|
29
|
+
uv run mypy src/ && \
|
|
30
|
+
uv run ruff check src/ tests/ && \
|
|
31
|
+
uv run ruff format --check src/ tests/ && \
|
|
32
|
+
uv run pip-audit --ignore-vuln PYSEC-2025-183
|
|
27
33
|
```
|
|
28
34
|
|
|
35
|
+
## ドキュメント入口
|
|
36
|
+
|
|
37
|
+
| 用途 | ファイル |
|
|
38
|
+
|---|---|
|
|
39
|
+
| 設計ポリシー(SSOT) | [CLAUDE.md](CLAUDE.md) |
|
|
40
|
+
| 現状・次タスク | [docs/todo/current.md](docs/todo/current.md) |
|
|
41
|
+
| FT 一覧 | [docs/field-trials/INDEX.md](docs/field-trials/INDEX.md) |
|
|
42
|
+
| API リファレンス | [docs/reference/framework-modules.md](docs/reference/framework-modules.md) |
|
|
43
|
+
| How-to | [docs/how-to/](docs/how-to/) |
|
|
44
|
+
|
|
29
45
|
## PHP 版リポジトリとの関係
|
|
30
46
|
|
|
31
47
|
PHP 版 NENE2 の設計決定・ADR・フィールドトライアル記録は `../NENE2/docs/` を参照。
|
|
@@ -3,6 +3,57 @@
|
|
|
3
3
|
All notable changes to nene2-python are documented here.
|
|
4
4
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
5
|
|
|
6
|
+
> 詳細な版ごとの一行サマリーは [`docs/todo/current.md`](docs/todo/current.md) の
|
|
7
|
+
> マイルストーン表を参照。本ファイルにはリリース粒度の集約エントリを記録する。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## [1.8.164] — 2026-05-29
|
|
12
|
+
|
|
13
|
+
実データベース(PostgreSQL / MySQL)統合テストを追加し、マルチDB対応を実測で検証 (#747)。
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- `SqlAlchemyQueryExecutor.write()` / `_BoundQueryExecutor.write()` の INSERT 採番を
|
|
17
|
+
全方言で正しく返すよう修正。psycopg2 は `lastrowid` 非対応のため、PostgreSQL では
|
|
18
|
+
`lastval()` フォールバックを使う(従来は `rowcount` を返し、`save()` が常に `1` を
|
|
19
|
+
返す重大バグだった)。SQLite / MySQL は従来どおり `lastrowid`。
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- 実DB統合テスト `tests/integration/`(PostgreSQL / MySQL)。環境変数
|
|
23
|
+
`NENE2_TEST_POSTGRES_URL` / `NENE2_TEST_MYSQL_URL` 設定時のみ実行、未設定ならスキップ。
|
|
24
|
+
スキーマは SQLAlchemy `Table` から方言非依存に生成。
|
|
25
|
+
- CI に `integration-db` ジョブ(postgres:16 / mysql:8 service container)を追加。
|
|
26
|
+
- how-to [`run-integration-tests.md`](docs/how-to/run-integration-tests.md)(EN/JA)を追加。
|
|
27
|
+
- `pymysql` を dev 依存に追加(`mysql+pymysql://` ドライバが未導入だった)。
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- リリース手順 how-to を「公開済み」の現実に合わせて訂正(#541 の事後整合)。
|
|
31
|
+
|
|
32
|
+
## [1.8.163] — 2026-05-29
|
|
33
|
+
|
|
34
|
+
v1.8.35〜v1.8.163 の集約リリース。フィールドトライアル網羅スイープの完了と、
|
|
35
|
+
公開準備・ポリシー整合・ハウスキーピングを含む。
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
- フィールドトライアル **FT203〜FT282**(標準ライブラリ検証 + セキュリティ深掘り)。
|
|
39
|
+
セキュリティ診断(`%3==0`)・クラッカーペンテスト(`%4==0`)・6 ペルソナ DX レビューを各 FT で実施。
|
|
40
|
+
危険プリミティブ回避シリーズ(pickle/marshal/eval、subprocess、SSRF、ReDoS、zip/tar slip、解凍爆弾、SSTI、XXE 等)を含む。
|
|
41
|
+
- FT ループ方法論ドキュメント [`docs/explanation/field-trial-methodology.md`](docs/explanation/field-trial-methodology.md)(EN/JA)— 目的・3 フェーズ・終着点を明文化 (#540)
|
|
42
|
+
- ETag / 条件付きリクエスト、`CompositeAuthMiddleware`、`InMemoryRateLimitStorage`、query ヘルパー、`LocalTokenIssuer`、`RequestScopedContext`
|
|
43
|
+
- リリース手順 how-to [`docs/how-to/release-and-publish.md`](docs/how-to/release-and-publish.md)、CI に配布物ビルド検証ジョブ (#541)
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
- example の全ハンドラー(Note/Tag/Comment)に `response_model` を付与し OpenAPI にレスポンス型を出力 (#539)
|
|
47
|
+
- starlette 1.0.1 へ更新(PYSEC-2026-161 解消、#611)
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
- example の 422 レスポンスで全フィールドのエラーを返すように修正 (#588)
|
|
51
|
+
- `APP_ENV=local` で throttle を既定無効化 (#592)
|
|
52
|
+
|
|
53
|
+
### Housekeeping
|
|
54
|
+
- FT サンドボックスを 5.1G→79M に整理(`ft-status.sh --clean-sandbox` 追加)、マージ済み orphan ブランチを削除
|
|
55
|
+
- #553(`/examples/ping`・`/examples/notes`)は #578 で実装済みを確認し close
|
|
56
|
+
|
|
6
57
|
---
|
|
7
58
|
|
|
8
59
|
## [1.8.34] — 2026-05-20
|
|
@@ -223,7 +223,14 @@ AI エージェント(Claude 等)がこのコードベースを正確に理
|
|
|
223
223
|
## 7. エラーハンドリングポリシー
|
|
224
224
|
|
|
225
225
|
- `ValidationException` → 422 validation-failed Problem Details(自動)
|
|
226
|
-
- `
|
|
226
|
+
- `ValidationError` は **`field / message / code` の 3 引数がすべて必須**(省略すると TypeError)
|
|
227
|
+
```python
|
|
228
|
+
from nene2.validation import ValidationError, ValidationException
|
|
229
|
+
raise ValidationException([
|
|
230
|
+
ValidationError(field="host", message="許可されていません", code="host_not_allowed")
|
|
231
|
+
])
|
|
232
|
+
```
|
|
233
|
+
- `ErrorHandlerMiddleware` が全例外をキャッチ(FT サンドボックスでも `add_middleware(ErrorHandlerMiddleware)` を忘れないこと)
|
|
227
234
|
- `APP_DEBUG=true` 時のみ例外メッセージを detail に含める
|
|
228
235
|
- **スタックトレース・DB 接続情報を公開レスポンスに含めない**
|
|
229
236
|
- ログには `logging` モジュールのみ使用(`print()` 禁止)
|
|
@@ -319,7 +326,7 @@ uv run pytest && \
|
|
|
319
326
|
uv run mypy src/ && \
|
|
320
327
|
uv run ruff check src/ tests/ && \
|
|
321
328
|
uv run ruff format --check src/ tests/ && \
|
|
322
|
-
uv run pip-audit
|
|
329
|
+
uv run pip-audit --ignore-vuln PYSEC-2025-183
|
|
323
330
|
|
|
324
331
|
# 個別
|
|
325
332
|
uv run pytest
|
|
@@ -329,7 +336,7 @@ uv run mypy src/
|
|
|
329
336
|
uv run ruff check src/ tests/
|
|
330
337
|
uv run ruff check src/ tests/ --fix # 自動修正
|
|
331
338
|
uv run ruff format src/ tests/
|
|
332
|
-
uv run pip-audit
|
|
339
|
+
uv run pip-audit --ignore-vuln PYSEC-2025-183 # 依存関係の脆弱性スキャン(CI と同じ)
|
|
333
340
|
|
|
334
341
|
# 開発サーバー
|
|
335
342
|
uv run uvicorn src.example.app:app --reload --port 8080
|
|
@@ -345,11 +352,13 @@ docker compose up app
|
|
|
345
352
|
```
|
|
346
353
|
src/
|
|
347
354
|
nene2/ フレームワークコア
|
|
348
|
-
http/ JSON レスポンス・ページネーション・Problem Details
|
|
349
|
-
middleware/
|
|
355
|
+
http/ JSON レスポンス・ページネーション・Problem Details・ETag・query ヘルパー
|
|
356
|
+
middleware/ ミドルウェアパイプライン + setup_middlewares()
|
|
350
357
|
validation/ ValidationException / ValidationError
|
|
351
358
|
config/ 型付き設定オブジェクト(AppSettings)
|
|
352
|
-
auth/
|
|
359
|
+
auth/ Bearer / API Key / CompositeAuth / LocalTokenIssuer
|
|
360
|
+
cache/ TtlCache[V]
|
|
361
|
+
security/ verify_hmac_signature()
|
|
353
362
|
database/ SqlAlchemyQueryExecutor / SqlAlchemyTransactionManager
|
|
354
363
|
mcp/ LocalMcpServer / HttpxMcpClient
|
|
355
364
|
log/ structlog セットアップ
|
|
@@ -358,20 +367,24 @@ src/
|
|
|
358
367
|
note/ Note ドメイン(entity / repository / use_case / handler / sqlalchemy_repository)
|
|
359
368
|
tag/ Tag ドメイン(entity / repository / use_case / handler / sqlalchemy_repository)
|
|
360
369
|
comment/ Comment ドメイン(Note に紐付く nested ドメイン)
|
|
361
|
-
app.py
|
|
370
|
+
app.py アプリケーションファクトリ(create_app)
|
|
362
371
|
mcp.py MCP サーバー(Note / Tag / Comment 全 15 ツール)
|
|
363
372
|
|
|
364
|
-
tests/ pytest テスト(src/
|
|
373
|
+
tests/ pytest テスト(src/ を鏡像、466 tests)
|
|
365
374
|
docs/
|
|
366
375
|
adr/ 設計決定記録(変更理由を残す)
|
|
367
|
-
how-to/ How-to
|
|
376
|
+
how-to/ How-to ガイド(24+ 本)
|
|
368
377
|
howto/ MCP セットアップガイド
|
|
369
|
-
field-trials/ フィールドトライアル記録(FT1〜
|
|
378
|
+
field-trials/ フィールドトライアル記録(FT1〜FT219+、INDEX.md 参照)
|
|
379
|
+
field-trials/INDEX.md FT 検索索引(テーマ・診断種別・Follow-up Issue)
|
|
380
|
+
todo/current.md 現状サマリー・次タスク
|
|
381
|
+
roadmap.md ロードマップ・PHP 版対応表
|
|
382
|
+
review/ 作業日報
|
|
370
383
|
tutorials/ チュートリアル
|
|
371
384
|
explanation/ アーキテクチャ解説
|
|
372
385
|
reference/ 設定・モジュールリファレンス
|
|
373
386
|
ja/ 日本語ドキュメント(上記すべての翻訳)
|
|
374
|
-
.github/workflows/ CI(GitHub Actions)
|
|
387
|
+
.github/workflows/ CI(GitHub Actions: Python 3.12 / 3.14)
|
|
375
388
|
```
|
|
376
389
|
|
|
377
390
|
---
|
|
@@ -476,4 +489,4 @@ Python 標準ライブラリ・サードパーティライブラリを nene2-pyt
|
|
|
476
489
|
| `JsonResponseFactory` | `fastapi.responses.JSONResponse` |
|
|
477
490
|
| `PHPStan level 8` | `mypy --strict` |
|
|
478
491
|
| `PHP-CS-Fixer` | `ruff format` |
|
|
479
|
-
| `composer check` | `uv run pytest && mypy && ruff check && ruff format --check && pip-audit` |
|
|
492
|
+
| `composer check` | `uv run pytest && mypy && ruff check && ruff format --check && pip-audit --ignore-vuln PYSEC-2025-183` |
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nene2-python
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.164
|
|
4
4
|
Summary: NENE2 Python — minimal API framework following NENE2's design philosophy
|
|
5
5
|
Project-URL: Homepage, https://github.com/hideyukiMORI/nene2-python
|
|
6
6
|
Project-URL: Repository, https://github.com/hideyukiMORI/nene2-python
|
|
7
|
-
Project-URL: Documentation, https://github.
|
|
7
|
+
Project-URL: Documentation, https://hideyukimori.github.io/nene2-python/
|
|
8
8
|
Project-URL: Bug Tracker, https://github.com/hideyukiMORI/nene2-python/issues
|
|
9
9
|
Author-email: hideyukiMORI <info.xion.cc@gmail.com>
|
|
10
10
|
License: MIT
|
|
@@ -18,6 +18,7 @@ Classifier: Operating System :: OS Independent
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
22
|
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
22
23
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
23
24
|
Classifier: Typing :: Typed
|
|
@@ -51,6 +52,8 @@ A Python reference framework implementing the [NENE2](https://github.com/hideyuk
|
|
|
51
52
|
[](https://www.python.org/)
|
|
52
53
|
[](LICENSE)
|
|
53
54
|
|
|
55
|
+
**Current release**: `v1.8.97` · **466 tests** · CI on Python 3.12 and 3.14
|
|
56
|
+
|
|
54
57
|
---
|
|
55
58
|
|
|
56
59
|
## Features
|
|
@@ -60,11 +63,14 @@ A Python reference framework implementing the [NENE2](https://github.com/hideyuk
|
|
|
60
63
|
- **`mypy --strict`** — equivalent to PHPStan level 8 type safety
|
|
61
64
|
- **ruff** — lint and format in one tool (replaces flake8, isort, black, bandit)
|
|
62
65
|
- **RFC 9457 Problem Details** — uniform error responses across all endpoints
|
|
63
|
-
- **Bearer Token / API Key auth** —
|
|
66
|
+
- **Bearer Token / API Key auth** — `LocalTokenVerifier`, `CompositeAuthMiddleware`, dev JWT helpers
|
|
64
67
|
- **MCP support** — expose UseCases as AI agent tools via `LocalMcpServer`
|
|
65
68
|
- **SQLAlchemy Core** — parameterised SQL without ORM overhead
|
|
66
|
-
- **Security middleware** — CSP,
|
|
69
|
+
- **Security middleware** — CSP, rate limiting, request size limit, CORS via `setup_middlewares()`
|
|
70
|
+
- **ETag / conditional requests** — `generate_etag()`, `check_not_modified()`, `check_precondition()`
|
|
71
|
+
- **TTL cache & webhooks** — `TtlCache[V]`, `verify_hmac_signature()`
|
|
67
72
|
- **structlog** — structured JSON logging with request ID correlation
|
|
73
|
+
- **219 field trials** — stdlib and framework patterns validated in sandbox apps ([INDEX](docs/field-trials/INDEX.md))
|
|
68
74
|
|
|
69
75
|
---
|
|
70
76
|
|
|
@@ -76,31 +82,44 @@ pip install nene2-python
|
|
|
76
82
|
uv add nene2-python
|
|
77
83
|
```
|
|
78
84
|
|
|
79
|
-
Requires Python 3.12
|
|
85
|
+
Requires Python 3.12+ (CI also tests 3.14).
|
|
80
86
|
|
|
81
87
|
---
|
|
82
88
|
|
|
83
89
|
## Quick Start
|
|
84
90
|
|
|
91
|
+
Use `APIRouter` + `create_app()` at the **end of the file** (see [CLAUDE.md](CLAUDE.md)). Register middlewares with `setup_middlewares()` so 500 responses still get `X-Request-Id` and security headers.
|
|
92
|
+
|
|
85
93
|
```python
|
|
86
|
-
from fastapi import FastAPI
|
|
94
|
+
from fastapi import APIRouter, FastAPI
|
|
87
95
|
from nene2.config import AppSettings
|
|
88
|
-
from nene2.middleware import
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
app
|
|
99
|
-
|
|
100
|
-
app
|
|
101
|
-
|
|
96
|
+
from nene2.middleware import setup_middlewares
|
|
97
|
+
|
|
98
|
+
router = APIRouter()
|
|
99
|
+
|
|
100
|
+
@router.get("/health")
|
|
101
|
+
def health() -> dict[str, str]:
|
|
102
|
+
return {"status": "ok"}
|
|
103
|
+
|
|
104
|
+
def create_app() -> FastAPI:
|
|
105
|
+
cfg = AppSettings()
|
|
106
|
+
app = FastAPI(title=cfg.app_name)
|
|
107
|
+
setup_middlewares(
|
|
108
|
+
app,
|
|
109
|
+
debug=cfg.app_debug,
|
|
110
|
+
throttle_limit=cfg.throttle_limit if cfg.throttle_enabled else None,
|
|
111
|
+
cors_allowed_origins=cfg.cors_origins if cfg.cors_enabled else None,
|
|
112
|
+
)
|
|
113
|
+
app.include_router(router)
|
|
114
|
+
return app
|
|
115
|
+
|
|
116
|
+
app = create_app()
|
|
102
117
|
```
|
|
103
118
|
|
|
119
|
+
See the full reference app in [`src/example/`](src/example/) (Note / Tag / Comment CRUD, auth, MCP).
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
104
123
|
### Define a domain
|
|
105
124
|
|
|
106
125
|
```python
|
|
@@ -137,7 +156,6 @@ class GetNoteUseCase:
|
|
|
137
156
|
```python
|
|
138
157
|
from fastapi import APIRouter
|
|
139
158
|
from fastapi.responses import JSONResponse
|
|
140
|
-
from nene2.http import problem_details_response
|
|
141
159
|
|
|
142
160
|
router = APIRouter(prefix="/notes", tags=["notes"])
|
|
143
161
|
|
|
@@ -147,16 +165,14 @@ async def get_note(note_id: int) -> JSONResponse:
|
|
|
147
165
|
return JSONResponse({"id": note.id, "title": note.title, "body": note.body})
|
|
148
166
|
```
|
|
149
167
|
|
|
150
|
-
See the full working example in [`src/example/`](src/example/).
|
|
151
|
-
|
|
152
168
|
---
|
|
153
169
|
|
|
154
170
|
## Development Commands
|
|
155
171
|
|
|
156
172
|
```bash
|
|
157
173
|
uv sync # install dependencies
|
|
158
|
-
uv run pytest #
|
|
159
|
-
uv run mypy src/ # type check
|
|
174
|
+
uv run pytest # 466 tests, coverage ≥ 80%
|
|
175
|
+
uv run mypy src/ # type check (strict)
|
|
160
176
|
uv run ruff check src/ tests/ # lint
|
|
161
177
|
uv run ruff format src/ tests/ # format
|
|
162
178
|
uv run uvicorn src.example.app:app --reload --port 8080 # dev server
|
|
@@ -169,25 +185,39 @@ uv run pytest && \
|
|
|
169
185
|
uv run mypy src/ && \
|
|
170
186
|
uv run ruff check src/ tests/ && \
|
|
171
187
|
uv run ruff format --check src/ tests/ && \
|
|
172
|
-
uv run pip-audit
|
|
188
|
+
uv run pip-audit --ignore-vuln PYSEC-2025-183
|
|
173
189
|
```
|
|
174
190
|
|
|
191
|
+
CI also runs a **90% coverage gate** on `example/*/use_case.py`, `entity.py`, and `async_use_case.py`.
|
|
192
|
+
|
|
175
193
|
---
|
|
176
194
|
|
|
177
195
|
## Framework Modules
|
|
178
196
|
|
|
179
197
|
| Module | Purpose |
|
|
180
198
|
|---|---|
|
|
181
|
-
| `nene2.http` |
|
|
182
|
-
| `nene2.middleware` |
|
|
183
|
-
| `nene2.auth` |
|
|
199
|
+
| `nene2.http` | Pagination, Problem Details, health checks, ETag, query helpers, `RequestScopedContext` |
|
|
200
|
+
| `nene2.middleware` | Full pipeline + `setup_middlewares()`, rate-limit storage protocol |
|
|
201
|
+
| `nene2.auth` | Bearer / API Key / composite auth, `LocalTokenIssuer`, `make_require_auth()` |
|
|
184
202
|
| `nene2.database` | `SqlAlchemyQueryExecutor`, `SqlAlchemyTransactionManager`, `DatabaseHealthCheck` |
|
|
185
203
|
| `nene2.config` | `AppSettings` (pydantic-settings, reads from env / `.env`) |
|
|
186
204
|
| `nene2.validation` | `ValidationException`, `ValidationError` |
|
|
205
|
+
| `nene2.cache` | `TtlCache[V]` — thread-safe in-memory TTL cache |
|
|
206
|
+
| `nene2.security` | `verify_hmac_signature()` for webhook verification |
|
|
187
207
|
| `nene2.mcp` | `LocalMcpServer`, `HttpxMcpClient` |
|
|
188
208
|
| `nene2.log` | `setup_logging()` (structlog, JSON in production) |
|
|
189
209
|
| `nene2.use_case` | `UseCaseProtocol[I, O]`, `AsyncUseCaseProtocol[I, O]` |
|
|
190
210
|
|
|
211
|
+
Details: [Framework modules reference](docs/reference/framework-modules.md) · [How-to guides](docs/how-to/)
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Versioning
|
|
216
|
+
|
|
217
|
+
- **`pyproject.toml` `version`** — bumped with each merged FT or feature PR (currently `1.8.97`).
|
|
218
|
+
- **Git tags** (`v1.8.N`) — created on selected releases; may lag behind `pyproject.toml` during rapid FT loops.
|
|
219
|
+
- See [docs/todo/current.md](docs/todo/current.md) for the latest milestone table.
|
|
220
|
+
|
|
191
221
|
---
|
|
192
222
|
|
|
193
223
|
## PHP NENE2 Correspondence
|
|
@@ -197,7 +227,7 @@ uv run pip-audit
|
|
|
197
227
|
| `readonly class` | `dataclass(frozen=True, slots=True)` |
|
|
198
228
|
| `PHPStan level 8` | `mypy --strict` |
|
|
199
229
|
| `PHP-CS-Fixer` | `ruff format` |
|
|
200
|
-
| `composer check` | `uv run pytest && mypy && ruff check && ruff format --check && pip-audit` |
|
|
230
|
+
| `composer check` | `uv run pytest && mypy && ruff check && ruff format --check && pip-audit --ignore-vuln PYSEC-2025-183` |
|
|
201
231
|
| `ValidationException` | `nene2.validation.ValidationException` |
|
|
202
232
|
| `PaginationQueryParser` | `nene2.http.PaginationQueryParser` |
|
|
203
233
|
| `ErrorHandlerMiddleware` | `nene2.middleware.ErrorHandlerMiddleware` |
|
|
@@ -208,4 +238,6 @@ uv run pip-audit
|
|
|
208
238
|
## Related
|
|
209
239
|
|
|
210
240
|
- [NENE2 (PHP)](https://github.com/hideyukiMORI/NENE2) — PHP reference implementation
|
|
211
|
-
- [Documentation](https://hideyukimori.github.io/nene2-python/) —
|
|
241
|
+
- [Documentation (GitHub Pages)](https://hideyukimori.github.io/nene2-python/) — tutorials, how-to, reference (Diátaxis)
|
|
242
|
+
- [Field Trial INDEX](docs/field-trials/INDEX.md) — FT1–FT219 searchable index
|
|
243
|
+
- [Roadmap](docs/roadmap.md) — current status and planned work
|