nene2-python 1.8.40__tar.gz → 1.8.41__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 (391) hide show
  1. {nene2_python-1.8.40 → nene2_python-1.8.41}/PKG-INFO +1 -1
  2. nene2_python-1.8.41/docs/field-trials/2026-05-field-trial-170.md +242 -0
  3. {nene2_python-1.8.40 → nene2_python-1.8.41}/pyproject.toml +1 -1
  4. {nene2_python-1.8.40 → nene2_python-1.8.41}/uv.lock +1 -1
  5. {nene2_python-1.8.40 → nene2_python-1.8.41}/.env.example +0 -0
  6. {nene2_python-1.8.40 → nene2_python-1.8.41}/.github/workflows/ci.yml +0 -0
  7. {nene2_python-1.8.40 → nene2_python-1.8.41}/.github/workflows/docs.yml +0 -0
  8. {nene2_python-1.8.40 → nene2_python-1.8.41}/.github/workflows/publish.yml +0 -0
  9. {nene2_python-1.8.40 → nene2_python-1.8.41}/.gitignore +0 -0
  10. {nene2_python-1.8.40 → nene2_python-1.8.41}/.vitepress/config.mts +0 -0
  11. {nene2_python-1.8.40 → nene2_python-1.8.41}/.vitepress/theme/custom.css +0 -0
  12. {nene2_python-1.8.40 → nene2_python-1.8.41}/.vitepress/theme/index.ts +0 -0
  13. {nene2_python-1.8.40 → nene2_python-1.8.41}/AGENTS.md +0 -0
  14. {nene2_python-1.8.40 → nene2_python-1.8.41}/CHANGELOG.md +0 -0
  15. {nene2_python-1.8.40 → nene2_python-1.8.41}/CLAUDE.md +0 -0
  16. {nene2_python-1.8.40 → nene2_python-1.8.41}/Dockerfile +0 -0
  17. {nene2_python-1.8.40 → nene2_python-1.8.41}/LICENSE +0 -0
  18. {nene2_python-1.8.40 → nene2_python-1.8.41}/README.md +0 -0
  19. {nene2_python-1.8.40 → nene2_python-1.8.41}/alembic/README +0 -0
  20. {nene2_python-1.8.40 → nene2_python-1.8.41}/alembic/env.py +0 -0
  21. {nene2_python-1.8.40 → nene2_python-1.8.41}/alembic/script.py.mako +0 -0
  22. {nene2_python-1.8.40 → nene2_python-1.8.41}/alembic/versions/001_create_notes_and_tags_tables.py +0 -0
  23. {nene2_python-1.8.40 → nene2_python-1.8.41}/alembic.ini +0 -0
  24. {nene2_python-1.8.40 → nene2_python-1.8.41}/compose.yaml +0 -0
  25. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/adr/0001-toolchain.md +0 -0
  26. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/adr/0002-clean-architecture.md +0 -0
  27. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/adr/0003-security-first.md +0 -0
  28. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/adr/0004-ai-first-design.md +0 -0
  29. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/adr/0005-logging.md +0 -0
  30. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/adr/0006-rate-limiting.md +0 -0
  31. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/adr/0009-mcp-design.md +0 -0
  32. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/adr/0010-async-use-case.md +0 -0
  33. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/adr/0011-mcp-as-core-dependency.md +0 -0
  34. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/de/index.md +0 -0
  35. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/de/tutorials/getting-started.md +0 -0
  36. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/explanation/architecture.md +0 -0
  37. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/explanation/design-philosophy.md +0 -0
  38. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-1.md +0 -0
  39. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-10.md +0 -0
  40. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-100.md +0 -0
  41. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-101.md +0 -0
  42. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-102.md +0 -0
  43. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-103.md +0 -0
  44. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-104.md +0 -0
  45. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-105.md +0 -0
  46. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-106.md +0 -0
  47. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-107.md +0 -0
  48. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-108.md +0 -0
  49. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-109.md +0 -0
  50. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-11.md +0 -0
  51. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-110.md +0 -0
  52. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-111.md +0 -0
  53. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-112.md +0 -0
  54. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-113.md +0 -0
  55. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-114.md +0 -0
  56. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-115.md +0 -0
  57. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-116.md +0 -0
  58. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-117.md +0 -0
  59. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-118.md +0 -0
  60. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-119.md +0 -0
  61. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-12.md +0 -0
  62. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-120.md +0 -0
  63. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-121.md +0 -0
  64. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-122.md +0 -0
  65. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-123.md +0 -0
  66. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-124.md +0 -0
  67. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-125.md +0 -0
  68. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-126.md +0 -0
  69. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-127.md +0 -0
  70. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-128.md +0 -0
  71. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-129.md +0 -0
  72. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-13.md +0 -0
  73. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-130.md +0 -0
  74. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-131.md +0 -0
  75. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-132.md +0 -0
  76. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-133.md +0 -0
  77. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-134.md +0 -0
  78. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-135.md +0 -0
  79. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-136.md +0 -0
  80. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-137.md +0 -0
  81. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-138.md +0 -0
  82. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-139.md +0 -0
  83. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-14.md +0 -0
  84. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-140.md +0 -0
  85. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-141.md +0 -0
  86. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-142.md +0 -0
  87. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-143.md +0 -0
  88. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-144.md +0 -0
  89. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-145.md +0 -0
  90. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-146.md +0 -0
  91. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-147.md +0 -0
  92. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-148.md +0 -0
  93. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-149.md +0 -0
  94. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-15.md +0 -0
  95. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-150.md +0 -0
  96. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-151.md +0 -0
  97. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-152.md +0 -0
  98. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-153.md +0 -0
  99. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-154.md +0 -0
  100. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-155.md +0 -0
  101. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-156.md +0 -0
  102. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-157.md +0 -0
  103. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-158.md +0 -0
  104. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-159.md +0 -0
  105. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-16.md +0 -0
  106. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-160.md +0 -0
  107. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-161.md +0 -0
  108. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-162.md +0 -0
  109. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-163.md +0 -0
  110. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-164.md +0 -0
  111. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-165.md +0 -0
  112. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-166.md +0 -0
  113. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-167.md +0 -0
  114. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-168.md +0 -0
  115. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-169.md +0 -0
  116. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-17.md +0 -0
  117. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-18.md +0 -0
  118. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-19.md +0 -0
  119. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-2.md +0 -0
  120. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-20.md +0 -0
  121. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-21.md +0 -0
  122. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-22.md +0 -0
  123. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-23.md +0 -0
  124. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-24.md +0 -0
  125. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-25.md +0 -0
  126. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-26.md +0 -0
  127. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-27.md +0 -0
  128. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-28.md +0 -0
  129. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-29.md +0 -0
  130. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-3.md +0 -0
  131. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-30.md +0 -0
  132. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-31.md +0 -0
  133. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-32.md +0 -0
  134. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-33.md +0 -0
  135. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-34.md +0 -0
  136. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-35.md +0 -0
  137. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-36.md +0 -0
  138. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-37.md +0 -0
  139. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-38.md +0 -0
  140. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-39.md +0 -0
  141. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-4.md +0 -0
  142. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-40.md +0 -0
  143. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-41.md +0 -0
  144. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-42.md +0 -0
  145. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-43.md +0 -0
  146. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-44.md +0 -0
  147. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-45.md +0 -0
  148. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-46.md +0 -0
  149. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-47.md +0 -0
  150. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-48.md +0 -0
  151. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-49.md +0 -0
  152. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-5.md +0 -0
  153. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-50.md +0 -0
  154. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-51.md +0 -0
  155. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-52.md +0 -0
  156. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-53.md +0 -0
  157. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-54.md +0 -0
  158. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-55.md +0 -0
  159. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-56.md +0 -0
  160. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-57.md +0 -0
  161. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-58.md +0 -0
  162. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-59.md +0 -0
  163. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-6.md +0 -0
  164. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-60.md +0 -0
  165. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-61.md +0 -0
  166. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-62.md +0 -0
  167. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-63.md +0 -0
  168. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-64.md +0 -0
  169. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-65.md +0 -0
  170. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-66.md +0 -0
  171. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-67.md +0 -0
  172. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-68.md +0 -0
  173. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-69.md +0 -0
  174. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-7.md +0 -0
  175. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-70.md +0 -0
  176. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-71.md +0 -0
  177. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-72.md +0 -0
  178. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-73.md +0 -0
  179. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-74.md +0 -0
  180. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-75.md +0 -0
  181. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-76.md +0 -0
  182. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-77.md +0 -0
  183. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-78.md +0 -0
  184. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-79.md +0 -0
  185. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-8.md +0 -0
  186. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-80.md +0 -0
  187. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-81.md +0 -0
  188. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-82.md +0 -0
  189. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-83.md +0 -0
  190. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-84.md +0 -0
  191. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-85.md +0 -0
  192. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-86.md +0 -0
  193. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-87.md +0 -0
  194. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-88.md +0 -0
  195. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-89.md +0 -0
  196. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-9.md +0 -0
  197. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-90.md +0 -0
  198. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-91.md +0 -0
  199. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-92.md +0 -0
  200. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-93.md +0 -0
  201. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-94.md +0 -0
  202. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-95.md +0 -0
  203. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-96.md +0 -0
  204. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-97.md +0 -0
  205. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-98.md +0 -0
  206. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/field-trials/2026-05-field-trial-99.md +0 -0
  207. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/fr/index.md +0 -0
  208. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/fr/tutorials/getting-started.md +0 -0
  209. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/add-new-domain.md +0 -0
  210. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/api-versioning.md +0 -0
  211. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/async-use-case.md +0 -0
  212. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/background-tasks.md +0 -0
  213. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/configure-auth.md +0 -0
  214. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/cors.md +0 -0
  215. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/custom-auth-middleware.md +0 -0
  216. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/dependency-injection.md +0 -0
  217. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/domain-events.md +0 -0
  218. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/file-upload.md +0 -0
  219. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/lifespan-and-app-state.md +0 -0
  220. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/middleware-stack.md +0 -0
  221. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/new-project.md +0 -0
  222. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/problem-details.md +0 -0
  223. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/response-patterns.md +0 -0
  224. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/run-tests.md +0 -0
  225. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/soft-delete.md +0 -0
  226. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/sqlalchemy-repository.md +0 -0
  227. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/streaming.md +0 -0
  228. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/structured-logging.md +0 -0
  229. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/validation.md +0 -0
  230. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/how-to/webhook.md +0 -0
  231. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/howto/mcp-setup.md +0 -0
  232. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/index.md +0 -0
  233. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/explanation/architecture.md +0 -0
  234. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/explanation/design-philosophy.md +0 -0
  235. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/how-to/add-new-domain.md +0 -0
  236. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/how-to/configure-auth.md +0 -0
  237. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/how-to/new-project.md +0 -0
  238. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/how-to/run-tests.md +0 -0
  239. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/how-to/sqlalchemy-repository.md +0 -0
  240. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/howto/mcp-setup.md +0 -0
  241. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/index.md +0 -0
  242. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/reference/api.md +0 -0
  243. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/reference/configuration.md +0 -0
  244. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/reference/framework-modules.md +0 -0
  245. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/tutorials/first-domain.md +0 -0
  246. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/ja/tutorials/getting-started.md +0 -0
  247. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/pt-br/index.md +0 -0
  248. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/pt-br/tutorials/getting-started.md +0 -0
  249. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/reference/api.md +0 -0
  250. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/reference/configuration.md +0 -0
  251. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/reference/framework-modules.md +0 -0
  252. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/roadmap.md +0 -0
  253. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/templates/field-trial-report.md +0 -0
  254. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/todo/current.md +0 -0
  255. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/tutorials/first-domain.md +0 -0
  256. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/tutorials/getting-started.md +0 -0
  257. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/zh/index.md +0 -0
  258. {nene2_python-1.8.40 → nene2_python-1.8.41}/docs/zh/tutorials/getting-started.md +0 -0
  259. {nene2_python-1.8.40 → nene2_python-1.8.41}/package-lock.json +0 -0
  260. {nene2_python-1.8.40 → nene2_python-1.8.41}/package.json +0 -0
  261. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/__init__.py +0 -0
  262. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/__main__.py +0 -0
  263. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/app.py +0 -0
  264. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/comment/__init__.py +0 -0
  265. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/comment/entity.py +0 -0
  266. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/comment/exceptions.py +0 -0
  267. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/comment/handler.py +0 -0
  268. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/comment/repository.py +0 -0
  269. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/comment/sqlalchemy_repository.py +0 -0
  270. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/comment/use_case.py +0 -0
  271. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/mcp.py +0 -0
  272. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/note/__init__.py +0 -0
  273. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/note/async_use_case.py +0 -0
  274. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/note/entity.py +0 -0
  275. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/note/exceptions.py +0 -0
  276. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/note/handler.py +0 -0
  277. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/note/repository.py +0 -0
  278. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/note/sqlalchemy_repository.py +0 -0
  279. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/note/use_case.py +0 -0
  280. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/schema.py +0 -0
  281. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/tag/__init__.py +0 -0
  282. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/tag/entity.py +0 -0
  283. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/tag/exceptions.py +0 -0
  284. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/tag/handler.py +0 -0
  285. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/tag/repository.py +0 -0
  286. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/tag/sqlalchemy_repository.py +0 -0
  287. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/example/tag/use_case.py +0 -0
  288. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/__init__.py +0 -0
  289. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/auth/__init__.py +0 -0
  290. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/auth/api_key.py +0 -0
  291. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/auth/bearer_token.py +0 -0
  292. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/auth/deps.py +0 -0
  293. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/auth/exceptions.py +0 -0
  294. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/auth/interfaces.py +0 -0
  295. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/auth/local_verifier.py +0 -0
  296. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/cache/__init__.py +0 -0
  297. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/cache/ttl.py +0 -0
  298. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/config/__init__.py +0 -0
  299. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/config/settings.py +0 -0
  300. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/database/__init__.py +0 -0
  301. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/database/exceptions.py +0 -0
  302. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/database/health.py +0 -0
  303. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/database/interfaces.py +0 -0
  304. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/database/sqlalchemy_executor.py +0 -0
  305. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/database/utils.py +0 -0
  306. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/http/__init__.py +0 -0
  307. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/http/etag.py +0 -0
  308. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/http/health.py +0 -0
  309. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/http/pagination.py +0 -0
  310. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/http/problem_details.py +0 -0
  311. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/log/__init__.py +0 -0
  312. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/log/setup.py +0 -0
  313. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/mcp/__init__.py +0 -0
  314. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/mcp/http_client.py +0 -0
  315. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/mcp/server.py +0 -0
  316. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/middleware/__init__.py +0 -0
  317. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/middleware/domain_exception.py +0 -0
  318. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/middleware/error_handler.py +0 -0
  319. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/middleware/request_id.py +0 -0
  320. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/middleware/request_logging.py +0 -0
  321. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/middleware/request_size_limit.py +0 -0
  322. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/middleware/security_headers.py +0 -0
  323. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/middleware/setup.py +0 -0
  324. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/middleware/throttle.py +0 -0
  325. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/py.typed +0 -0
  326. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/security/__init__.py +0 -0
  327. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/security/webhook.py +0 -0
  328. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/use_case/__init__.py +0 -0
  329. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/use_case/protocols.py +0 -0
  330. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/validation/__init__.py +0 -0
  331. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/nene2/validation/exceptions.py +0 -0
  332. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/scripts/__init__.py +0 -0
  333. {nene2_python-1.8.40 → nene2_python-1.8.41}/src/scripts/export_openapi.py +0 -0
  334. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/__init__.py +0 -0
  335. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/conftest.py +0 -0
  336. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/__init__.py +0 -0
  337. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/comment/__init__.py +0 -0
  338. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/comment/test_comment_http.py +0 -0
  339. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/comment/test_comment_repository.py +0 -0
  340. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/comment/test_comment_use_case.py +0 -0
  341. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/conftest.py +0 -0
  342. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/note/__init__.py +0 -0
  343. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/note/test_async_note_use_case.py +0 -0
  344. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/note/test_list_notes.py +0 -0
  345. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/note/test_note_repository.py +0 -0
  346. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/tag/__init__.py +0 -0
  347. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/tag/test_tag_repository.py +0 -0
  348. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/tag/test_tags.py +0 -0
  349. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/test_cors.py +0 -0
  350. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/example/test_mcp.py +0 -0
  351. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/__init__.py +0 -0
  352. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/auth/__init__.py +0 -0
  353. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/auth/test_api_key.py +0 -0
  354. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/auth/test_bearer_token.py +0 -0
  355. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/auth/test_make_require_auth.py +0 -0
  356. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/auth/test_token_issuer.py +0 -0
  357. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/cache/__init__.py +0 -0
  358. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/cache/test_ttl.py +0 -0
  359. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/config/__init__.py +0 -0
  360. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/config/test_settings.py +0 -0
  361. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/database/__init__.py +0 -0
  362. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/database/test_transaction.py +0 -0
  363. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/database/test_utils.py +0 -0
  364. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/http/__init__.py +0 -0
  365. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/http/test_etag.py +0 -0
  366. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/http/test_health.py +0 -0
  367. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/http/test_pagination.py +0 -0
  368. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/http/test_problem_details.py +0 -0
  369. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/log/__init__.py +0 -0
  370. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/log/test_setup.py +0 -0
  371. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/mcp/__init__.py +0 -0
  372. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/mcp/test_http_client.py +0 -0
  373. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/mcp/test_server.py +0 -0
  374. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/middleware/__init__.py +0 -0
  375. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/middleware/test_error_handler.py +0 -0
  376. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/middleware/test_request_id.py +0 -0
  377. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/middleware/test_request_logging.py +0 -0
  378. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/middleware/test_request_size_limit.py +0 -0
  379. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/middleware/test_security_headers.py +0 -0
  380. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/middleware/test_setup_middlewares.py +0 -0
  381. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/middleware/test_simple_domain_handler.py +0 -0
  382. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/middleware/test_throttle.py +0 -0
  383. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/security/__init__.py +0 -0
  384. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/security/test_webhook.py +0 -0
  385. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/use_case/__init__.py +0 -0
  386. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/use_case/test_protocols.py +0 -0
  387. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/use_case/test_run_in_threadpool.py +0 -0
  388. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/validation/__init__.py +0 -0
  389. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/nene2/validation/test_exceptions.py +0 -0
  390. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/scripts/__init__.py +0 -0
  391. {nene2_python-1.8.40 → nene2_python-1.8.41}/tests/scripts/test_export_openapi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nene2-python
3
- Version: 1.8.40
3
+ Version: 1.8.41
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,242 @@
1
+ # FT170: collections モジュール
2
+
3
+ **日付**: 2026-05-21
4
+ **テーマ**: `collections` モジュール — `namedtuple`・`defaultdict`・`Counter`・`deque`・`OrderedDict`・`ChainMap`
5
+ **セキュリティ診断**: なし(170 % 3 = 2)
6
+
7
+ ---
8
+
9
+ ## 概要
10
+
11
+ Python 標準ライブラリの `collections` モジュールを nene2-python フレームワーク上で検証した。
12
+ `collections` は Python の基本データ構造を拡張する実用的なモジュールで、
13
+ ドメインデータ集計・キャッシュ・グラフ探索・設定管理に直接使えるパターンを提供する。
14
+
15
+ ---
16
+
17
+ ## 実装したサンプルアプリ
18
+
19
+ **場所**: `/home/xi/docker/nene2-python-FT/ft170-collections/`
20
+
21
+ ### 主要機能
22
+
23
+ | クラス/関数 | 概要 |
24
+ |---|---|
25
+ | `ApiError` (namedtuple) | エラー情報の軽量イミュータブル型。`_asdict()` で辞書変換 |
26
+ | `group_by_first_char()` | `defaultdict(list)` でグループ集計 |
27
+ | `count_tags()` | `defaultdict(int)` で出現頻度集計 |
28
+ | `build_adjacency_list()` | `defaultdict(list)` でグラフ構築 |
29
+ | `word_frequency()` / `top_n_words()` | `Counter` で単語頻度・トップN |
30
+ | `tag_overlap()` | `Counter` の intersection で共通タグを抽出 |
31
+ | `merge_counts()` | 複数 `Counter` を `update()` で合算 |
32
+ | `sliding_window_max()` | `deque` で O(n) スライディングウィンドウ最大値 |
33
+ | `recent_n()` | `deque(maxlen=n)` でリングバッファ |
34
+ | `bfs_path()` | `deque` をキューとして BFS 最短経路探索 |
35
+ | `LruCache` | `OrderedDict` + `move_to_end()` で O(1) LRU キャッシュ |
36
+ | `resolve_config()` / `config_source()` | `ChainMap` で env > file > defaults の優先順位設定 |
37
+
38
+ ### HTTP エンドポイント
39
+
40
+ | メソッド | パス | 概要 |
41
+ |---|---|---|
42
+ | GET | `/collections/namedtuple` | namedtuple デモ(距離計算・エラー構造体) |
43
+ | POST | `/collections/group-by` | defaultdict でグループ集計 |
44
+ | POST | `/collections/count-tags` | defaultdict でタグ集計 |
45
+ | GET | `/collections/word-freq` | Counter で単語頻度分析 |
46
+ | GET | `/collections/sliding-window` | deque でスライディングウィンドウ |
47
+ | GET | `/collections/recent` | deque(maxlen) リングバッファ |
48
+ | POST | `/collections/bfs` | BFS グラフ探索 |
49
+ | PUT/GET | `/collections/lru/{key}` | OrderedDict LRU キャッシュ |
50
+ | POST | `/collections/config` | ChainMap 設定レイヤー解決 |
51
+
52
+ ---
53
+
54
+ ## テスト結果
55
+
56
+ **36 passed(摩擦ゼロ)**
57
+
58
+ ```
59
+ 36 passed in 0.94s
60
+ ```
61
+
62
+ ---
63
+
64
+ ## 摩擦ポイント
65
+
66
+ **今回の FT では実装上の摩擦はゼロだった。**
67
+
68
+ ---
69
+
70
+ ## 観察点
71
+
72
+ ### 観察1: `defaultdict` は「キーがなければ初期値」を明示的に設計できる
73
+
74
+ ```python
75
+ result: defaultdict[str, list[str]] = defaultdict(list)
76
+ for word in words:
77
+ result[word[0]].append(word) # KeyError なし
78
+ ```
79
+
80
+ `dict.setdefault()` より意図が明確で、`if key not in d:` 分岐が不要になる。
81
+ グループ集計・グラフ隣接リスト構築・カウンタ実装の3パターンで多用できる。
82
+
83
+ ### 観察2: `Counter` は集合演算(`+`, `-`, `&`, `|`)が使える辞書
84
+
85
+ ```python
86
+ Counter(["python", "typing", "python"]) & Counter(["python", "asyncio"])
87
+ # → Counter({"python": 1}) — min(2,1) = 1
88
+ ```
89
+
90
+ `Counter` 同士の `+` は合算、`&` は最小値、`|` は最大値。
91
+ 複数の集計結果をマージする `merge_counts()` は `Counter.update()` で自然に書ける。
92
+ `most_common(n)` で上位 N 件を O(n log n) で取得できる。
93
+
94
+ ### 観察3: `deque(maxlen=n)` はリングバッファとして使える
95
+
96
+ ```python
97
+ buf: deque[str] = deque(maxlen=5)
98
+ buf.extend(["a", "b", "c", "d", "e", "f"])
99
+ list(buf) # → ["b", "c", "d", "e", "f"] — 最新5件のみ保持
100
+ ```
101
+
102
+ `maxlen` を指定すると、追加時に先頭から自動削除される。
103
+ ログ末尾 N 行・最近の操作履歴・スライディングウィンドウのバッファとして最適。
104
+ `collections.deque` は `list` と異なり先頭操作が O(1)。
105
+
106
+ ### 観察4: `OrderedDict.move_to_end()` で O(1) LRU キャッシュが実装できる
107
+
108
+ ```python
109
+ class LruCache:
110
+ def get(self, key: str) -> Any:
111
+ if key not in self._cache:
112
+ return None
113
+ self._cache.move_to_end(key) # 最近使用済みとしてマーク
114
+ return self._cache[key]
115
+
116
+ def put(self, key: str, value: Any) -> None:
117
+ ...
118
+ if len(self._cache) > self.capacity:
119
+ self._cache.popitem(last=False) # 最も古いものを削除
120
+ ```
121
+
122
+ `Python 3.7+` の `dict` は挿入順を保証するが、`move_to_end()` がないため
123
+ LRU の「使用順序の更新」には `OrderedDict` が必要。
124
+ nene2 の `TtlCache` と組み合わせた TTL+LRU キャッシュへの発展も可能。
125
+
126
+ ### 観察5: `ChainMap` で設定レイヤーのオーバーライドが宣言的に書ける
127
+
128
+ ```python
129
+ chain = ChainMap(env_vars, file_config, defaults)
130
+ chain["DB_HOST"] # env_vars → file_config → defaults の優先順位で検索
131
+ ```
132
+
133
+ `os.environ` + ファイル設定 + デフォルト値の優先順位解決は
134
+ 従来 `{**defaults, **file_config, **env_vars}` で実装していたが、
135
+ `ChainMap` は元の辞書を変更せず参照のみのため副作用がない。
136
+ `chain.maps[0]` で最優先レイヤー、`chain.new_child()` でスコープを重ねることもできる。
137
+
138
+ ---
139
+
140
+ ## nene2-python フレームワークとの統合
141
+
142
+ - `Counter` はタグ・カテゴリの集計 Use Case で `GROUP BY` SQL の代替になる(小規模データ)
143
+ - `LruCache` は nene2 の `TtlCache[V]` と組み合わせて TTL + LRU の複合キャッシュに発展できる
144
+ - `ChainMap` は `AppSettings` の `pydantic-settings` が行っている env > file > default 解決と同じパターン
145
+ - `deque` は WebSocket メッセージキューやストリーミングレスポンスのバッファとして適用できる
146
+ - `namedtuple` は UseCase の軽量 Output DTO として `dataclass(frozen=True)` より軽量な選択肢になる
147
+
148
+ ---
149
+
150
+ ## Developer Experience (DX) Review
151
+
152
+ ### ペルソナ1: 初心者(Python 歴1年・独学中・女性・バックエンド志望)
153
+
154
+ `defaultdict` は「エラーが出なくなった辞書」として直感的に受け入れられる。
155
+ `Counter` は「辞書の特殊版」として理解でき、`.most_common()` が使いやすい。
156
+ `deque` の「両端キュー」という概念は最初はピンとこないが、`maxlen` のリングバッファ用途はすぐに理解できる。
157
+
158
+ **ドキュメント理解**: `defaultdict(list)` のファクトリ関数の渡し方(`list` を呼び出さない)は最初に混乱する。
159
+ `defaultdict(lambda: [])` との違いを最初に説明すると理解が早い。
160
+
161
+ **事故リスク**: 中。`defaultdict` は存在しないキーにアクセスすると自動で作成するため、
162
+ タイポキーが無音で `{}` や `[]` に変わり、後続処理でのデバッグが難しくなる可能性。
163
+
164
+ **規約の使いやすさ**: コピペで使えるパターンが多い。
165
+
166
+ ### ペルソナ2: ロースキル経験者(Python 歴3-4年・スクリプト系・男性・SES)
167
+
168
+ `Counter` を知らずに `dict` + `if key in d: d[key] += 1 else: d[key] = 1` を書いている。
169
+ `Counter` を知ると即採用する。
170
+
171
+ **コピペ可能性**: 高。特に `Counter(list).most_common(n)` のワンライナーは即戦力。
172
+
173
+ **拡張時の罠**: `LruCache` で `OrderedDict` を使っているが、
174
+ Python 3.7+ の `dict` で書き直そうとして `move_to_end()` がないことに気づかず壊す可能性。
175
+ 「`OrderedDict` には `move_to_end()` がある」という固有 API を README に明記するべき。
176
+
177
+ **セキュリティ的な事故リスク**: 低。`collections` の誤用は機能バグには繋がるが、セキュリティリスクは低い。
178
+
179
+ ### ペルソナ3: フロントエンド寄り経験者(React/TS 歴4年・バックエンド転向中・ノンバイナリ)
180
+
181
+ `Counter` は JavaScript の `reduce` で頻度集計するパターンと概念的に近い。
182
+ `namedtuple` は TypeScript の `readonly struct` 的に理解できる。
183
+
184
+ **エラーレスポンスの質**: `/collections/sliding-window` で `"a,b,c"` を送ると 422 が返る。
185
+ クライアントには `{"error": "values must be comma-separated integers"}` が届き明確。
186
+
187
+ **事故リスク**: 低。
188
+
189
+ ### ペルソナ4: バックエンド経験者(Django/FastAPI 歴5-6年・男性・リードエンジニア)
190
+
191
+ Django の `QuerySet.values().annotate(count=Count(...))` と `Counter` の使い分けが判断ポイント。
192
+ DB に集計クエリを投げられるなら Django ORM が適切。
193
+ インメモリ集計(小規模・一時的)には `Counter` が軽量。
194
+
195
+ **本番投入可能性**: 問題なし。`LruCache` は nene2 の `TtlCache` と組み合わせて即本番投入できる。
196
+
197
+ ### ペルソナ5: シニアエンジニア(設計・コードレビュー担当・女性・10-12年)
198
+
199
+ **コードレビューチェックポイント**:
200
+ - [ ] `defaultdict` のキーが意図せず作成されていないか(`d[key]` アクセスだけでキーが生える)
201
+ - [ ] `Counter` の `most_common()` が `None` を返さないことを前提にしているか(空リストなら空リストを返す)
202
+ - [ ] `LruCache` が複数リクエストからアクセスされるグローバル状態の場合、`asyncio.Lock()` が必要か確認
203
+ - [ ] `ChainMap` の子マップへの書き込みが親マップに伝播しないことを理解しているか
204
+
205
+ **チームでの安全なパターン**: グローバルな `LruCache` インスタンスは `asyncio.Lock()` でガードするか、
206
+ スレッドセーフな実装(`threading.RLock`)に置き換える。
207
+
208
+ ### ペルソナ6: 設計者・ポリシー照合(nene2-python 設計ポリシー目線)
209
+
210
+ **ポリシー達成度**: 高
211
+
212
+ **「初心者でも安全な API」達成度**: 中
213
+ - `defaultdict` のキー自動生成は初心者には予期しない動作になりうる
214
+ - `LruCache` のスレッドセーフ性は nene2 の非同期環境では注意が必要
215
+
216
+ **設計上の負債・ドキュメント不足**:
217
+ - nene2 の `TtlCache[V]` と `LruCache` の組み合わせパターンが未文書化
218
+ - グローバルキャッシュインスタンスの非同期安全性に関する how-to がない
219
+
220
+ **Follow-up Issue 候補**: `docs: キャッシュの TTL + LRU 複合パターンと非同期安全性の how-to を追加`
221
+
222
+ ---
223
+
224
+ ## Follow-up Issues
225
+
226
+ | 優先度 | タイトル | 種別 |
227
+ |---|---|---|
228
+ | 中 | `docs: collections.Counter をタグ集計 Use Case に適用するパターンを how-to に追加` | docs |
229
+ | 低 | `feat: TtlCache に LRU 退去ポリシーを追加するオプションを検討` | feat |
230
+
231
+ ---
232
+
233
+ ## まとめ
234
+
235
+ `collections` モジュールは nene2-python の集計・キャッシュ・探索・設定管理に直接使える実用的な機能群。
236
+ 36 テスト全通過、摩擦ゼロ。
237
+
238
+ `defaultdict` / `Counter` / `deque` の三点セットは Python バックエンドの必須知識。
239
+ `OrderedDict.move_to_end()` による LRU キャッシュは nene2 の `TtlCache` と組み合わせる価値がある。
240
+ `ChainMap` は `pydantic-settings` が内部でやっている設定レイヤー解決と同じパターンで、
241
+ 環境別設定のオーバーライドを副作用なしに実装できる。
242
+
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nene2-python"
3
- version = "1.8.40"
3
+ version = "1.8.41"
4
4
  description = "NENE2 Python — minimal API framework following NENE2's design philosophy"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -925,7 +925,7 @@ wheels = [
925
925
 
926
926
  [[package]]
927
927
  name = "nene2-python"
928
- version = "1.8.40"
928
+ version = "1.8.41"
929
929
  source = { editable = "." }
930
930
  dependencies = [
931
931
  { name = "alembic" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes