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.
Files changed (387) hide show
  1. {nene2_python-1.8.36 → nene2_python-1.8.37}/PKG-INFO +1 -1
  2. nene2_python-1.8.37/docs/field-trials/2026-05-field-trial-166.md +246 -0
  3. {nene2_python-1.8.36 → nene2_python-1.8.37}/pyproject.toml +1 -1
  4. {nene2_python-1.8.36 → nene2_python-1.8.37}/.env.example +0 -0
  5. {nene2_python-1.8.36 → nene2_python-1.8.37}/.github/workflows/ci.yml +0 -0
  6. {nene2_python-1.8.36 → nene2_python-1.8.37}/.github/workflows/docs.yml +0 -0
  7. {nene2_python-1.8.36 → nene2_python-1.8.37}/.github/workflows/publish.yml +0 -0
  8. {nene2_python-1.8.36 → nene2_python-1.8.37}/.gitignore +0 -0
  9. {nene2_python-1.8.36 → nene2_python-1.8.37}/.vitepress/config.mts +0 -0
  10. {nene2_python-1.8.36 → nene2_python-1.8.37}/.vitepress/theme/custom.css +0 -0
  11. {nene2_python-1.8.36 → nene2_python-1.8.37}/.vitepress/theme/index.ts +0 -0
  12. {nene2_python-1.8.36 → nene2_python-1.8.37}/AGENTS.md +0 -0
  13. {nene2_python-1.8.36 → nene2_python-1.8.37}/CHANGELOG.md +0 -0
  14. {nene2_python-1.8.36 → nene2_python-1.8.37}/CLAUDE.md +0 -0
  15. {nene2_python-1.8.36 → nene2_python-1.8.37}/Dockerfile +0 -0
  16. {nene2_python-1.8.36 → nene2_python-1.8.37}/LICENSE +0 -0
  17. {nene2_python-1.8.36 → nene2_python-1.8.37}/README.md +0 -0
  18. {nene2_python-1.8.36 → nene2_python-1.8.37}/alembic/README +0 -0
  19. {nene2_python-1.8.36 → nene2_python-1.8.37}/alembic/env.py +0 -0
  20. {nene2_python-1.8.36 → nene2_python-1.8.37}/alembic/script.py.mako +0 -0
  21. {nene2_python-1.8.36 → nene2_python-1.8.37}/alembic/versions/001_create_notes_and_tags_tables.py +0 -0
  22. {nene2_python-1.8.36 → nene2_python-1.8.37}/alembic.ini +0 -0
  23. {nene2_python-1.8.36 → nene2_python-1.8.37}/compose.yaml +0 -0
  24. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0001-toolchain.md +0 -0
  25. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0002-clean-architecture.md +0 -0
  26. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0003-security-first.md +0 -0
  27. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0004-ai-first-design.md +0 -0
  28. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0005-logging.md +0 -0
  29. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0006-rate-limiting.md +0 -0
  30. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0009-mcp-design.md +0 -0
  31. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0010-async-use-case.md +0 -0
  32. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/adr/0011-mcp-as-core-dependency.md +0 -0
  33. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/de/index.md +0 -0
  34. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/de/tutorials/getting-started.md +0 -0
  35. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/explanation/architecture.md +0 -0
  36. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/explanation/design-philosophy.md +0 -0
  37. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-1.md +0 -0
  38. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-10.md +0 -0
  39. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-100.md +0 -0
  40. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-101.md +0 -0
  41. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-102.md +0 -0
  42. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-103.md +0 -0
  43. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-104.md +0 -0
  44. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-105.md +0 -0
  45. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-106.md +0 -0
  46. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-107.md +0 -0
  47. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-108.md +0 -0
  48. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-109.md +0 -0
  49. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-11.md +0 -0
  50. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-110.md +0 -0
  51. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-111.md +0 -0
  52. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-112.md +0 -0
  53. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-113.md +0 -0
  54. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-114.md +0 -0
  55. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-115.md +0 -0
  56. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-116.md +0 -0
  57. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-117.md +0 -0
  58. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-118.md +0 -0
  59. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-119.md +0 -0
  60. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-12.md +0 -0
  61. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-120.md +0 -0
  62. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-121.md +0 -0
  63. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-122.md +0 -0
  64. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-123.md +0 -0
  65. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-124.md +0 -0
  66. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-125.md +0 -0
  67. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-126.md +0 -0
  68. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-127.md +0 -0
  69. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-128.md +0 -0
  70. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-129.md +0 -0
  71. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-13.md +0 -0
  72. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-130.md +0 -0
  73. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-131.md +0 -0
  74. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-132.md +0 -0
  75. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-133.md +0 -0
  76. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-134.md +0 -0
  77. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-135.md +0 -0
  78. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-136.md +0 -0
  79. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-137.md +0 -0
  80. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-138.md +0 -0
  81. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-139.md +0 -0
  82. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-14.md +0 -0
  83. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-140.md +0 -0
  84. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-141.md +0 -0
  85. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-142.md +0 -0
  86. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-143.md +0 -0
  87. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-144.md +0 -0
  88. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-145.md +0 -0
  89. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-146.md +0 -0
  90. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-147.md +0 -0
  91. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-148.md +0 -0
  92. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-149.md +0 -0
  93. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-15.md +0 -0
  94. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-150.md +0 -0
  95. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-151.md +0 -0
  96. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-152.md +0 -0
  97. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-153.md +0 -0
  98. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-154.md +0 -0
  99. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-155.md +0 -0
  100. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-156.md +0 -0
  101. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-157.md +0 -0
  102. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-158.md +0 -0
  103. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-159.md +0 -0
  104. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-16.md +0 -0
  105. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-160.md +0 -0
  106. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-161.md +0 -0
  107. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-162.md +0 -0
  108. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-163.md +0 -0
  109. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-164.md +0 -0
  110. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-165.md +0 -0
  111. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-17.md +0 -0
  112. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-18.md +0 -0
  113. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-19.md +0 -0
  114. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-2.md +0 -0
  115. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-20.md +0 -0
  116. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-21.md +0 -0
  117. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-22.md +0 -0
  118. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-23.md +0 -0
  119. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-24.md +0 -0
  120. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-25.md +0 -0
  121. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-26.md +0 -0
  122. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-27.md +0 -0
  123. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-28.md +0 -0
  124. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-29.md +0 -0
  125. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-3.md +0 -0
  126. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-30.md +0 -0
  127. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-31.md +0 -0
  128. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-32.md +0 -0
  129. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-33.md +0 -0
  130. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-34.md +0 -0
  131. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-35.md +0 -0
  132. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-36.md +0 -0
  133. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-37.md +0 -0
  134. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-38.md +0 -0
  135. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-39.md +0 -0
  136. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-4.md +0 -0
  137. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-40.md +0 -0
  138. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-41.md +0 -0
  139. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-42.md +0 -0
  140. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-43.md +0 -0
  141. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-44.md +0 -0
  142. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-45.md +0 -0
  143. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-46.md +0 -0
  144. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-47.md +0 -0
  145. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-48.md +0 -0
  146. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-49.md +0 -0
  147. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-5.md +0 -0
  148. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-50.md +0 -0
  149. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-51.md +0 -0
  150. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-52.md +0 -0
  151. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-53.md +0 -0
  152. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-54.md +0 -0
  153. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-55.md +0 -0
  154. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-56.md +0 -0
  155. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-57.md +0 -0
  156. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-58.md +0 -0
  157. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-59.md +0 -0
  158. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-6.md +0 -0
  159. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-60.md +0 -0
  160. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-61.md +0 -0
  161. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-62.md +0 -0
  162. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-63.md +0 -0
  163. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-64.md +0 -0
  164. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-65.md +0 -0
  165. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-66.md +0 -0
  166. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-67.md +0 -0
  167. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-68.md +0 -0
  168. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-69.md +0 -0
  169. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-7.md +0 -0
  170. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-70.md +0 -0
  171. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-71.md +0 -0
  172. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-72.md +0 -0
  173. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-73.md +0 -0
  174. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-74.md +0 -0
  175. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-75.md +0 -0
  176. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-76.md +0 -0
  177. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-77.md +0 -0
  178. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-78.md +0 -0
  179. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-79.md +0 -0
  180. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-8.md +0 -0
  181. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-80.md +0 -0
  182. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-81.md +0 -0
  183. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-82.md +0 -0
  184. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-83.md +0 -0
  185. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-84.md +0 -0
  186. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-85.md +0 -0
  187. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-86.md +0 -0
  188. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-87.md +0 -0
  189. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-88.md +0 -0
  190. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-89.md +0 -0
  191. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-9.md +0 -0
  192. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-90.md +0 -0
  193. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-91.md +0 -0
  194. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-92.md +0 -0
  195. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-93.md +0 -0
  196. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-94.md +0 -0
  197. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-95.md +0 -0
  198. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-96.md +0 -0
  199. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-97.md +0 -0
  200. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-98.md +0 -0
  201. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/field-trials/2026-05-field-trial-99.md +0 -0
  202. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/fr/index.md +0 -0
  203. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/fr/tutorials/getting-started.md +0 -0
  204. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/add-new-domain.md +0 -0
  205. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/api-versioning.md +0 -0
  206. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/async-use-case.md +0 -0
  207. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/background-tasks.md +0 -0
  208. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/configure-auth.md +0 -0
  209. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/cors.md +0 -0
  210. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/custom-auth-middleware.md +0 -0
  211. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/dependency-injection.md +0 -0
  212. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/domain-events.md +0 -0
  213. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/file-upload.md +0 -0
  214. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/lifespan-and-app-state.md +0 -0
  215. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/middleware-stack.md +0 -0
  216. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/new-project.md +0 -0
  217. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/problem-details.md +0 -0
  218. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/response-patterns.md +0 -0
  219. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/run-tests.md +0 -0
  220. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/soft-delete.md +0 -0
  221. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/sqlalchemy-repository.md +0 -0
  222. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/streaming.md +0 -0
  223. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/structured-logging.md +0 -0
  224. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/validation.md +0 -0
  225. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/how-to/webhook.md +0 -0
  226. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/howto/mcp-setup.md +0 -0
  227. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/index.md +0 -0
  228. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/explanation/architecture.md +0 -0
  229. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/explanation/design-philosophy.md +0 -0
  230. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/how-to/add-new-domain.md +0 -0
  231. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/how-to/configure-auth.md +0 -0
  232. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/how-to/new-project.md +0 -0
  233. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/how-to/run-tests.md +0 -0
  234. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/how-to/sqlalchemy-repository.md +0 -0
  235. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/howto/mcp-setup.md +0 -0
  236. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/index.md +0 -0
  237. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/reference/api.md +0 -0
  238. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/reference/configuration.md +0 -0
  239. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/reference/framework-modules.md +0 -0
  240. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/tutorials/first-domain.md +0 -0
  241. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/ja/tutorials/getting-started.md +0 -0
  242. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/pt-br/index.md +0 -0
  243. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/pt-br/tutorials/getting-started.md +0 -0
  244. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/reference/api.md +0 -0
  245. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/reference/configuration.md +0 -0
  246. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/reference/framework-modules.md +0 -0
  247. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/roadmap.md +0 -0
  248. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/templates/field-trial-report.md +0 -0
  249. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/todo/current.md +0 -0
  250. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/tutorials/first-domain.md +0 -0
  251. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/tutorials/getting-started.md +0 -0
  252. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/zh/index.md +0 -0
  253. {nene2_python-1.8.36 → nene2_python-1.8.37}/docs/zh/tutorials/getting-started.md +0 -0
  254. {nene2_python-1.8.36 → nene2_python-1.8.37}/package-lock.json +0 -0
  255. {nene2_python-1.8.36 → nene2_python-1.8.37}/package.json +0 -0
  256. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/__init__.py +0 -0
  257. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/__main__.py +0 -0
  258. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/app.py +0 -0
  259. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/__init__.py +0 -0
  260. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/entity.py +0 -0
  261. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/exceptions.py +0 -0
  262. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/handler.py +0 -0
  263. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/repository.py +0 -0
  264. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/sqlalchemy_repository.py +0 -0
  265. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/comment/use_case.py +0 -0
  266. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/mcp.py +0 -0
  267. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/__init__.py +0 -0
  268. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/async_use_case.py +0 -0
  269. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/entity.py +0 -0
  270. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/exceptions.py +0 -0
  271. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/handler.py +0 -0
  272. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/repository.py +0 -0
  273. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/sqlalchemy_repository.py +0 -0
  274. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/note/use_case.py +0 -0
  275. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/schema.py +0 -0
  276. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/__init__.py +0 -0
  277. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/entity.py +0 -0
  278. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/exceptions.py +0 -0
  279. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/handler.py +0 -0
  280. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/repository.py +0 -0
  281. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/sqlalchemy_repository.py +0 -0
  282. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/example/tag/use_case.py +0 -0
  283. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/__init__.py +0 -0
  284. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/__init__.py +0 -0
  285. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/api_key.py +0 -0
  286. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/bearer_token.py +0 -0
  287. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/deps.py +0 -0
  288. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/exceptions.py +0 -0
  289. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/interfaces.py +0 -0
  290. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/auth/local_verifier.py +0 -0
  291. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/cache/__init__.py +0 -0
  292. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/cache/ttl.py +0 -0
  293. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/config/__init__.py +0 -0
  294. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/config/settings.py +0 -0
  295. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/database/__init__.py +0 -0
  296. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/database/exceptions.py +0 -0
  297. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/database/health.py +0 -0
  298. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/database/interfaces.py +0 -0
  299. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/database/sqlalchemy_executor.py +0 -0
  300. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/database/utils.py +0 -0
  301. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/http/__init__.py +0 -0
  302. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/http/etag.py +0 -0
  303. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/http/health.py +0 -0
  304. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/http/pagination.py +0 -0
  305. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/http/problem_details.py +0 -0
  306. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/log/__init__.py +0 -0
  307. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/log/setup.py +0 -0
  308. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/mcp/__init__.py +0 -0
  309. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/mcp/http_client.py +0 -0
  310. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/mcp/server.py +0 -0
  311. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/__init__.py +0 -0
  312. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/domain_exception.py +0 -0
  313. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/error_handler.py +0 -0
  314. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/request_id.py +0 -0
  315. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/request_logging.py +0 -0
  316. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/request_size_limit.py +0 -0
  317. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/security_headers.py +0 -0
  318. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/setup.py +0 -0
  319. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/middleware/throttle.py +0 -0
  320. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/py.typed +0 -0
  321. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/security/__init__.py +0 -0
  322. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/security/webhook.py +0 -0
  323. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/use_case/__init__.py +0 -0
  324. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/use_case/protocols.py +0 -0
  325. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/validation/__init__.py +0 -0
  326. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/nene2/validation/exceptions.py +0 -0
  327. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/scripts/__init__.py +0 -0
  328. {nene2_python-1.8.36 → nene2_python-1.8.37}/src/scripts/export_openapi.py +0 -0
  329. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/__init__.py +0 -0
  330. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/conftest.py +0 -0
  331. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/__init__.py +0 -0
  332. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/comment/__init__.py +0 -0
  333. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/comment/test_comment_http.py +0 -0
  334. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/comment/test_comment_repository.py +0 -0
  335. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/comment/test_comment_use_case.py +0 -0
  336. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/conftest.py +0 -0
  337. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/note/__init__.py +0 -0
  338. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/note/test_async_note_use_case.py +0 -0
  339. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/note/test_list_notes.py +0 -0
  340. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/note/test_note_repository.py +0 -0
  341. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/tag/__init__.py +0 -0
  342. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/tag/test_tag_repository.py +0 -0
  343. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/tag/test_tags.py +0 -0
  344. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/test_cors.py +0 -0
  345. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/example/test_mcp.py +0 -0
  346. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/__init__.py +0 -0
  347. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/auth/__init__.py +0 -0
  348. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/auth/test_api_key.py +0 -0
  349. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/auth/test_bearer_token.py +0 -0
  350. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/auth/test_make_require_auth.py +0 -0
  351. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/auth/test_token_issuer.py +0 -0
  352. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/cache/__init__.py +0 -0
  353. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/cache/test_ttl.py +0 -0
  354. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/config/__init__.py +0 -0
  355. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/config/test_settings.py +0 -0
  356. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/database/__init__.py +0 -0
  357. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/database/test_transaction.py +0 -0
  358. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/database/test_utils.py +0 -0
  359. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/http/__init__.py +0 -0
  360. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/http/test_etag.py +0 -0
  361. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/http/test_health.py +0 -0
  362. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/http/test_pagination.py +0 -0
  363. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/http/test_problem_details.py +0 -0
  364. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/log/__init__.py +0 -0
  365. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/log/test_setup.py +0 -0
  366. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/mcp/__init__.py +0 -0
  367. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/mcp/test_http_client.py +0 -0
  368. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/mcp/test_server.py +0 -0
  369. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/__init__.py +0 -0
  370. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_error_handler.py +0 -0
  371. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_request_id.py +0 -0
  372. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_request_logging.py +0 -0
  373. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_request_size_limit.py +0 -0
  374. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_security_headers.py +0 -0
  375. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_setup_middlewares.py +0 -0
  376. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_simple_domain_handler.py +0 -0
  377. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/middleware/test_throttle.py +0 -0
  378. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/security/__init__.py +0 -0
  379. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/security/test_webhook.py +0 -0
  380. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/use_case/__init__.py +0 -0
  381. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/use_case/test_protocols.py +0 -0
  382. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/use_case/test_run_in_threadpool.py +0 -0
  383. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/validation/__init__.py +0 -0
  384. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/nene2/validation/test_exceptions.py +0 -0
  385. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/scripts/__init__.py +0 -0
  386. {nene2_python-1.8.36 → nene2_python-1.8.37}/tests/scripts/test_export_openapi.py +0 -0
  387. {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.36
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
+ カスタムデコレーター規約への追記が推奨される。
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nene2-python"
3
- version = "1.8.36"
3
+ version = "1.8.37"
4
4
  description = "NENE2 Python — minimal API framework following NENE2's design philosophy"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes