nene2-python 1.8.36__tar.gz → 1.8.37__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.36 → nene2_python-1.8.37}/PKG-INFO +1 -1
- nene2_python-1.8.37/docs/field-trials/2026-05-field-trial-166.md +246 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/pyproject.toml +1 -1
- {nene2_python-1.8.36 → nene2_python-1.8.37}/.env.example +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/.github/workflows/ci.yml +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/.github/workflows/docs.yml +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/.github/workflows/publish.yml +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/.gitignore +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/.vitepress/config.mts +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/.vitepress/theme/custom.css +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/.vitepress/theme/index.ts +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/AGENTS.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/CHANGELOG.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/CLAUDE.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/Dockerfile +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/LICENSE +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/README.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/alembic/README +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/alembic/env.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/alembic/script.py.mako +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/alembic/versions/001_create_notes_and_tags_tables.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/alembic.ini +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/compose.yaml +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0001-toolchain.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0002-clean-architecture.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0003-security-first.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0004-ai-first-design.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0005-logging.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0006-rate-limiting.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0009-mcp-design.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0010-async-use-case.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0011-mcp-as-core-dependency.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/de/index.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/de/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/explanation/architecture.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/explanation/design-philosophy.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-1.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-10.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-100.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-101.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-102.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-103.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-104.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-105.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-106.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-107.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-108.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-109.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-11.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-110.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-111.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-112.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-113.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-114.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-115.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-116.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-117.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-118.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-119.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-12.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-120.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-121.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-122.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-123.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-124.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-125.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-126.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-127.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-128.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-129.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-13.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-130.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-131.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-132.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-133.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-134.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-135.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-136.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-137.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-138.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-139.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-14.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-140.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-141.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-142.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-143.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-144.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-145.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-146.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-147.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-148.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-149.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-15.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-150.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-151.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-152.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-153.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-154.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-155.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-156.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-157.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-158.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-159.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-16.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-160.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-161.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-162.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-163.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-164.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-165.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-17.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-18.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-19.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-2.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-20.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-21.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-22.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-23.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-24.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-25.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-26.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-27.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-28.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-29.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-3.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-30.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-31.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-32.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-33.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-34.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-35.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-36.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-37.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-38.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-39.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-4.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-40.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-41.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-42.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-43.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-44.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-45.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-46.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-47.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-48.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-49.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-5.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-50.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-51.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-52.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-53.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-54.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-55.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-56.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-57.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-58.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-59.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-6.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-60.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-61.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-62.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-63.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-64.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-65.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-66.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-67.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-68.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-69.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-7.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-70.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-71.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-72.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-73.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-74.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-75.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-76.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-77.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-78.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-79.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-8.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-80.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-81.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-82.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-83.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-84.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-85.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-86.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-87.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-88.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-89.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-9.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-90.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-91.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-92.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-93.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-94.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-95.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-96.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-97.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-98.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-99.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/fr/index.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/fr/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/add-new-domain.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/api-versioning.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/async-use-case.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/background-tasks.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/configure-auth.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/cors.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/custom-auth-middleware.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/dependency-injection.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/domain-events.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/file-upload.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/lifespan-and-app-state.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/middleware-stack.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/new-project.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/problem-details.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/response-patterns.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/run-tests.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/soft-delete.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/sqlalchemy-repository.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/streaming.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/structured-logging.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/validation.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/webhook.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/howto/mcp-setup.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/index.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/explanation/architecture.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/explanation/design-philosophy.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/how-to/add-new-domain.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/how-to/configure-auth.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/how-to/new-project.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/how-to/run-tests.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/how-to/sqlalchemy-repository.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/howto/mcp-setup.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/index.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/reference/api.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/reference/configuration.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/reference/framework-modules.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/tutorials/first-domain.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/pt-br/index.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/pt-br/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/reference/api.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/reference/configuration.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/reference/framework-modules.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/roadmap.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/templates/field-trial-report.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/todo/current.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/tutorials/first-domain.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/zh/index.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/zh/tutorials/getting-started.md +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/package-lock.json +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/package.json +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/__main__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/app.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/entity.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/exceptions.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/handler.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/repository.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/sqlalchemy_repository.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/use_case.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/mcp.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/async_use_case.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/entity.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/exceptions.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/handler.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/repository.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/sqlalchemy_repository.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/use_case.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/schema.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/entity.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/exceptions.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/handler.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/repository.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/sqlalchemy_repository.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/use_case.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/api_key.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/bearer_token.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/deps.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/exceptions.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/interfaces.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/local_verifier.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/cache/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/cache/ttl.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/config/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/config/settings.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/database/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/database/exceptions.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/database/health.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/database/interfaces.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/database/sqlalchemy_executor.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/database/utils.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/http/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/http/etag.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/http/health.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/http/pagination.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/http/problem_details.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/log/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/log/setup.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/mcp/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/mcp/http_client.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/mcp/server.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/domain_exception.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/error_handler.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/request_id.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/request_logging.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/request_size_limit.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/security_headers.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/setup.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/throttle.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/py.typed +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/security/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/security/webhook.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/use_case/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/use_case/protocols.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/validation/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/validation/exceptions.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/scripts/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/src/scripts/export_openapi.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/conftest.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/comment/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/comment/test_comment_http.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/comment/test_comment_repository.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/comment/test_comment_use_case.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/conftest.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/note/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/note/test_async_note_use_case.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/note/test_list_notes.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/note/test_note_repository.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/tag/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/tag/test_tag_repository.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/tag/test_tags.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/test_cors.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/test_mcp.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/auth/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/auth/test_api_key.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/auth/test_bearer_token.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/auth/test_make_require_auth.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/auth/test_token_issuer.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/cache/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/cache/test_ttl.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/config/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/config/test_settings.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/database/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/database/test_transaction.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/database/test_utils.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/http/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/http/test_etag.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/http/test_health.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/http/test_pagination.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/http/test_problem_details.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/log/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/log/test_setup.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/mcp/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/mcp/test_http_client.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/mcp/test_server.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_error_handler.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_request_id.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_request_logging.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_request_size_limit.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_security_headers.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_setup_middlewares.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_simple_domain_handler.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_throttle.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/security/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/security/test_webhook.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/use_case/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/use_case/test_protocols.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/use_case/test_run_in_threadpool.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/validation/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/validation/test_exceptions.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/scripts/__init__.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/scripts/test_export_openapi.py +0 -0
- {nene2_python-1.8.36 → nene2_python-1.8.37}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nene2-python
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.37
|
|
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
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# FT166: functools モジュール
|
|
2
|
+
|
|
3
|
+
**日付**: 2026-05-21
|
|
4
|
+
**テーマ**: `functools` モジュール — `lru_cache`・`cached_property`・`partial`・`wraps`・`reduce`・`cache`
|
|
5
|
+
**セキュリティ診断**: なし(166 % 3 = 1)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 概要
|
|
10
|
+
|
|
11
|
+
Python 標準ライブラリの `functools` モジュールを nene2-python フレームワーク上で検証した。
|
|
12
|
+
`functools` は高階関数・デコレーター・メモ化のユーティリティを提供し、
|
|
13
|
+
nene2-python の DI パターン・レスポンスキャッシュ・ミドルウェア実装に直結する。
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 実装したサンプルアプリ
|
|
18
|
+
|
|
19
|
+
**場所**: `/home/xi/docker/nene2-python-FT/ft166-functools/`
|
|
20
|
+
|
|
21
|
+
### 主要機能
|
|
22
|
+
|
|
23
|
+
| 関数/クラス | 概要 |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `fibonacci(n)` | `@lru_cache(maxsize=128)` でメモ化された再帰 fibonacci |
|
|
26
|
+
| `expensive_computation(key)` | `@lru_cache(maxsize=32)` で文字列キーのキャッシュ |
|
|
27
|
+
| `HeavyComputer` | `@cached_property` で total / average を遅延計算・キャッシュ |
|
|
28
|
+
| `double / triple` | `functools.partial` で multiply の引数を固定 |
|
|
29
|
+
| `greet_hello / greet_hi` | `partial` でテンプレートと記号を固定したあいさつ生成 |
|
|
30
|
+
| `timing_decorator` | `@functools.wraps` でデコレーターが元の関数名・docstring を保持 |
|
|
31
|
+
| `product_reduce(numbers)` | `functools.reduce` で積を計算 |
|
|
32
|
+
| `flatten_reduce(nested)` | `reduce` でネストしたリストをフラット化 |
|
|
33
|
+
| `collatz_steps(n)` | `@functools.cache`(unbounded)でコラッツ数列ステップ数をメモ化 |
|
|
34
|
+
|
|
35
|
+
### HTTP エンドポイント
|
|
36
|
+
|
|
37
|
+
| メソッド | パス | 概要 |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| GET | `/functools/fibonacci` | lru_cache 付き fibonacci(キャッシュ統計返却) |
|
|
40
|
+
| GET | `/functools/lru-cache` | 任意キーのキャッシュ統計デモ |
|
|
41
|
+
| GET | `/functools/cached-property` | HeavyComputer の計算回数デモ |
|
|
42
|
+
| GET | `/functools/partial` | double / triple / greet デモ |
|
|
43
|
+
| GET | `/functools/wraps` | slow_add の __name__ 保持確認 |
|
|
44
|
+
| POST | `/functools/reduce-product` | 整数リストの積 |
|
|
45
|
+
| POST | `/functools/reduce-flatten` | ネストリストのフラット化 |
|
|
46
|
+
| GET | `/functools/cache-collatz` | unbounded cache でコラッツ数列 |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## テスト結果
|
|
51
|
+
|
|
52
|
+
**34 passed(摩擦ゼロ)**
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
34 passed in 0.83s
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 摩擦ポイント
|
|
61
|
+
|
|
62
|
+
**今回の FT では実装上の摩擦はゼロだった。**
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 観察点
|
|
67
|
+
|
|
68
|
+
### 観察1: `@lru_cache` はグローバル状態 — テスト間でキャッシュを `clear` する必要がある
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
@pytest.fixture(autouse=True)
|
|
72
|
+
def clear_caches() -> None:
|
|
73
|
+
fibonacci.cache_clear()
|
|
74
|
+
expensive_computation.cache_clear()
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`@lru_cache` の対象関数はプロセス共有のキャッシュを持つ。
|
|
78
|
+
テスト間でキャッシュが汚染されるため `autouse=True` で毎回クリアする必要がある。
|
|
79
|
+
nene2-python でキャッシュを使う UseCase は `cache_clear()` を lifespan の shutdown で呼ぶか、
|
|
80
|
+
または `@lru_cache` をクラスメソッドに適用してインスタンス単位でスコープを制御する。
|
|
81
|
+
|
|
82
|
+
### 観察2: `@cached_property` はインスタンス単位 — `lru_cache` との使い分け
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
class HeavyComputer:
|
|
86
|
+
@functools.cached_property
|
|
87
|
+
def total(self) -> int:
|
|
88
|
+
self.compute_count += 1
|
|
89
|
+
return sum(self._data)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`@cached_property` はインスタンスの `__dict__` に値を保存する。
|
|
93
|
+
同じインスタンスで 2 回目のアクセスは計算なし。新しいインスタンスは再計算。
|
|
94
|
+
`@lru_cache` はプロセス全体で共有・引数でキー管理、`@cached_property` はインスタンスで管理。
|
|
95
|
+
nene2-python での使い分け:
|
|
96
|
+
- UseCase / Repository インスタンスの設定値計算 → `@cached_property`
|
|
97
|
+
- 引数ベースの重い計算(ページネーション計算など)→ `@lru_cache`
|
|
98
|
+
|
|
99
|
+
### 観察3: `@functools.cache` = `@lru_cache(maxsize=None)` でメモリ無制限
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
@functools.cache # Python 3.9+ / unbounded
|
|
103
|
+
def collatz_steps(n: int) -> int: ...
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`@cache` は `@lru_cache(maxsize=None)` の略記で、キャッシュサイズ制限なし。
|
|
107
|
+
再帰的な数学関数に適しているが、引数の値域が大きい場合はメモリ枯渇に注意。
|
|
108
|
+
nene2-python での用途: 設定値の解析結果など、引数の種類が少ない場合に使う。
|
|
109
|
+
|
|
110
|
+
### 観察4: `functools.partial` で DI 設定をカリー化できる
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
double = functools.partial(multiply, y=2)
|
|
114
|
+
greet_hello = functools.partial(make_greeting, "Hello")
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
FastAPI の `Depends` と組み合わせる場合、`partial` でリポジトリに設定を注入できる:
|
|
118
|
+
```python
|
|
119
|
+
get_repo = functools.partial(NoteRepository, db_url=settings.db_url)
|
|
120
|
+
Depends(get_repo)
|
|
121
|
+
```
|
|
122
|
+
ただし `Depends` に渡す関数はシグネチャが重要なため、`partial` が残す引数を確認すること。
|
|
123
|
+
|
|
124
|
+
### 観察5: `@functools.wraps` なしのデコレーターは `__name__` を上書きする
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
def timing_decorator(func):
|
|
128
|
+
# @functools.wraps(func) がないと:
|
|
129
|
+
def wrapper(*args, **kwargs): ...
|
|
130
|
+
return wrapper # → slow_add.__name__ == "wrapper" になる
|
|
131
|
+
|
|
132
|
+
def timing_decorator(func):
|
|
133
|
+
@functools.wraps(func) # ← これがないと OpenAPI ルート名が壊れる
|
|
134
|
+
def wrapper(*args, **kwargs): ...
|
|
135
|
+
return wrapper
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
FastAPI はルート関数の `__name__` を operationId に使う。
|
|
139
|
+
カスタムミドルウェア・デコレーターに `@functools.wraps` がないと OpenAPI スキーマが壊れる。
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## nene2-python フレームワークとの統合
|
|
144
|
+
|
|
145
|
+
- `@lru_cache` は `TtlCache`(FT100 で追加済み)と役割が異なる(TTL なし vs TTL あり)
|
|
146
|
+
- `@cached_property` は Repository の設定パース結果のキャッシュに最適
|
|
147
|
+
- `@functools.wraps` は nene2-python の `BearerTokenMiddleware` 等のデコレーターで使用が推奨される
|
|
148
|
+
- `functools.reduce` は UseCase の集計ロジックに使えるが、`sum()` / リスト内包表記の方が可読性が高い場合が多い
|
|
149
|
+
- `@functools.cache` は設定値の解析・静的ルックアップに適している
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Developer Experience (DX) Review
|
|
154
|
+
|
|
155
|
+
### ペルソナ1: 初心者(Python 歴1年・独学中・女性・バックエンド志望)
|
|
156
|
+
|
|
157
|
+
`@lru_cache` は「デコレーターをつけるとキャッシュされる」という概念は分かりやすいが、
|
|
158
|
+
`cache_clear()` が必要なことや、グローバル共有であることは見落としやすい。
|
|
159
|
+
|
|
160
|
+
**ドキュメント理解**: `@lru_cache` のサンプルはフィボナッチが定番だが、
|
|
161
|
+
「Web API の UseCase でいつ使うか」の例がないと「難しそうなやつ」で止まる。
|
|
162
|
+
|
|
163
|
+
**事故リスク**: 中。`@lru_cache` をテストで使うときにキャッシュをクリアし忘れ、
|
|
164
|
+
他のテストのキャッシュが漏れ込んでテストが通ったり失敗したりするフレーキーなテストが生まれる。
|
|
165
|
+
|
|
166
|
+
**規約の使いやすさ**: `@functools.wraps` の必要性は理解しにくい。
|
|
167
|
+
「デコレーターを作るときは必ず `@functools.wraps` をつける」という規則を覚えれば十分。
|
|
168
|
+
|
|
169
|
+
### ペルソナ2: ロースキル経験者(Python 歴3-4年・スクリプト系・男性・SES)
|
|
170
|
+
|
|
171
|
+
`functools` は名前を知っていても使いこなせていないことが多い。
|
|
172
|
+
`reduce` は「forループで書いた方が分かる」と言って使わない傾向がある。
|
|
173
|
+
|
|
174
|
+
**コピペ可能性**: `@lru_cache(maxsize=128)` と `@functools.wraps(func)` はそのままコピペできる。
|
|
175
|
+
|
|
176
|
+
**拡張時の罠**: `@lru_cache` の引数が変わったときにキャッシュが古い値を返し続ける。
|
|
177
|
+
引数の型が mutable(`list`, `dict`)だと `TypeError: unhashable type` が発生することに気づかない。
|
|
178
|
+
|
|
179
|
+
**セキュリティ的な事故リスク**: 低。ただし `@lru_cache` に認証情報を含む引数を渡すと
|
|
180
|
+
別ユーザーのキャッシュが混入するリスクがある(BOLA の一形態)。
|
|
181
|
+
|
|
182
|
+
### ペルソナ3: フロントエンド寄り経験者(React/TS 歴4年・バックエンド転向中・ノンバイナリ)
|
|
183
|
+
|
|
184
|
+
`useMemo` / `useCallback` と `@lru_cache` / `@cached_property` は概念が近い。
|
|
185
|
+
「同じ入力なら再計算しない」という理解はすでにある。
|
|
186
|
+
|
|
187
|
+
**Python 固有概念の学習コスト**: `partial` は JS の `bind` や `curry` に近い概念。
|
|
188
|
+
`reduce` は `Array.prototype.reduce` と同じ。TypeScript ユーザーには直感的。
|
|
189
|
+
|
|
190
|
+
**事故リスク**: 低。
|
|
191
|
+
|
|
192
|
+
### ペルソナ4: バックエンド経験者(Django/FastAPI 歴5-6年・男性・リードエンジニア)
|
|
193
|
+
|
|
194
|
+
Django の `@method_decorator` / `cache_page` との差異を理解している。
|
|
195
|
+
`@functools.wraps` は既知。`@lru_cache` の eviction ポリシー(LRU)を正確に理解している。
|
|
196
|
+
|
|
197
|
+
**他フレームワークとの差異**: Django は `cache.get/set` で明示的にキャッシュを管理する。
|
|
198
|
+
nene2-python で `@lru_cache` を使う場合、TTL がないことを意識する必要がある。
|
|
199
|
+
TTL が必要なら FT100 で追加した `TtlCache` を使う。
|
|
200
|
+
|
|
201
|
+
**本番投入可能性**: 問題なし。ただしキャッシュキーのサイズとメモリ消費量の設計が必要。
|
|
202
|
+
|
|
203
|
+
### ペルソナ5: シニアエンジニア(設計・コードレビュー担当・女性・10-12年)
|
|
204
|
+
|
|
205
|
+
**コードレビューチェックポイント**:
|
|
206
|
+
- [ ] `@lru_cache` / `@cache` の引数に mutable 型(list, dict)が渡されていないか(`TypeError` になる)
|
|
207
|
+
- [ ] `@lru_cache` をリクエストスコープで使っていないか(プロセス共有で期待外の値が返る)
|
|
208
|
+
- [ ] `@lru_cache` に認証情報・ユーザーIDが引数に含まれる場合、BOLA にならないか
|
|
209
|
+
- [ ] デコレーターに `@functools.wraps` がついているか(OpenAPI operationId の破損防止)
|
|
210
|
+
- [ ] `@cache`(unbounded)を使う場合、引数の値域が有限か(メモリリーク防止)
|
|
211
|
+
|
|
212
|
+
**チームでの安全なパターン**: キャッシュが必要な UseCase は `cache_clear()` を公開メソッドとして持ち、
|
|
213
|
+
lifespan の shutdown / テストの teardown で明示的にクリアする規約を設ける。
|
|
214
|
+
|
|
215
|
+
### ペルソナ6: 設計者・ポリシー照合(nene2-python 設計ポリシー目線)
|
|
216
|
+
|
|
217
|
+
**ポリシー達成度**: 高
|
|
218
|
+
|
|
219
|
+
**「初心者でも安全な API」達成度**: 中
|
|
220
|
+
- `@lru_cache` のキャッシュ汚染リスク(テスト・BOLA)をドキュメントが説明していない
|
|
221
|
+
- `@functools.wraps` の必要性が CLAUDE.md に明記されていない(FastAPI との相性問題)
|
|
222
|
+
|
|
223
|
+
**設計上の負債・ドキュメント不足**:
|
|
224
|
+
- nene2-python のカスタムデコレーター作成時の `@functools.wraps` 使用がポリシー化されていない
|
|
225
|
+
- `@lru_cache` の「リクエストスコープ不可・認証情報を引数に含めない」ルールが未文書
|
|
226
|
+
|
|
227
|
+
**Follow-up Issue 候補**: `docs: functools.wraps をカスタムデコレーター規約に追加`
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Follow-up Issues
|
|
232
|
+
|
|
233
|
+
| 優先度 | タイトル | 種別 |
|
|
234
|
+
|---|---|---|
|
|
235
|
+
| 中 | `docs: @functools.wraps をデコレーター作成規約として CLAUDE.md に追加` | docs |
|
|
236
|
+
| 低 | `docs: @lru_cache のリクエストスコープ不可・認証情報禁止をキャッシュ how-to に記載` | docs |
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## まとめ
|
|
241
|
+
|
|
242
|
+
`functools` は nene2-python の DI・キャッシュ・デコレーター実装に広く関連するモジュール。
|
|
243
|
+
34 テスト全通過、摩擦ゼロ。
|
|
244
|
+
`@cached_property` がインスタンス単位、`@lru_cache` がプロセス単位という使い分けが重要。
|
|
245
|
+
`@functools.wraps` なしのデコレーターは FastAPI の operationId を破壊するため、
|
|
246
|
+
カスタムデコレーター規約への追記が推奨される。
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nene2_python-1.8.36 → nene2_python-1.8.37}/alembic/versions/001_create_notes_and_tags_tables.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|