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,72 @@
1
+ """
2
+ Pytest fixtures for testing
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
+
15
+ from src.api.dependencies import get_db # type: ignore[import-not-found]
16
+ from src.main import app # type: ignore[import-not-found]
17
+
18
+
19
+ # Test database URL (use in-memory SQLite for testing)
20
+ TEST_DATABASE_URL = "sqlite+aiosqlite:///:memory:"
21
+
22
+
23
+ @pytest.fixture
24
+ async def db_engine() -> AsyncGenerator[Any, None]:
25
+ """Create a test database engine."""
26
+ engine = create_async_engine(
27
+ TEST_DATABASE_URL,
28
+ echo=False,
29
+ future=True,
30
+ )
31
+
32
+ async with engine.begin() as conn:
33
+ await conn.run_sync(SQLModel.metadata.create_all)
34
+
35
+ yield engine
36
+
37
+ async with engine.begin() as conn:
38
+ await conn.run_sync(SQLModel.metadata.drop_all)
39
+
40
+ await engine.dispose()
41
+
42
+
43
+ @pytest.fixture
44
+ async def db_session(db_engine: Any) -> AsyncGenerator[AsyncSession, None]:
45
+ """Create a test database session."""
46
+ async_session_maker = sessionmaker(
47
+ 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
57
+ async def client(db_session: AsyncSession) -> AsyncGenerator[AsyncClient, None]:
58
+ """
59
+ Create a test client with database session override.
60
+ """
61
+
62
+ async def override_get_db() -> AsyncGenerator[AsyncSession, None]:
63
+ yield db_session
64
+
65
+ app.dependency_overrides[get_db] = override_get_db
66
+
67
+ async with AsyncClient(
68
+ transport=ASGITransport(app=app), base_url="http://test", timeout=30.0
69
+ ) as ac: # nosec B113 - Test client timeout is set to 30 seconds
70
+ yield ac
71
+
72
+ app.dependency_overrides.clear()
@@ -0,0 +1,49 @@
1
+ """
2
+ Tests for main FastAPI application
3
+ """
4
+
5
+ import pytest
6
+ from httpx import AsyncClient # type: ignore[import-not-found]
7
+
8
+
9
+ @pytest.mark.unit
10
+ class TestMainApp:
11
+ """Test cases for main application endpoints."""
12
+
13
+ async def test_root_endpoint(self, client: AsyncClient) -> None:
14
+ """Test root endpoint returns correct information."""
15
+ response = await client.get("/")
16
+
17
+ assert response.status_code == 200
18
+ data = response.json()
19
+ assert "name" in data
20
+ assert "version" in data
21
+ assert "status" in data
22
+ assert data["status"] == "running"
23
+
24
+ async def test_health_check(self, client: AsyncClient) -> None:
25
+ """Test health check endpoint."""
26
+ response = await client.get("/health")
27
+
28
+ assert response.status_code == 200
29
+ data = response.json()
30
+ assert data["status"] == "healthy"
31
+ assert "service" in data
32
+ assert "version" in data
33
+
34
+ async def test_liveness_check(self, client: AsyncClient) -> None:
35
+ """Test liveness check endpoint."""
36
+ response = await client.get("/health/live")
37
+
38
+ assert response.status_code == 200
39
+ data = response.json()
40
+ assert data["status"] == "alive"
41
+
42
+ async def test_readiness_check(self, client: AsyncClient) -> None:
43
+ """Test readiness check endpoint."""
44
+ response = await client.get("/health/ready")
45
+
46
+ assert response.status_code == 200
47
+ data = response.json()
48
+ assert "status" in data
49
+ assert "database" in data
@@ -0,0 +1,3 @@
1
+ """
2
+ Unit tests package
3
+ """
@@ -0,0 +1,113 @@
1
+ """
2
+ Unit tests for example service
3
+ """
4
+
5
+ import pytest
6
+ from sqlmodel.ext.asyncio.session import AsyncSession # type: ignore[import-not-found]
7
+
8
+ from src.models.example import ItemCreate, ItemUpdate # type: ignore[import-not-found]
9
+ from src.services.example import ItemService # type: ignore[import-not-found]
10
+
11
+
12
+ @pytest.mark.unit
13
+ class TestItemService:
14
+ """Test cases for ItemService."""
15
+
16
+ async def test_create_item(self, db_session: AsyncSession) -> None:
17
+ """Test creating an item."""
18
+ service = ItemService(db_session)
19
+ item_data = ItemCreate(
20
+ name="Test Item",
21
+ description="A test item",
22
+ price=9.99,
23
+ )
24
+
25
+ item = await service.create_item(item_data)
26
+
27
+ assert item.id is not None
28
+ assert item.name == "Test Item"
29
+ assert item.description == "A test item"
30
+ assert item.price == 9.99
31
+ assert item.is_active is True
32
+
33
+ async def test_get_item(self, db_session: AsyncSession) -> None:
34
+ """Test retrieving an item."""
35
+ service = ItemService(db_session)
36
+
37
+ # Create an item first
38
+ item_data = ItemCreate(name="Test Item", price=9.99)
39
+ created_item = await service.create_item(item_data)
40
+
41
+ # Retrieve the item
42
+ retrieved_item = await service.get_item(created_item.id)
43
+
44
+ assert retrieved_item is not None
45
+ assert retrieved_item.id == created_item.id
46
+ assert retrieved_item.name == created_item.name
47
+
48
+ async def test_get_nonexistent_item(self, db_session: AsyncSession) -> None:
49
+ """Test retrieving a non-existent item."""
50
+ service = ItemService(db_session)
51
+ item = await service.get_item(999)
52
+ assert item is None
53
+
54
+ async def test_get_items_pagination(self, db_session: AsyncSession) -> None:
55
+ """Test listing items with pagination."""
56
+ service = ItemService(db_session)
57
+
58
+ # Create multiple items (starting from 1 to avoid price=0 validation error)
59
+ for i in range(1, 6):
60
+ item_data = ItemCreate(name=f"Item {i}", price=float(i))
61
+ await service.create_item(item_data)
62
+
63
+ # Test pagination
64
+ items = await service.get_items(skip=0, limit=3)
65
+ assert len(items) == 3
66
+
67
+ items = await service.get_items(skip=3, limit=3)
68
+ assert len(items) == 2
69
+
70
+ async def test_update_item(self, db_session: AsyncSession) -> None:
71
+ """Test updating an item."""
72
+ service = ItemService(db_session)
73
+
74
+ # Create an item
75
+ item_data = ItemCreate(name="Original Name", price=10.0)
76
+ created_item = await service.create_item(item_data)
77
+
78
+ # Update the item
79
+ update_data = ItemUpdate(name="Updated Name", price=15.0)
80
+ updated_item = await service.update_item(created_item.id, update_data)
81
+
82
+ assert updated_item is not None
83
+ assert updated_item.name == "Updated Name"
84
+ assert updated_item.price == 15.0
85
+
86
+ async def test_update_nonexistent_item(self, db_session: AsyncSession) -> None:
87
+ """Test updating a non-existent item."""
88
+ service = ItemService(db_session)
89
+ update_data = ItemUpdate(name="Updated Name")
90
+ result = await service.update_item(999, update_data)
91
+ assert result is None
92
+
93
+ async def test_delete_item(self, db_session: AsyncSession) -> None:
94
+ """Test deleting an item."""
95
+ service = ItemService(db_session)
96
+
97
+ # Create an item
98
+ item_data = ItemCreate(name="To Delete", price=10.0)
99
+ created_item = await service.create_item(item_data)
100
+
101
+ # Delete the item
102
+ success = await service.delete_item(created_item.id)
103
+ assert success is True
104
+
105
+ # Verify deletion
106
+ deleted_item = await service.get_item(created_item.id)
107
+ assert deleted_item is None
108
+
109
+ async def test_delete_nonexistent_item(self, db_session: AsyncSession) -> None:
110
+ """Test deleting a non-existent item."""
111
+ service = ItemService(db_session)
112
+ success = await service.delete_item(999)
113
+ assert success is False
@@ -0,0 +1,130 @@
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
+ [build-system]
39
+ requires = ["setuptools>=61.0"]
40
+ build-backend = "setuptools.build_meta"
41
+
42
+ [tool.setuptools]
43
+ packages = ["src"]
44
+
45
+ # Ruff configuration
46
+ [tool.ruff]
47
+ line-length = 100
48
+ target-version = "py311"
49
+
50
+ select = [
51
+ "E", # pycodestyle errors
52
+ "W", # pycodestyle warnings
53
+ "F", # pyflakes
54
+ "I", # isort
55
+ "N", # pep8-naming
56
+ "UP", # pyupgrade
57
+ "B", # flake8-bugbear
58
+ "S", # bandit security checks
59
+ ]
60
+
61
+ ignore = [
62
+ "E501", # line too long (handled by formatter)
63
+ "S101", # assert used (we use asserts in tests)
64
+ ]
65
+
66
+ exclude = [
67
+ ".git",
68
+ ".venv",
69
+ "__pycache__",
70
+ "alembic/versions",
71
+ ".pytest_cache",
72
+ ]
73
+
74
+ [tool.ruff.format]
75
+ quote-style = "double"
76
+ indent-style = "space"
77
+
78
+ [tool.ruff.isort]
79
+ known-first-party = ["src"]
80
+
81
+ [tool.ruff.per-file-ignores]
82
+ "tests/*" = ["S101"]
83
+
84
+ # Pytest configuration
85
+ [tool.pytest.ini_options]
86
+ asyncio_mode = "auto"
87
+ testpaths = ["tests"]
88
+ python_files = ["test_*.py", "*_test.py"]
89
+ python_classes = ["Test*"]
90
+ python_functions = ["test_*"]
91
+ addopts = [
92
+ "-v",
93
+ "--strict-markers",
94
+ "--tb=short",
95
+ "--cov=src",
96
+ "--cov-report=term-missing",
97
+ "--cov-fail-under=80",
98
+ ]
99
+
100
+ # Coverage configuration
101
+ [tool.coverage.run]
102
+ source = ["src"]
103
+ omit = [
104
+ "tests/*",
105
+ "alembic/*",
106
+ "*/__init__.py",
107
+ ]
108
+
109
+ [tool.coverage.report]
110
+ precision = 2
111
+ show_missing = true
112
+ skip_covered = false
113
+ exclude_lines = [
114
+ "pragma: no cover",
115
+ "def __repr__",
116
+ "raise AssertionError",
117
+ "raise NotImplementedError",
118
+ "if __name__ == .__main__.:",
119
+ "if TYPE_CHECKING:",
120
+ "@abstractmethod",
121
+ ]
122
+
123
+ # Bandit security configuration
124
+ [tool.bandit]
125
+ exclude_dirs = ["tests", ".venv", "venv", "alembic/versions"]
126
+ skips = ["B101"]
127
+
128
+ # Scripts
129
+ [project.scripts]
130
+ dev = "uvicorn src.main:app --reload --host 0.0.0.0 --port 8000"
@@ -0,0 +1,99 @@
1
+ """
2
+ Locust load testing configuration for FastAPI application
3
+ https://docs.locust.io/
4
+ """
5
+
6
+ from locust import HttpUser, between, task # type: ignore[import-not-found]
7
+
8
+
9
+ class FastAPIUser(HttpUser):
10
+ """
11
+ Simulated user for load testing the FastAPI application.
12
+ """
13
+
14
+ # Wait time between tasks (in seconds)
15
+ wait_time = between(1, 3)
16
+
17
+ # Base host will be set via command line: locust --host=http://localhost:8000
18
+
19
+ @task(3)
20
+ def get_root(self) -> None:
21
+ """Test the root endpoint (higher weight = 3)."""
22
+ self.client.get("/")
23
+
24
+ @task(5)
25
+ def health_check(self) -> None:
26
+ """Test the health check endpoint (higher weight = 5)."""
27
+ self.client.get("/health")
28
+
29
+ @task(2)
30
+ def list_items(self) -> None:
31
+ """Test listing items."""
32
+ self.client.get("/api/v1/items")
33
+
34
+ @task(1)
35
+ def create_item(self) -> None:
36
+ """Test creating an item."""
37
+ self.client.post(
38
+ "/api/v1/items",
39
+ json={
40
+ "name": "Load Test Item",
41
+ "description": "Created during load testing",
42
+ "price": 99.99,
43
+ },
44
+ )
45
+
46
+ @task(1)
47
+ def get_item(self) -> None:
48
+ """Test getting a specific item."""
49
+ # Note: This assumes item with ID 1 exists
50
+ # In production, you'd create items first
51
+ with self.client.get("/api/v1/items/1", catch_response=True) as response:
52
+ if response.status_code == 404:
53
+ response.success() # Mark as success even if not found
54
+
55
+ def on_start(self) -> None:
56
+ """
57
+ Called when a simulated user starts.
58
+ Use this to set up test data or authenticate.
59
+ """
60
+ # Example: Create test items
61
+ for i in range(3):
62
+ self.client.post(
63
+ "/api/v1/items",
64
+ json={
65
+ "name": f"Test Item {i}",
66
+ "description": f"Description {i}",
67
+ "price": 10.0 * (i + 1),
68
+ },
69
+ )
70
+
71
+ def on_stop(self) -> None:
72
+ """
73
+ Called when a simulated user stops.
74
+ Use this to clean up test data.
75
+ """
76
+ pass
77
+
78
+
79
+ class AdminUser(HttpUser):
80
+ """
81
+ Simulated admin user with different behavior patterns.
82
+ """
83
+
84
+ wait_time = between(2, 5)
85
+
86
+ @task(1)
87
+ def check_readiness(self) -> None:
88
+ """Test the readiness check endpoint."""
89
+ self.client.get("/health/ready")
90
+
91
+ @task(1)
92
+ def check_liveness(self) -> None:
93
+ """Test the liveness check endpoint."""
94
+ self.client.get("/health/live")
95
+
96
+
97
+ # Run with:
98
+ # locust --host=http://localhost:8000
99
+ # locust --host=http://localhost:8000 --users 100 --spawn-rate 10 --run-time 1m
@@ -0,0 +1,53 @@
1
+ """
2
+ Mutation testing configuration for mutmut
3
+ https://mutmut.readthedocs.io/
4
+ """
5
+
6
+ from typing import Any
7
+
8
+
9
+ def pre_mutation(context: Any) -> None:
10
+ """
11
+ Called before each mutation is tested.
12
+ Can be used to skip certain mutations.
13
+ """
14
+ # Skip mutations in test files
15
+ if "test_" in context.filename:
16
+ context.skip = True
17
+
18
+ # Skip mutations in migration files
19
+ if "alembic/versions" in context.filename:
20
+ context.skip = True
21
+
22
+
23
+ def post_mutation(context: Any) -> None:
24
+ """
25
+ Called after each mutation is tested.
26
+ Can be used for custom reporting.
27
+ """
28
+ pass
29
+
30
+
31
+ # Paths to mutate
32
+ paths_to_mutate = "src/"
33
+
34
+ # Paths to exclude from mutation
35
+ paths_to_exclude = [
36
+ "tests/",
37
+ "alembic/",
38
+ "__pycache__/",
39
+ ".venv/",
40
+ ]
41
+
42
+ # Test command
43
+ tests_dir = "tests/"
44
+ test_command = "pytest -x --tb=short"
45
+
46
+ # Runner configuration
47
+ runner = "python"
48
+
49
+ # Coverage threshold (percentage)
50
+ coverage_threshold = 80
51
+
52
+ # Mutation operators to use
53
+ dict_synonyms = ["dict", "OrderedDict", "defaultdict"]
@@ -0,0 +1,150 @@
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
+ [build-system]
48
+ requires = ["setuptools>=61.0"]
49
+ build-backend = "setuptools.build_meta"
50
+
51
+ [tool.setuptools]
52
+ packages = ["src"]
53
+
54
+ # Ruff configuration
55
+ [tool.ruff]
56
+ line-length = 100
57
+ target-version = "py311"
58
+
59
+ select = [
60
+ "E", # pycodestyle errors
61
+ "W", # pycodestyle warnings
62
+ "F", # pyflakes
63
+ "I", # isort
64
+ "N", # pep8-naming
65
+ "UP", # pyupgrade
66
+ "B", # flake8-bugbear
67
+ "S", # bandit security checks
68
+ ]
69
+
70
+ ignore = [
71
+ "E501", # line too long (handled by formatter)
72
+ "S101", # assert used (we use asserts in tests)
73
+ ]
74
+
75
+ exclude = [
76
+ ".git",
77
+ ".venv",
78
+ "__pycache__",
79
+ "alembic/versions",
80
+ ".pytest_cache",
81
+ ]
82
+
83
+ [tool.ruff.format]
84
+ quote-style = "double"
85
+ indent-style = "space"
86
+
87
+ [tool.ruff.isort]
88
+ known-first-party = ["src"]
89
+
90
+ [tool.ruff.per-file-ignores]
91
+ "tests/*" = ["S101"]
92
+
93
+ # Pytest configuration
94
+ [tool.pytest.ini_options]
95
+ asyncio_mode = "auto"
96
+ testpaths = ["tests"]
97
+ python_files = ["test_*.py", "*_test.py"]
98
+ python_classes = ["Test*"]
99
+ python_functions = ["test_*"]
100
+ markers = [
101
+ "unit: Unit tests",
102
+ "integration: Integration tests",
103
+ "slow: Slow running tests",
104
+ "api: API tests",
105
+ "db: Database tests",
106
+ ]
107
+ addopts = [
108
+ "-v",
109
+ "--strict-markers",
110
+ "--tb=short",
111
+ "--cov=src",
112
+ "--cov-report=term-missing",
113
+ "--cov-report=html",
114
+ "--cov-report=xml",
115
+ "--cov-fail-under=80",
116
+ ]
117
+
118
+ # Coverage configuration
119
+ [tool.coverage.run]
120
+ source = ["src"]
121
+ omit = [
122
+ "tests/*",
123
+ "alembic/*",
124
+ "*/__init__.py",
125
+ ]
126
+ branch = true
127
+
128
+ [tool.coverage.report]
129
+ precision = 2
130
+ show_missing = true
131
+ skip_covered = false
132
+ fail_under = 80
133
+ exclude_lines = [
134
+ "pragma: no cover",
135
+ "def __repr__",
136
+ "raise AssertionError",
137
+ "raise NotImplementedError",
138
+ "if __name__ == .__main__.:",
139
+ "if TYPE_CHECKING:",
140
+ "@abstractmethod",
141
+ ]
142
+
143
+ # Bandit security configuration
144
+ [tool.bandit]
145
+ exclude_dirs = ["tests", ".venv", "venv", "alembic/versions"]
146
+ skips = ["B101"]
147
+
148
+ # Scripts
149
+ [project.scripts]
150
+ dev = "uvicorn src.main:app --reload --host 0.0.0.0 --port 8000"
@@ -0,0 +1,3 @@
1
+ """
2
+ Integration tests package
3
+ """