solokit 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. solokit/__init__.py +10 -0
  2. solokit/__version__.py +3 -0
  3. solokit/cli.py +374 -0
  4. solokit/core/__init__.py +1 -0
  5. solokit/core/cache.py +102 -0
  6. solokit/core/command_runner.py +278 -0
  7. solokit/core/config.py +453 -0
  8. solokit/core/config_validator.py +204 -0
  9. solokit/core/constants.py +291 -0
  10. solokit/core/error_formatter.py +279 -0
  11. solokit/core/error_handlers.py +346 -0
  12. solokit/core/exceptions.py +1567 -0
  13. solokit/core/file_ops.py +309 -0
  14. solokit/core/logging_config.py +166 -0
  15. solokit/core/output.py +99 -0
  16. solokit/core/performance.py +57 -0
  17. solokit/core/protocols.py +141 -0
  18. solokit/core/types.py +312 -0
  19. solokit/deployment/__init__.py +1 -0
  20. solokit/deployment/executor.py +411 -0
  21. solokit/git/__init__.py +1 -0
  22. solokit/git/integration.py +619 -0
  23. solokit/init/__init__.py +41 -0
  24. solokit/init/claude_commands_installer.py +87 -0
  25. solokit/init/dependency_installer.py +313 -0
  26. solokit/init/docs_structure.py +90 -0
  27. solokit/init/env_generator.py +160 -0
  28. solokit/init/environment_validator.py +334 -0
  29. solokit/init/git_hooks_installer.py +71 -0
  30. solokit/init/git_setup.py +188 -0
  31. solokit/init/gitignore_updater.py +195 -0
  32. solokit/init/initial_commit.py +145 -0
  33. solokit/init/initial_scans.py +109 -0
  34. solokit/init/orchestrator.py +246 -0
  35. solokit/init/readme_generator.py +207 -0
  36. solokit/init/session_structure.py +239 -0
  37. solokit/init/template_installer.py +424 -0
  38. solokit/learning/__init__.py +1 -0
  39. solokit/learning/archiver.py +115 -0
  40. solokit/learning/categorizer.py +126 -0
  41. solokit/learning/curator.py +428 -0
  42. solokit/learning/extractor.py +352 -0
  43. solokit/learning/reporter.py +351 -0
  44. solokit/learning/repository.py +254 -0
  45. solokit/learning/similarity.py +342 -0
  46. solokit/learning/validator.py +144 -0
  47. solokit/project/__init__.py +1 -0
  48. solokit/project/init.py +1162 -0
  49. solokit/project/stack.py +436 -0
  50. solokit/project/sync_plugin.py +438 -0
  51. solokit/project/tree.py +375 -0
  52. solokit/quality/__init__.py +1 -0
  53. solokit/quality/api_validator.py +424 -0
  54. solokit/quality/checkers/__init__.py +25 -0
  55. solokit/quality/checkers/base.py +114 -0
  56. solokit/quality/checkers/context7.py +221 -0
  57. solokit/quality/checkers/custom.py +162 -0
  58. solokit/quality/checkers/deployment.py +323 -0
  59. solokit/quality/checkers/documentation.py +179 -0
  60. solokit/quality/checkers/formatting.py +161 -0
  61. solokit/quality/checkers/integration.py +394 -0
  62. solokit/quality/checkers/linting.py +159 -0
  63. solokit/quality/checkers/security.py +261 -0
  64. solokit/quality/checkers/spec_completeness.py +127 -0
  65. solokit/quality/checkers/tests.py +184 -0
  66. solokit/quality/env_validator.py +306 -0
  67. solokit/quality/gates.py +655 -0
  68. solokit/quality/reporters/__init__.py +10 -0
  69. solokit/quality/reporters/base.py +25 -0
  70. solokit/quality/reporters/console.py +98 -0
  71. solokit/quality/reporters/json_reporter.py +34 -0
  72. solokit/quality/results.py +98 -0
  73. solokit/session/__init__.py +1 -0
  74. solokit/session/briefing/__init__.py +245 -0
  75. solokit/session/briefing/documentation_loader.py +53 -0
  76. solokit/session/briefing/formatter.py +476 -0
  77. solokit/session/briefing/git_context.py +282 -0
  78. solokit/session/briefing/learning_loader.py +212 -0
  79. solokit/session/briefing/milestone_builder.py +78 -0
  80. solokit/session/briefing/orchestrator.py +137 -0
  81. solokit/session/briefing/stack_detector.py +51 -0
  82. solokit/session/briefing/tree_generator.py +52 -0
  83. solokit/session/briefing/work_item_loader.py +209 -0
  84. solokit/session/briefing.py +353 -0
  85. solokit/session/complete.py +1188 -0
  86. solokit/session/status.py +246 -0
  87. solokit/session/validate.py +452 -0
  88. solokit/templates/.claude/commands/end.md +109 -0
  89. solokit/templates/.claude/commands/init.md +159 -0
  90. solokit/templates/.claude/commands/learn-curate.md +88 -0
  91. solokit/templates/.claude/commands/learn-search.md +62 -0
  92. solokit/templates/.claude/commands/learn-show.md +69 -0
  93. solokit/templates/.claude/commands/learn.md +136 -0
  94. solokit/templates/.claude/commands/start.md +114 -0
  95. solokit/templates/.claude/commands/status.md +22 -0
  96. solokit/templates/.claude/commands/validate.md +27 -0
  97. solokit/templates/.claude/commands/work-delete.md +119 -0
  98. solokit/templates/.claude/commands/work-graph.md +139 -0
  99. solokit/templates/.claude/commands/work-list.md +26 -0
  100. solokit/templates/.claude/commands/work-new.md +114 -0
  101. solokit/templates/.claude/commands/work-next.md +25 -0
  102. solokit/templates/.claude/commands/work-show.md +24 -0
  103. solokit/templates/.claude/commands/work-update.md +141 -0
  104. solokit/templates/CHANGELOG.md +17 -0
  105. solokit/templates/WORK_ITEM_TYPES.md +141 -0
  106. solokit/templates/__init__.py +1 -0
  107. solokit/templates/bug_spec.md +217 -0
  108. solokit/templates/config.schema.json +150 -0
  109. solokit/templates/dashboard_refine/base/.gitignore +36 -0
  110. solokit/templates/dashboard_refine/base/app/(dashboard)/layout.tsx +22 -0
  111. solokit/templates/dashboard_refine/base/app/(dashboard)/page.tsx +68 -0
  112. solokit/templates/dashboard_refine/base/app/(dashboard)/users/page.tsx +77 -0
  113. solokit/templates/dashboard_refine/base/app/globals.css +60 -0
  114. solokit/templates/dashboard_refine/base/app/layout.tsx +23 -0
  115. solokit/templates/dashboard_refine/base/app/page.tsx +9 -0
  116. solokit/templates/dashboard_refine/base/components/client-refine-wrapper.tsx +21 -0
  117. solokit/templates/dashboard_refine/base/components/layout/header.tsx +44 -0
  118. solokit/templates/dashboard_refine/base/components/layout/sidebar.tsx +82 -0
  119. solokit/templates/dashboard_refine/base/components/ui/button.tsx +53 -0
  120. solokit/templates/dashboard_refine/base/components/ui/card.tsx +78 -0
  121. solokit/templates/dashboard_refine/base/components/ui/table.tsx +116 -0
  122. solokit/templates/dashboard_refine/base/components.json +16 -0
  123. solokit/templates/dashboard_refine/base/lib/refine.tsx +65 -0
  124. solokit/templates/dashboard_refine/base/lib/utils.ts +13 -0
  125. solokit/templates/dashboard_refine/base/next.config.ts +10 -0
  126. solokit/templates/dashboard_refine/base/package.json.template +40 -0
  127. solokit/templates/dashboard_refine/base/postcss.config.mjs +8 -0
  128. solokit/templates/dashboard_refine/base/providers/refine-provider.tsx +26 -0
  129. solokit/templates/dashboard_refine/base/tailwind.config.ts +57 -0
  130. solokit/templates/dashboard_refine/base/tsconfig.json +27 -0
  131. solokit/templates/dashboard_refine/docker/Dockerfile +57 -0
  132. solokit/templates/dashboard_refine/docker/docker-compose.prod.yml +31 -0
  133. solokit/templates/dashboard_refine/docker/docker-compose.yml +21 -0
  134. solokit/templates/dashboard_refine/tier-1-essential/.eslintrc.json +7 -0
  135. solokit/templates/dashboard_refine/tier-1-essential/jest.config.ts +17 -0
  136. solokit/templates/dashboard_refine/tier-1-essential/jest.setup.ts +1 -0
  137. solokit/templates/dashboard_refine/tier-1-essential/package.json.tier1.template +57 -0
  138. solokit/templates/dashboard_refine/tier-1-essential/tests/setup.ts +26 -0
  139. solokit/templates/dashboard_refine/tier-1-essential/tests/unit/example.test.tsx +73 -0
  140. solokit/templates/dashboard_refine/tier-2-standard/package.json.tier2.template +62 -0
  141. solokit/templates/dashboard_refine/tier-3-comprehensive/eslint.config.mjs +22 -0
  142. solokit/templates/dashboard_refine/tier-3-comprehensive/package.json.tier3.template +79 -0
  143. solokit/templates/dashboard_refine/tier-3-comprehensive/playwright.config.ts +66 -0
  144. solokit/templates/dashboard_refine/tier-3-comprehensive/stryker.conf.json +38 -0
  145. solokit/templates/dashboard_refine/tier-3-comprehensive/tests/e2e/dashboard.spec.ts +88 -0
  146. solokit/templates/dashboard_refine/tier-3-comprehensive/tests/e2e/user-management.spec.ts +102 -0
  147. solokit/templates/dashboard_refine/tier-3-comprehensive/tests/integration/dashboard.test.tsx +90 -0
  148. solokit/templates/dashboard_refine/tier-3-comprehensive/type-coverage.json +16 -0
  149. solokit/templates/dashboard_refine/tier-4-production/instrumentation.ts +9 -0
  150. solokit/templates/dashboard_refine/tier-4-production/k6/dashboard-load-test.js +70 -0
  151. solokit/templates/dashboard_refine/tier-4-production/next.config.ts +46 -0
  152. solokit/templates/dashboard_refine/tier-4-production/package.json.tier4.template +89 -0
  153. solokit/templates/dashboard_refine/tier-4-production/sentry.client.config.ts +26 -0
  154. solokit/templates/dashboard_refine/tier-4-production/sentry.edge.config.ts +11 -0
  155. solokit/templates/dashboard_refine/tier-4-production/sentry.server.config.ts +11 -0
  156. solokit/templates/deployment_spec.md +500 -0
  157. solokit/templates/feature_spec.md +248 -0
  158. solokit/templates/fullstack_nextjs/base/.gitignore +36 -0
  159. solokit/templates/fullstack_nextjs/base/app/api/example/route.ts +65 -0
  160. solokit/templates/fullstack_nextjs/base/app/globals.css +27 -0
  161. solokit/templates/fullstack_nextjs/base/app/layout.tsx +20 -0
  162. solokit/templates/fullstack_nextjs/base/app/page.tsx +32 -0
  163. solokit/templates/fullstack_nextjs/base/components/example-component.tsx +20 -0
  164. solokit/templates/fullstack_nextjs/base/lib/prisma.ts +17 -0
  165. solokit/templates/fullstack_nextjs/base/lib/utils.ts +13 -0
  166. solokit/templates/fullstack_nextjs/base/lib/validations.ts +20 -0
  167. solokit/templates/fullstack_nextjs/base/next.config.ts +7 -0
  168. solokit/templates/fullstack_nextjs/base/package.json.template +32 -0
  169. solokit/templates/fullstack_nextjs/base/postcss.config.mjs +8 -0
  170. solokit/templates/fullstack_nextjs/base/prisma/schema.prisma +21 -0
  171. solokit/templates/fullstack_nextjs/base/tailwind.config.ts +19 -0
  172. solokit/templates/fullstack_nextjs/base/tsconfig.json +27 -0
  173. solokit/templates/fullstack_nextjs/docker/Dockerfile +60 -0
  174. solokit/templates/fullstack_nextjs/docker/docker-compose.prod.yml +57 -0
  175. solokit/templates/fullstack_nextjs/docker/docker-compose.yml +47 -0
  176. solokit/templates/fullstack_nextjs/tier-1-essential/.eslintrc.json +7 -0
  177. solokit/templates/fullstack_nextjs/tier-1-essential/jest.config.ts +17 -0
  178. solokit/templates/fullstack_nextjs/tier-1-essential/jest.setup.ts +1 -0
  179. solokit/templates/fullstack_nextjs/tier-1-essential/package.json.tier1.template +48 -0
  180. solokit/templates/fullstack_nextjs/tier-1-essential/tests/api/example.test.ts +88 -0
  181. solokit/templates/fullstack_nextjs/tier-1-essential/tests/setup.ts +22 -0
  182. solokit/templates/fullstack_nextjs/tier-1-essential/tests/unit/example.test.tsx +22 -0
  183. solokit/templates/fullstack_nextjs/tier-2-standard/package.json.tier2.template +52 -0
  184. solokit/templates/fullstack_nextjs/tier-3-comprehensive/eslint.config.mjs +39 -0
  185. solokit/templates/fullstack_nextjs/tier-3-comprehensive/package.json.tier3.template +68 -0
  186. solokit/templates/fullstack_nextjs/tier-3-comprehensive/playwright.config.ts +66 -0
  187. solokit/templates/fullstack_nextjs/tier-3-comprehensive/stryker.conf.json +33 -0
  188. solokit/templates/fullstack_nextjs/tier-3-comprehensive/tests/e2e/flow.spec.ts +59 -0
  189. solokit/templates/fullstack_nextjs/tier-3-comprehensive/tests/integration/api.test.ts +165 -0
  190. solokit/templates/fullstack_nextjs/tier-3-comprehensive/type-coverage.json +12 -0
  191. solokit/templates/fullstack_nextjs/tier-4-production/instrumentation.ts +9 -0
  192. solokit/templates/fullstack_nextjs/tier-4-production/k6/load-test.js +45 -0
  193. solokit/templates/fullstack_nextjs/tier-4-production/next.config.ts +46 -0
  194. solokit/templates/fullstack_nextjs/tier-4-production/package.json.tier4.template +77 -0
  195. solokit/templates/fullstack_nextjs/tier-4-production/sentry.client.config.ts +26 -0
  196. solokit/templates/fullstack_nextjs/tier-4-production/sentry.edge.config.ts +11 -0
  197. solokit/templates/fullstack_nextjs/tier-4-production/sentry.server.config.ts +11 -0
  198. solokit/templates/git-hooks/prepare-commit-msg +24 -0
  199. solokit/templates/integration_test_spec.md +363 -0
  200. solokit/templates/learnings.json +15 -0
  201. solokit/templates/ml_ai_fastapi/base/.gitignore +104 -0
  202. solokit/templates/ml_ai_fastapi/base/alembic/env.py +96 -0
  203. solokit/templates/ml_ai_fastapi/base/alembic.ini +114 -0
  204. solokit/templates/ml_ai_fastapi/base/pyproject.toml.template +91 -0
  205. solokit/templates/ml_ai_fastapi/base/requirements.txt.template +28 -0
  206. solokit/templates/ml_ai_fastapi/base/src/__init__.py +5 -0
  207. solokit/templates/ml_ai_fastapi/base/src/api/__init__.py +3 -0
  208. solokit/templates/ml_ai_fastapi/base/src/api/dependencies.py +20 -0
  209. solokit/templates/ml_ai_fastapi/base/src/api/routes/__init__.py +3 -0
  210. solokit/templates/ml_ai_fastapi/base/src/api/routes/example.py +134 -0
  211. solokit/templates/ml_ai_fastapi/base/src/api/routes/health.py +66 -0
  212. solokit/templates/ml_ai_fastapi/base/src/core/__init__.py +3 -0
  213. solokit/templates/ml_ai_fastapi/base/src/core/config.py +64 -0
  214. solokit/templates/ml_ai_fastapi/base/src/core/database.py +50 -0
  215. solokit/templates/ml_ai_fastapi/base/src/main.py +64 -0
  216. solokit/templates/ml_ai_fastapi/base/src/models/__init__.py +7 -0
  217. solokit/templates/ml_ai_fastapi/base/src/models/example.py +61 -0
  218. solokit/templates/ml_ai_fastapi/base/src/services/__init__.py +3 -0
  219. solokit/templates/ml_ai_fastapi/base/src/services/example.py +115 -0
  220. solokit/templates/ml_ai_fastapi/docker/Dockerfile +59 -0
  221. solokit/templates/ml_ai_fastapi/docker/docker-compose.prod.yml +112 -0
  222. solokit/templates/ml_ai_fastapi/docker/docker-compose.yml +77 -0
  223. solokit/templates/ml_ai_fastapi/tier-1-essential/pyproject.toml.tier1.template +112 -0
  224. solokit/templates/ml_ai_fastapi/tier-1-essential/pyrightconfig.json +41 -0
  225. solokit/templates/ml_ai_fastapi/tier-1-essential/pytest.ini +69 -0
  226. solokit/templates/ml_ai_fastapi/tier-1-essential/requirements-dev.txt +17 -0
  227. solokit/templates/ml_ai_fastapi/tier-1-essential/ruff.toml +81 -0
  228. solokit/templates/ml_ai_fastapi/tier-1-essential/tests/__init__.py +3 -0
  229. solokit/templates/ml_ai_fastapi/tier-1-essential/tests/conftest.py +72 -0
  230. solokit/templates/ml_ai_fastapi/tier-1-essential/tests/test_main.py +49 -0
  231. solokit/templates/ml_ai_fastapi/tier-1-essential/tests/unit/__init__.py +3 -0
  232. solokit/templates/ml_ai_fastapi/tier-1-essential/tests/unit/test_example.py +113 -0
  233. solokit/templates/ml_ai_fastapi/tier-2-standard/pyproject.toml.tier2.template +130 -0
  234. solokit/templates/ml_ai_fastapi/tier-3-comprehensive/locustfile.py +99 -0
  235. solokit/templates/ml_ai_fastapi/tier-3-comprehensive/mutmut_config.py +53 -0
  236. solokit/templates/ml_ai_fastapi/tier-3-comprehensive/pyproject.toml.tier3.template +150 -0
  237. solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/__init__.py +3 -0
  238. solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/conftest.py +74 -0
  239. solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/test_api.py +131 -0
  240. solokit/templates/ml_ai_fastapi/tier-4-production/pyproject.toml.tier4.template +162 -0
  241. solokit/templates/ml_ai_fastapi/tier-4-production/requirements-prod.txt +25 -0
  242. solokit/templates/ml_ai_fastapi/tier-4-production/src/api/routes/metrics.py +19 -0
  243. solokit/templates/ml_ai_fastapi/tier-4-production/src/core/logging.py +74 -0
  244. solokit/templates/ml_ai_fastapi/tier-4-production/src/core/monitoring.py +68 -0
  245. solokit/templates/ml_ai_fastapi/tier-4-production/src/core/sentry.py +66 -0
  246. solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/__init__.py +3 -0
  247. solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/logging.py +79 -0
  248. solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/tracing.py +60 -0
  249. solokit/templates/refactor_spec.md +287 -0
  250. solokit/templates/saas_t3/base/.gitignore +36 -0
  251. solokit/templates/saas_t3/base/app/api/trpc/[trpc]/route.ts +33 -0
  252. solokit/templates/saas_t3/base/app/globals.css +27 -0
  253. solokit/templates/saas_t3/base/app/layout.tsx +23 -0
  254. solokit/templates/saas_t3/base/app/page.tsx +31 -0
  255. solokit/templates/saas_t3/base/lib/api.tsx +77 -0
  256. solokit/templates/saas_t3/base/lib/utils.ts +13 -0
  257. solokit/templates/saas_t3/base/next.config.ts +7 -0
  258. solokit/templates/saas_t3/base/package.json.template +38 -0
  259. solokit/templates/saas_t3/base/postcss.config.mjs +8 -0
  260. solokit/templates/saas_t3/base/prisma/schema.prisma +20 -0
  261. solokit/templates/saas_t3/base/server/api/root.ts +19 -0
  262. solokit/templates/saas_t3/base/server/api/routers/example.ts +28 -0
  263. solokit/templates/saas_t3/base/server/api/trpc.ts +52 -0
  264. solokit/templates/saas_t3/base/server/db.ts +17 -0
  265. solokit/templates/saas_t3/base/tailwind.config.ts +19 -0
  266. solokit/templates/saas_t3/base/tsconfig.json +27 -0
  267. solokit/templates/saas_t3/docker/Dockerfile +60 -0
  268. solokit/templates/saas_t3/docker/docker-compose.prod.yml +59 -0
  269. solokit/templates/saas_t3/docker/docker-compose.yml +49 -0
  270. solokit/templates/saas_t3/tier-1-essential/.eslintrc.json +7 -0
  271. solokit/templates/saas_t3/tier-1-essential/jest.config.ts +17 -0
  272. solokit/templates/saas_t3/tier-1-essential/jest.setup.ts +1 -0
  273. solokit/templates/saas_t3/tier-1-essential/package.json.tier1.template +54 -0
  274. solokit/templates/saas_t3/tier-1-essential/tests/setup.ts +22 -0
  275. solokit/templates/saas_t3/tier-1-essential/tests/unit/example.test.tsx +24 -0
  276. solokit/templates/saas_t3/tier-2-standard/package.json.tier2.template +58 -0
  277. solokit/templates/saas_t3/tier-3-comprehensive/eslint.config.mjs +39 -0
  278. solokit/templates/saas_t3/tier-3-comprehensive/package.json.tier3.template +74 -0
  279. solokit/templates/saas_t3/tier-3-comprehensive/playwright.config.ts +66 -0
  280. solokit/templates/saas_t3/tier-3-comprehensive/stryker.conf.json +34 -0
  281. solokit/templates/saas_t3/tier-3-comprehensive/tests/e2e/home.spec.ts +41 -0
  282. solokit/templates/saas_t3/tier-3-comprehensive/tests/integration/api.test.ts +44 -0
  283. solokit/templates/saas_t3/tier-3-comprehensive/type-coverage.json +12 -0
  284. solokit/templates/saas_t3/tier-4-production/instrumentation.ts +9 -0
  285. solokit/templates/saas_t3/tier-4-production/k6/load-test.js +51 -0
  286. solokit/templates/saas_t3/tier-4-production/next.config.ts +46 -0
  287. solokit/templates/saas_t3/tier-4-production/package.json.tier4.template +83 -0
  288. solokit/templates/saas_t3/tier-4-production/sentry.client.config.ts +26 -0
  289. solokit/templates/saas_t3/tier-4-production/sentry.edge.config.ts +11 -0
  290. solokit/templates/saas_t3/tier-4-production/sentry.server.config.ts +11 -0
  291. solokit/templates/saas_t3/tier-4-production/vercel.json +37 -0
  292. solokit/templates/security_spec.md +287 -0
  293. solokit/templates/stack-versions.yaml +617 -0
  294. solokit/templates/status_update.json +6 -0
  295. solokit/templates/template-registry.json +257 -0
  296. solokit/templates/work_items.json +11 -0
  297. solokit/testing/__init__.py +1 -0
  298. solokit/testing/integration_runner.py +550 -0
  299. solokit/testing/performance.py +637 -0
  300. solokit/visualization/__init__.py +1 -0
  301. solokit/visualization/dependency_graph.py +788 -0
  302. solokit/work_items/__init__.py +1 -0
  303. solokit/work_items/creator.py +217 -0
  304. solokit/work_items/delete.py +264 -0
  305. solokit/work_items/get_dependencies.py +185 -0
  306. solokit/work_items/get_dependents.py +113 -0
  307. solokit/work_items/get_metadata.py +121 -0
  308. solokit/work_items/get_next_recommendations.py +133 -0
  309. solokit/work_items/manager.py +235 -0
  310. solokit/work_items/milestones.py +137 -0
  311. solokit/work_items/query.py +376 -0
  312. solokit/work_items/repository.py +267 -0
  313. solokit/work_items/scheduler.py +184 -0
  314. solokit/work_items/spec_parser.py +838 -0
  315. solokit/work_items/spec_validator.py +493 -0
  316. solokit/work_items/updater.py +157 -0
  317. solokit/work_items/validator.py +205 -0
  318. solokit-0.1.1.dist-info/METADATA +640 -0
  319. solokit-0.1.1.dist-info/RECORD +323 -0
  320. solokit-0.1.1.dist-info/WHEEL +5 -0
  321. solokit-0.1.1.dist-info/entry_points.txt +2 -0
  322. solokit-0.1.1.dist-info/licenses/LICENSE +21 -0
  323. solokit-0.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,74 @@
1
+ """
2
+ Integration test fixtures
3
+ """
4
+
5
+ from collections.abc import AsyncGenerator
6
+ from typing import Any
7
+
8
+ import pytest
9
+ from httpx import ASGITransport, AsyncClient # type: ignore[import-not-found]
10
+ from sqlalchemy.ext.asyncio import create_async_engine # type: ignore[import-not-found]
11
+ from sqlalchemy.orm import sessionmaker # type: ignore[import-not-found]
12
+ from sqlmodel import SQLModel # type: ignore[import-not-found]
13
+ from sqlmodel.ext.asyncio.session import AsyncSession # type: ignore[import-not-found]
14
+ from src.api.dependencies import get_db # type: ignore[import-not-found]
15
+ from src.main import app # type: ignore[import-not-found]
16
+
17
+ # Use a separate test database for integration tests
18
+ INTEGRATION_DATABASE_URL = "sqlite+aiosqlite:///./test_integration.db"
19
+
20
+
21
+ @pytest.fixture(scope="function")
22
+ async def integration_db_engine() -> AsyncGenerator[Any, None]:
23
+ """Create a test database engine for integration tests."""
24
+ engine = create_async_engine(
25
+ INTEGRATION_DATABASE_URL,
26
+ echo=False,
27
+ future=True,
28
+ )
29
+
30
+ async with engine.begin() as conn:
31
+ await conn.run_sync(SQLModel.metadata.create_all)
32
+
33
+ yield engine
34
+
35
+ async with engine.begin() as conn:
36
+ await conn.run_sync(SQLModel.metadata.drop_all)
37
+
38
+ await engine.dispose()
39
+
40
+
41
+ @pytest.fixture(scope="function")
42
+ async def integration_db_session(
43
+ integration_db_engine: Any,
44
+ ) -> AsyncGenerator[AsyncSession, None]:
45
+ """Create a test database session for integration tests."""
46
+ async_session_maker = sessionmaker(
47
+ integration_db_engine,
48
+ class_=AsyncSession,
49
+ expire_on_commit=False,
50
+ )
51
+
52
+ async with async_session_maker() as session:
53
+ yield session
54
+
55
+
56
+ @pytest.fixture(scope="function")
57
+ async def integration_client(
58
+ integration_db_session: AsyncSession,
59
+ ) -> AsyncGenerator[AsyncClient, None]:
60
+ """
61
+ Create a test client for integration tests.
62
+ """
63
+
64
+ async def override_get_db() -> AsyncGenerator[AsyncSession, None]:
65
+ yield integration_db_session
66
+
67
+ app.dependency_overrides[get_db] = override_get_db
68
+
69
+ async with AsyncClient(
70
+ transport=ASGITransport(app=app), base_url="http://testserver", timeout=30.0
71
+ ) as ac: # nosec B113 - Test client timeout is set to 30 seconds
72
+ yield ac
73
+
74
+ app.dependency_overrides.clear()
@@ -0,0 +1,131 @@
1
+ """
2
+ Integration tests for API endpoints
3
+ """
4
+
5
+ import pytest
6
+ from httpx import AsyncClient # type: ignore[import-not-found]
7
+
8
+
9
+ @pytest.mark.integration
10
+ @pytest.mark.api
11
+ class TestItemAPIIntegration:
12
+ """Integration tests for Item API endpoints."""
13
+
14
+ async def test_create_and_retrieve_item(self, integration_client: AsyncClient) -> None:
15
+ """Test full cycle: create item and retrieve it."""
16
+ # Create an item
17
+ create_response = await integration_client.post(
18
+ "/api/v1/items",
19
+ json={
20
+ "name": "Integration Test Item",
21
+ "description": "Full stack test",
22
+ "price": 29.99,
23
+ },
24
+ )
25
+ assert create_response.status_code == 201
26
+ created_item = create_response.json()
27
+ assert created_item["name"] == "Integration Test Item"
28
+ item_id = created_item["id"]
29
+
30
+ # Retrieve the item
31
+ get_response = await integration_client.get(f"/api/v1/items/{item_id}")
32
+ assert get_response.status_code == 200
33
+ retrieved_item = get_response.json()
34
+ assert retrieved_item["id"] == item_id
35
+ assert retrieved_item["name"] == "Integration Test Item"
36
+
37
+ async def test_create_update_delete_workflow(self, integration_client: AsyncClient) -> None:
38
+ """Test complete CRUD workflow."""
39
+ # Create
40
+ create_response = await integration_client.post(
41
+ "/api/v1/items",
42
+ json={"name": "Workflow Item", "price": 10.0},
43
+ )
44
+ assert create_response.status_code == 201
45
+ item_id = create_response.json()["id"]
46
+
47
+ # Update
48
+ update_response = await integration_client.patch(
49
+ f"/api/v1/items/{item_id}",
50
+ json={"name": "Updated Item", "price": 15.0},
51
+ )
52
+ assert update_response.status_code == 200
53
+ updated_item = update_response.json()
54
+ assert updated_item["name"] == "Updated Item"
55
+ assert updated_item["price"] == 15.0
56
+
57
+ # Verify update
58
+ get_response = await integration_client.get(f"/api/v1/items/{item_id}")
59
+ assert get_response.status_code == 200
60
+ assert get_response.json()["name"] == "Updated Item"
61
+
62
+ # Delete
63
+ delete_response = await integration_client.delete(f"/api/v1/items/{item_id}")
64
+ assert delete_response.status_code == 204
65
+
66
+ # Verify deletion
67
+ get_deleted_response = await integration_client.get(f"/api/v1/items/{item_id}")
68
+ assert get_deleted_response.status_code == 404
69
+
70
+ async def test_list_items_pagination(self, integration_client: AsyncClient) -> None:
71
+ """Test listing items with pagination."""
72
+ # Create multiple items
73
+ for i in range(15):
74
+ await integration_client.post(
75
+ "/api/v1/items",
76
+ json={"name": f"Item {i}", "price": float(i)},
77
+ )
78
+
79
+ # Test default pagination
80
+ response = await integration_client.get("/api/v1/items")
81
+ assert response.status_code == 200
82
+ items = response.json()
83
+ assert len(items) <= 100
84
+
85
+ # Test custom pagination
86
+ response = await integration_client.get("/api/v1/items?skip=5&limit=5")
87
+ assert response.status_code == 200
88
+ items = response.json()
89
+ assert len(items) == 5
90
+
91
+ async def test_validation_errors(self, integration_client: AsyncClient) -> None:
92
+ """Test API validation errors."""
93
+ # Missing required field
94
+ response = await integration_client.post(
95
+ "/api/v1/items",
96
+ json={"description": "Missing name and price"},
97
+ )
98
+ assert response.status_code == 422
99
+
100
+ # Invalid price (must be > 0)
101
+ response = await integration_client.post(
102
+ "/api/v1/items",
103
+ json={"name": "Invalid Price", "price": -10.0},
104
+ )
105
+ assert response.status_code == 422
106
+
107
+ async def test_not_found_error(self, integration_client: AsyncClient) -> None:
108
+ """Test 404 error for non-existent item."""
109
+ response = await integration_client.get("/api/v1/items/99999")
110
+ assert response.status_code == 404
111
+
112
+
113
+ @pytest.mark.integration
114
+ class TestHealthEndpoints:
115
+ """Integration tests for health check endpoints."""
116
+
117
+ async def test_health_endpoints_integration(self, integration_client: AsyncClient) -> None:
118
+ """Test all health check endpoints."""
119
+ # Health check
120
+ response = await integration_client.get("/health")
121
+ assert response.status_code == 200
122
+ assert response.json()["status"] == "healthy"
123
+
124
+ # Readiness check
125
+ response = await integration_client.get("/health/ready")
126
+ assert response.status_code == 200
127
+
128
+ # Liveness check
129
+ response = await integration_client.get("/health/live")
130
+ assert response.status_code == 200
131
+ assert response.json()["status"] == "alive"
@@ -0,0 +1,162 @@
1
+ [project]
2
+ name = "{project_name}"
3
+ version = "0.1.0"
4
+ description = "{project_description}"
5
+ requires-python = ">=3.11"
6
+ dependencies = [
7
+ "fastapi==0.115.6",
8
+ "uvicorn[standard]==0.34.0",
9
+ "pydantic==2.12.4",
10
+ "pydantic-core==2.41.5",
11
+ "pydantic-settings==2.11.0",
12
+ "sqlmodel==0.0.25",
13
+ "sqlalchemy==2.0.37",
14
+ "psycopg2-binary==2.9.10",
15
+ "alembic==1.14.0",
16
+ "python-dotenv==1.2.1",
17
+ "asyncpg==0.30.0",
18
+ ]
19
+
20
+ [project.optional-dependencies]
21
+ dev = [
22
+ "pytest==8.3.4",
23
+ "pytest-cov==6.0.0",
24
+ "pytest-asyncio==0.25.2",
25
+ "httpx==0.28.1",
26
+ "aiosqlite==0.20.0",
27
+ "ruff==0.9.2",
28
+ "pyright==1.1.396",
29
+ ]
30
+
31
+ security = [
32
+ "detect-secrets==1.5.0",
33
+ "pip-audit==2.7.3",
34
+ "bandit[toml]==1.8.0",
35
+ "pre-commit==4.0.1",
36
+ ]
37
+
38
+ quality = [
39
+ "radon==6.0.1",
40
+ "vulture==2.14",
41
+ "mutmut==3.3.1",
42
+ "locust==2.42.2",
43
+ "semgrep==1.142.1",
44
+ "coverage[toml]==7.11.1",
45
+ ]
46
+
47
+ production = [
48
+ "prometheus-client==0.23.1",
49
+ "statsd==4.0.1",
50
+ "structlog==25.5.0",
51
+ "python-json-logger==4.0.0",
52
+ "fastapi-health==0.4.0",
53
+ "sentry-sdk==2.27.0",
54
+ "opentelemetry-instrumentation-fastapi==0.59b0",
55
+ "gunicorn==23.0.0",
56
+ ]
57
+
58
+ [build-system]
59
+ requires = ["setuptools>=61.0"]
60
+ build-backend = "setuptools.build_meta"
61
+
62
+ [tool.setuptools]
63
+ packages = ["src"]
64
+
65
+ # Ruff configuration
66
+ [tool.ruff]
67
+ line-length = 100
68
+ target-version = "py311"
69
+
70
+ select = [
71
+ "E", # pycodestyle errors
72
+ "W", # pycodestyle warnings
73
+ "F", # pyflakes
74
+ "I", # isort
75
+ "N", # pep8-naming
76
+ "UP", # pyupgrade
77
+ "B", # flake8-bugbear
78
+ "S", # bandit security checks
79
+ ]
80
+
81
+ ignore = [
82
+ "E501", # line too long (handled by formatter)
83
+ "S101", # assert used (we use asserts in tests)
84
+ ]
85
+
86
+ exclude = [
87
+ ".git",
88
+ ".venv",
89
+ "__pycache__",
90
+ "alembic/versions",
91
+ ".pytest_cache",
92
+ ]
93
+
94
+ [tool.ruff.format]
95
+ quote-style = "double"
96
+ indent-style = "space"
97
+
98
+ [tool.ruff.isort]
99
+ known-first-party = ["src"]
100
+
101
+ [tool.ruff.per-file-ignores]
102
+ "tests/*" = ["S101"]
103
+
104
+ # Pytest configuration
105
+ [tool.pytest.ini_options]
106
+ asyncio_mode = "auto"
107
+ testpaths = ["tests"]
108
+ python_files = ["test_*.py", "*_test.py"]
109
+ python_classes = ["Test*"]
110
+ python_functions = ["test_*"]
111
+ markers = [
112
+ "unit: Unit tests",
113
+ "integration: Integration tests",
114
+ "slow: Slow running tests",
115
+ "api: API tests",
116
+ "db: Database tests",
117
+ ]
118
+ addopts = [
119
+ "-v",
120
+ "--strict-markers",
121
+ "--tb=short",
122
+ "--cov=src",
123
+ "--cov-report=term-missing",
124
+ "--cov-report=html",
125
+ "--cov-report=xml",
126
+ "--cov-fail-under=80",
127
+ ]
128
+
129
+ # Coverage configuration
130
+ [tool.coverage.run]
131
+ source = ["src"]
132
+ omit = [
133
+ "tests/*",
134
+ "alembic/*",
135
+ "*/__init__.py",
136
+ ]
137
+ branch = true
138
+
139
+ [tool.coverage.report]
140
+ precision = 2
141
+ show_missing = true
142
+ skip_covered = false
143
+ fail_under = 80
144
+ exclude_lines = [
145
+ "pragma: no cover",
146
+ "def __repr__",
147
+ "raise AssertionError",
148
+ "raise NotImplementedError",
149
+ "if __name__ == .__main__.:",
150
+ "if TYPE_CHECKING:",
151
+ "@abstractmethod",
152
+ ]
153
+
154
+ # Bandit security configuration
155
+ [tool.bandit]
156
+ exclude_dirs = ["tests", ".venv", "venv", "alembic/versions"]
157
+ skips = ["B101"]
158
+
159
+ # Scripts
160
+ [project.scripts]
161
+ dev = "uvicorn src.main:app --reload --host 0.0.0.0 --port 8000"
162
+ prod = "gunicorn src.main:app -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000"
@@ -0,0 +1,25 @@
1
+ # Production Dependencies for {project_name}
2
+
3
+ # Monitoring & Metrics
4
+ prometheus-client==0.23.1
5
+ statsd==4.0.1
6
+
7
+ # Structured Logging
8
+ structlog==25.5.0
9
+ python-json-logger==4.0.0
10
+
11
+ # Health Checks
12
+ fastapi-health==0.4.0
13
+
14
+ # Error Tracking
15
+ sentry-sdk==2.27.0
16
+
17
+ # OpenTelemetry (optional - may conflict with semgrep)
18
+ opentelemetry-api==1.38.0
19
+ opentelemetry-sdk==1.38.0
20
+ opentelemetry-instrumentation==0.59b0
21
+ opentelemetry-instrumentation-fastapi==0.59b0
22
+ opentelemetry-exporter-otlp==1.38.0
23
+
24
+ # Performance
25
+ gunicorn==23.0.0
@@ -0,0 +1,19 @@
1
+ """
2
+ Prometheus metrics endpoint
3
+ """
4
+
5
+ from fastapi import APIRouter, Response # type: ignore[import-not-found]
6
+ from src.core.monitoring import get_metrics # type: ignore[import-not-found]
7
+
8
+ router = APIRouter()
9
+
10
+
11
+ @router.get("/metrics")
12
+ async def metrics() -> Response:
13
+ """
14
+ Prometheus metrics endpoint.
15
+
16
+ Returns:
17
+ Response: Prometheus metrics in text format
18
+ """
19
+ return get_metrics()
@@ -0,0 +1,74 @@
1
+ """
2
+ Structured logging configuration using structlog
3
+ """
4
+
5
+ import logging
6
+ import sys
7
+ from typing import Any
8
+
9
+ import structlog # type: ignore[import-not-found]
10
+ from src.core.config import settings # type: ignore[import-not-found]
11
+ from structlog.types import EventDict, Processor # type: ignore[import-not-found]
12
+
13
+
14
+ def add_app_context(logger: Any, method_name: str, event_dict: EventDict) -> EventDict:
15
+ """
16
+ Add application context to log events.
17
+
18
+ Args:
19
+ logger: Logger instance
20
+ method_name: Method name
21
+ event_dict: Event dictionary
22
+
23
+ Returns:
24
+ EventDict: Updated event dictionary
25
+ """
26
+ event_dict["app"] = settings.APP_NAME
27
+ event_dict["env"] = settings.ENVIRONMENT
28
+ return event_dict
29
+
30
+
31
+ def configure_logging() -> None:
32
+ """
33
+ Configure structured logging with structlog.
34
+ """
35
+ # Determine log level
36
+ log_level = getattr(logging, settings.LOG_LEVEL.upper(), logging.INFO) # type: ignore[attr-defined]
37
+
38
+ # Configure standard library logging
39
+ logging.basicConfig( # type: ignore[attr-defined]
40
+ format="%(message)s",
41
+ stream=sys.stdout,
42
+ level=log_level,
43
+ )
44
+
45
+ # Configure structlog
46
+ processors: list[Processor] = [
47
+ structlog.contextvars.merge_contextvars,
48
+ add_app_context,
49
+ structlog.stdlib.add_log_level,
50
+ structlog.stdlib.add_logger_name,
51
+ structlog.processors.TimeStamper(fmt="iso"),
52
+ structlog.processors.StackInfoRenderer(),
53
+ ]
54
+
55
+ # Add JSON or console rendering based on settings
56
+ if settings.LOG_FORMAT == "json":
57
+ processors.append(structlog.processors.JSONRenderer())
58
+ else:
59
+ processors.append(structlog.dev.ConsoleRenderer())
60
+
61
+ structlog.configure(
62
+ processors=processors,
63
+ wrapper_class=structlog.stdlib.BoundLogger,
64
+ context_class=dict,
65
+ logger_factory=structlog.stdlib.LoggerFactory(),
66
+ cache_logger_on_first_use=True,
67
+ )
68
+
69
+
70
+ # Initialize logging
71
+ configure_logging()
72
+
73
+ # Create logger instance
74
+ logger = structlog.get_logger()
@@ -0,0 +1,68 @@
1
+ """
2
+ Prometheus metrics setup for monitoring
3
+ """
4
+
5
+ from fastapi import Response # type: ignore[import-not-found]
6
+ from prometheus_client import ( # type: ignore[import-not-found]
7
+ CONTENT_TYPE_LATEST,
8
+ CollectorRegistry,
9
+ Counter,
10
+ Gauge,
11
+ Histogram,
12
+ generate_latest,
13
+ )
14
+
15
+ # Create a custom registry
16
+ registry = CollectorRegistry()
17
+
18
+ # Request metrics
19
+ http_requests_total = Counter(
20
+ "http_requests_total",
21
+ "Total HTTP requests",
22
+ ["method", "endpoint", "status"],
23
+ registry=registry,
24
+ )
25
+
26
+ http_request_duration_seconds = Histogram(
27
+ "http_request_duration_seconds",
28
+ "HTTP request duration in seconds",
29
+ ["method", "endpoint"],
30
+ registry=registry,
31
+ )
32
+
33
+ # Application metrics
34
+ active_users = Gauge(
35
+ "active_users",
36
+ "Number of active users",
37
+ registry=registry,
38
+ )
39
+
40
+ database_connections = Gauge(
41
+ "database_connections",
42
+ "Number of active database connections",
43
+ registry=registry,
44
+ )
45
+
46
+ # Business metrics
47
+ items_created_total = Counter(
48
+ "items_created_total",
49
+ "Total number of items created",
50
+ registry=registry,
51
+ )
52
+
53
+ items_deleted_total = Counter(
54
+ "items_deleted_total",
55
+ "Total number of items deleted",
56
+ registry=registry,
57
+ )
58
+
59
+
60
+ def get_metrics() -> Response:
61
+ """
62
+ Generate Prometheus metrics response.
63
+
64
+ Returns:
65
+ Response: Prometheus metrics in text format
66
+ """
67
+ metrics = generate_latest(registry)
68
+ return Response(content=metrics, media_type=CONTENT_TYPE_LATEST)
@@ -0,0 +1,66 @@
1
+ """
2
+ Sentry error tracking integration
3
+ """
4
+
5
+ from typing import Any
6
+
7
+ import sentry_sdk # type: ignore[import-not-found]
8
+ from sentry_sdk.integrations.fastapi import FastApiIntegration # type: ignore[import-not-found]
9
+ from sentry_sdk.integrations.sqlalchemy import (
10
+ SqlalchemyIntegration, # type: ignore[import-not-found]
11
+ )
12
+ from src.core.config import settings # type: ignore[import-not-found]
13
+
14
+
15
+ def initialize_sentry() -> None:
16
+ """
17
+ Initialize Sentry SDK for error tracking.
18
+ Only initializes in non-development environments.
19
+ """
20
+ # Only initialize Sentry in production/staging
21
+ if settings.ENVIRONMENT == "development":
22
+ return
23
+
24
+ # Check if Sentry DSN is configured
25
+ sentry_dsn = getattr(settings, "SENTRY_DSN", None)
26
+ if not sentry_dsn:
27
+ return
28
+
29
+ sentry_sdk.init(
30
+ dsn=sentry_dsn,
31
+ environment=settings.ENVIRONMENT,
32
+ release=f"{settings.APP_NAME}@{settings.APP_VERSION}",
33
+ traces_sample_rate=0.1, # 10% of transactions for performance monitoring
34
+ profiles_sample_rate=0.1, # 10% of transactions for profiling
35
+ integrations=[
36
+ FastApiIntegration(),
37
+ SqlalchemyIntegration(),
38
+ ],
39
+ # Set traces_sample_rate to 1.0 to capture 100% of transactions
40
+ # Adjust this value in production to reduce overhead
41
+ send_default_pii=False, # Don't send personally identifiable information
42
+ before_send=before_send_filter,
43
+ )
44
+
45
+
46
+ def before_send_filter(event: dict[str, Any], hint: dict[str, Any]) -> dict[str, Any] | None:
47
+ """
48
+ Filter events before sending to Sentry.
49
+
50
+ Args:
51
+ event: Sentry event
52
+ hint: Additional context
53
+
54
+ Returns:
55
+ dict | None: Event to send or None to skip
56
+ """
57
+ # Filter out specific exceptions or add custom logic
58
+ # Example: Don't send 404 errors
59
+ if "exc_info" in hint:
60
+ exc_type, exc_value, tb = hint["exc_info"]
61
+ if exc_type.__name__ == "HTTPException":
62
+ # Don't send HTTP 404 errors
63
+ if hasattr(exc_value, "status_code") and exc_value.status_code == 404:
64
+ return None
65
+
66
+ return event
@@ -0,0 +1,3 @@
1
+ """
2
+ Middleware package for request/response processing
3
+ """