framework-py 0.1.0.dev1__tar.gz → 0.1.0.dev3__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 (348) hide show
  1. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/PKG-INFO +1 -1
  2. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/pyproject.toml +2 -2
  3. framework_py-0.1.0.dev3/scripts/build_docs.py +377 -0
  4. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/scripts/sync_assets.py +2 -0
  5. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/__main__.py +6 -1
  6. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/_assets/hooks/pre-commit +14 -6
  7. framework_py-0.1.0.dev3/src/framework/_assets/schema/docs-reference.v1.json +137 -0
  8. framework_py-0.1.0.dev3/src/framework/_pages.py +228 -0
  9. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/_paths.py +10 -0
  10. framework_py-0.1.0.dev3/src/framework/_private.py +69 -0
  11. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/ai.py +4 -1
  12. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/bootstrap.py +8 -2
  13. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/cache.py +20 -2
  14. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/catalog.py +72 -20
  15. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/cloud.py +80 -9
  16. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/config_home.py +19 -2
  17. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/connections.py +44 -1
  18. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/console.py +6 -1
  19. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/create.py +59 -14
  20. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/data.py +43 -23
  21. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/global_config.py +65 -5
  22. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/hooks.py +47 -2
  23. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/notebooks.py +94 -4
  24. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/outputs.py +16 -1
  25. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/packages.py +19 -1
  26. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/project.py +7 -0
  27. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/quarto.py +44 -4
  28. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/scaffold.py +17 -2
  29. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/scratch.py +1 -1
  30. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/security.py +13 -11
  31. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/settings.py +56 -8
  32. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/spec/check.py +10 -1
  33. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/spec/resolve.py +7 -1
  34. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/storage.py +178 -41
  35. {framework_py-0.1.0.dev1/tests/golden/no-assistants/expected/.agents → framework_py-0.1.0.dev3/src/framework/templates}/skills/framework-outputs/SKILL.md +5 -5
  36. {framework_py-0.1.0.dev1/tests/golden/project-sensitive/expected/.claude → framework_py-0.1.0.dev3/src/framework/templates}/skills/framework-sensitive-data/SKILL.md +3 -2
  37. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/.claude/skills/framework-outputs/SKILL.md +5 -5
  38. {framework_py-0.1.0.dev1/src/framework/templates → framework_py-0.1.0.dev3/tests/golden/files-and-skills/expected/.claude}/skills/framework-outputs/SKILL.md +5 -5
  39. {framework_py-0.1.0.dev1/tests/golden/files-and-skills/expected/.claude → framework_py-0.1.0.dev3/tests/golden/no-assistants/expected/.agents}/skills/framework-outputs/SKILL.md +5 -5
  40. framework_py-0.1.0.dev3/tests/golden/presentation/expected/.claude/skills/framework-outputs/SKILL.md +68 -0
  41. framework_py-0.1.0.dev3/tests/golden/project/expected/.claude/skills/framework-outputs/SKILL.md +68 -0
  42. framework_py-0.1.0.dev3/tests/golden/project-sensitive/expected/.claude/skills/framework-outputs/SKILL.md +68 -0
  43. {framework_py-0.1.0.dev1/tests/golden/sensitive-facet → framework_py-0.1.0.dev3/tests/golden/project-sensitive}/expected/.claude/skills/framework-sensitive-data/SKILL.md +3 -2
  44. framework_py-0.1.0.dev3/tests/golden/removals-and-assistants/expected/.agents/skills/framework-outputs/SKILL.md +68 -0
  45. framework_py-0.1.0.dev3/tests/golden/sensitive-facet/expected/.claude/skills/framework-outputs/SKILL.md +68 -0
  46. {framework_py-0.1.0.dev1/src/framework/templates → framework_py-0.1.0.dev3/tests/golden/sensitive-facet/expected/.claude}/skills/framework-sensitive-data/SKILL.md +3 -2
  47. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/integration/test_servers.py +1 -1
  48. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_bootstrap.py +28 -0
  49. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_catalog.py +53 -0
  50. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_cloud.py +35 -0
  51. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_create.py +33 -1
  52. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_data.py +66 -0
  53. framework_py-0.1.0.dev3/tests/test_docs_site.py +82 -0
  54. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_hooks.py +2 -1
  55. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_package.py +2 -2
  56. framework_py-0.1.0.dev3/tests/test_pages.py +201 -0
  57. framework_py-0.1.0.dev3/tests/test_private.py +70 -0
  58. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_scaffold.py +45 -0
  59. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_security.py +60 -15
  60. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_settings.py +36 -0
  61. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_storage.py +13 -12
  62. framework_py-0.1.0.dev1/tests/golden/presentation/expected/.claude/skills/framework-outputs/SKILL.md +0 -68
  63. framework_py-0.1.0.dev1/tests/golden/project/expected/.claude/skills/framework-outputs/SKILL.md +0 -68
  64. framework_py-0.1.0.dev1/tests/golden/project-sensitive/expected/.claude/skills/framework-outputs/SKILL.md +0 -68
  65. framework_py-0.1.0.dev1/tests/golden/removals-and-assistants/expected/.agents/skills/framework-outputs/SKILL.md +0 -68
  66. framework_py-0.1.0.dev1/tests/golden/sensitive-facet/expected/.claude/skills/framework-outputs/SKILL.md +0 -68
  67. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/.gitignore +0 -0
  68. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/LICENSE +0 -0
  69. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/README.md +0 -0
  70. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/parity.toml +0 -0
  71. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/scripts/__init__.py +0 -0
  72. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/scripts/check_parity.py +0 -0
  73. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/scripts/make_golden_trees.py +0 -0
  74. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/scripts/make_r_fixtures.R +0 -0
  75. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/__init__.py +0 -0
  76. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/_assets/init.sql +0 -0
  77. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/_assets/schema/layer.v1.json +0 -0
  78. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/_assets/schema/layers.v1.json +0 -0
  79. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/_assets/schema/spec.v1.json +0 -0
  80. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/_log.py +0 -0
  81. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/_secretservice.py +0 -0
  82. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/_time.py +0 -0
  83. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/_wincred.py +0 -0
  84. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/_yaml.py +0 -0
  85. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/db.py +0 -0
  86. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/dotenv.py +0 -0
  87. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/errors.py +0 -0
  88. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/integrity.py +0 -0
  89. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/py.typed +0 -0
  90. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/spec/__init__.py +0 -0
  91. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/spec/merge.py +0 -0
  92. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/defaults.yml +0 -0
  93. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/gitignore/course +0 -0
  94. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/gitignore/presentation +0 -0
  95. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/gitignore/project +0 -0
  96. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/gitignore/sensitive +0 -0
  97. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/skills/framework-data/SKILL.md +0 -0
  98. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/skills/framework-packages/SKILL.md +0 -0
  99. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/skills/framework-workflow/SKILL.md +0 -0
  100. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/stubs/notebook-default.ipynb +0 -0
  101. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/stubs/notebook-default.qmd +0 -0
  102. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/stubs/notebook-minimal.qmd +0 -0
  103. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/stubs/notebook-revealjs.qmd +0 -0
  104. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/src/framework/templates/stubs/script-default.py +0 -0
  105. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/__init__.py +0 -0
  106. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/conftest.py +0 -0
  107. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/.claude/skills/framework-data/SKILL.md +0 -0
  108. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/.claude/skills/framework-outputs/SKILL.md +0 -0
  109. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/.claude/skills/framework-packages/SKILL.md +0 -0
  110. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/.claude/skills/framework-workflow/SKILL.md +0 -0
  111. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/.env +0 -0
  112. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/.framework/spec.json +0 -0
  113. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/.gitignore +0 -0
  114. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/AGENTS.md +0 -0
  115. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/CLAUDE.md +0 -0
  116. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/_quarto.yml +0 -0
  117. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/docs/_quarto.yml +0 -0
  118. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/fixture-study.Rproj +0 -0
  119. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/fixture-study.code-workspace +0 -0
  120. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/framework.db +0 -0
  121. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/inputs/intermediate/r_clean.csv +0 -0
  122. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/inputs/private/ids.csv +0 -0
  123. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/inputs/raw/survey.csv +0 -0
  124. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/inputs/raw/visits.tsv +0 -0
  125. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/inputs/reference/test.dta +0 -0
  126. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/inputs/reference/test.sav +0 -0
  127. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/inputs/reference/test.xpt +0 -0
  128. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/notebooks/_quarto.yml +0 -0
  129. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/outputs/cache/r_value.rds +0 -0
  130. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/outputs/tables/r_summary.csv +0 -0
  131. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/scaffold.R +0 -0
  132. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/settings/ai.yml +0 -0
  133. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/settings/author.yml +0 -0
  134. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/settings/connections.yml +0 -0
  135. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/settings/data.yml +0 -0
  136. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/settings/git.yml +0 -0
  137. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/settings/packages.yml +0 -0
  138. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/settings/quarto.yml +0 -0
  139. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/settings/scaffold.yml +0 -0
  140. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project/settings.yml +0 -0
  141. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/fixtures/r_project.expected.json +0 -0
  142. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/bare/expected/.framework/spec.json +0 -0
  143. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/bare/expected/.gitignore +0 -0
  144. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/bare/expected/pyproject.toml +0 -0
  145. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/bare/expected/settings.yml +0 -0
  146. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/bare/layers.json +0 -0
  147. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/.claude/skills/framework-data/SKILL.md +0 -0
  148. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/.claude/skills/framework-packages/SKILL.md +0 -0
  149. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/.claude/skills/framework-workflow/SKILL.md +0 -0
  150. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/.env +0 -0
  151. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/.framework/spec.json +0 -0
  152. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/.gitignore +0 -0
  153. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/AGENTS.md +0 -0
  154. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/CLAUDE.md +0 -0
  155. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/_quarto.yml +0 -0
  156. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/assignments/_quarto.yml +0 -0
  157. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/course_docs/_quarto.yml +0 -0
  158. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/golden-course.code-workspace +0 -0
  159. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/modules/_quarto.yml +0 -0
  160. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/pyproject.toml +0 -0
  161. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/scaffold.py +0 -0
  162. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/settings.yml +0 -0
  163. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/expected/slides/_quarto.yml +0 -0
  164. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/course/layers.json +0 -0
  165. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/.claude/skills/framework-data/SKILL.md +0 -0
  166. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/.claude/skills/framework-packages/SKILL.md +0 -0
  167. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/.claude/skills/framework-workflow/SKILL.md +0 -0
  168. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/.claude/skills/study-protocol/SKILL.md +0 -0
  169. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/.claude/skills/study-protocol/references/consort.md +0 -0
  170. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/.env +0 -0
  171. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/.framework/spec.json +0 -0
  172. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/.gitignore +0 -0
  173. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/AGENTS.md +0 -0
  174. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/CLAUDE.md +0 -0
  175. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/README.md +0 -0
  176. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/_quarto.yml +0 -0
  177. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/docs/_quarto.yml +0 -0
  178. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/golden-files-and-skills.code-workspace +0 -0
  179. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/notebooks/_quarto.yml +0 -0
  180. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/notes.md +0 -0
  181. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/pyproject.toml +0 -0
  182. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/scaffold.py +0 -0
  183. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/settings/ai.yml +0 -0
  184. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/settings/author.yml +0 -0
  185. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/settings/connections.yml +0 -0
  186. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/settings/data.yml +0 -0
  187. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/settings/git.yml +0 -0
  188. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/settings/quarto.yml +0 -0
  189. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/settings/scaffold.yml +0 -0
  190. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/expected/settings.yml +0 -0
  191. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/files-and-skills/layers.json +0 -0
  192. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/.agents/skills/framework-data/SKILL.md +0 -0
  193. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/.agents/skills/framework-packages/SKILL.md +0 -0
  194. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/.agents/skills/framework-workflow/SKILL.md +0 -0
  195. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/.env +0 -0
  196. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/.framework/spec.json +0 -0
  197. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/.gitignore +0 -0
  198. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/AGENTS.md +0 -0
  199. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/_quarto.yml +0 -0
  200. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/docs/_quarto.yml +0 -0
  201. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/golden-no-assistants.code-workspace +0 -0
  202. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/notebooks/_quarto.yml +0 -0
  203. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/pyproject.toml +0 -0
  204. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/scaffold.py +0 -0
  205. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/settings/ai.yml +0 -0
  206. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/settings/author.yml +0 -0
  207. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/settings/connections.yml +0 -0
  208. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/settings/data.yml +0 -0
  209. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/settings/git.yml +0 -0
  210. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/settings/quarto.yml +0 -0
  211. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/settings/scaffold.yml +0 -0
  212. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/expected/settings.yml +0 -0
  213. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/no-assistants/layers.json +0 -0
  214. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/.claude/skills/framework-data/SKILL.md +0 -0
  215. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/.claude/skills/framework-packages/SKILL.md +0 -0
  216. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/.claude/skills/framework-workflow/SKILL.md +0 -0
  217. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/.env +0 -0
  218. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/.framework/spec.json +0 -0
  219. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/.gitignore +0 -0
  220. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/AGENTS.md +0 -0
  221. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/CLAUDE.md +0 -0
  222. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/_quarto.yml +0 -0
  223. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/golden-presentation.code-workspace +0 -0
  224. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/presentation.qmd +0 -0
  225. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/pyproject.toml +0 -0
  226. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/scaffold.py +0 -0
  227. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/expected/settings.yml +0 -0
  228. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/presentation/layers.json +0 -0
  229. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/.claude/skills/framework-data/SKILL.md +0 -0
  230. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/.claude/skills/framework-packages/SKILL.md +0 -0
  231. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/.claude/skills/framework-workflow/SKILL.md +0 -0
  232. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/.env +0 -0
  233. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/.framework/spec.json +0 -0
  234. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/.gitignore +0 -0
  235. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/AGENTS.md +0 -0
  236. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/CLAUDE.md +0 -0
  237. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/_quarto.yml +0 -0
  238. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/docs/_quarto.yml +0 -0
  239. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/golden-project.code-workspace +0 -0
  240. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/notebooks/_quarto.yml +0 -0
  241. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/pyproject.toml +0 -0
  242. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/scaffold.py +0 -0
  243. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/settings/ai.yml +0 -0
  244. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/settings/author.yml +0 -0
  245. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/settings/connections.yml +0 -0
  246. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/settings/data.yml +0 -0
  247. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/settings/git.yml +0 -0
  248. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/settings/quarto.yml +0 -0
  249. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/settings/scaffold.yml +0 -0
  250. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/expected/settings.yml +0 -0
  251. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project/layers.json +0 -0
  252. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/.claude/settings.json +0 -0
  253. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/.claude/skills/framework-data/SKILL.md +0 -0
  254. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/.claude/skills/framework-packages/SKILL.md +0 -0
  255. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/.claude/skills/framework-workflow/SKILL.md +0 -0
  256. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/.env +0 -0
  257. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/.framework/spec.json +0 -0
  258. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/.gitignore +0 -0
  259. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/AGENTS.md +0 -0
  260. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/CLAUDE.md +0 -0
  261. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/_quarto.yml +0 -0
  262. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/docs/_quarto.yml +0 -0
  263. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/golden-project-sensitive.code-workspace +0 -0
  264. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/notebooks/_quarto.yml +0 -0
  265. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/pyproject.toml +0 -0
  266. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/scaffold.py +0 -0
  267. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/settings/ai.yml +0 -0
  268. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/settings/author.yml +0 -0
  269. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/settings/connections.yml +0 -0
  270. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/settings/data.yml +0 -0
  271. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/settings/git.yml +0 -0
  272. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/settings/quarto.yml +0 -0
  273. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/settings/scaffold.yml +0 -0
  274. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/expected/settings.yml +0 -0
  275. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/project-sensitive/layers.json +0 -0
  276. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/.agents/skills/framework-data/SKILL.md +0 -0
  277. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/.agents/skills/framework-packages/SKILL.md +0 -0
  278. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/.agents/skills/framework-workflow/SKILL.md +0 -0
  279. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/.env +0 -0
  280. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/.framework/spec.json +0 -0
  281. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/.github/copilot-instructions.md +0 -0
  282. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/.gitignore +0 -0
  283. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/AGENTS.md +0 -0
  284. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/_quarto.yml +0 -0
  285. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/docs/_quarto.yml +0 -0
  286. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/golden-removals-and-assistants.code-workspace +0 -0
  287. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/notebooks/_quarto.yml +0 -0
  288. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/pyproject.toml +0 -0
  289. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/scaffold.py +0 -0
  290. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/settings/ai.yml +0 -0
  291. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/settings/author.yml +0 -0
  292. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/settings/connections.yml +0 -0
  293. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/settings/data.yml +0 -0
  294. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/settings/git.yml +0 -0
  295. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/settings/quarto.yml +0 -0
  296. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/settings/scaffold.yml +0 -0
  297. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/expected/settings.yml +0 -0
  298. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/removals-and-assistants/layers.json +0 -0
  299. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/.claude/settings.json +0 -0
  300. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/.claude/skills/framework-data/SKILL.md +0 -0
  301. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/.claude/skills/framework-packages/SKILL.md +0 -0
  302. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/.claude/skills/framework-workflow/SKILL.md +0 -0
  303. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/.env +0 -0
  304. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/.framework/spec.json +0 -0
  305. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/.gitignore +0 -0
  306. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/AGENTS.md +0 -0
  307. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/CLAUDE.md +0 -0
  308. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/_quarto.yml +0 -0
  309. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/docs/_quarto.yml +0 -0
  310. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/golden-sensitive-facet.code-workspace +0 -0
  311. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/notebooks/_quarto.yml +0 -0
  312. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/pyproject.toml +0 -0
  313. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/scaffold.py +0 -0
  314. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/settings/ai.yml +0 -0
  315. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/settings/author.yml +0 -0
  316. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/settings/connections.yml +0 -0
  317. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/settings/data.yml +0 -0
  318. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/settings/git.yml +0 -0
  319. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/settings/quarto.yml +0 -0
  320. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/settings/scaffold.yml +0 -0
  321. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/expected/settings.yml +0 -0
  322. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/golden/sensitive-facet/layers.json +0 -0
  323. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/integration/compose.yml +0 -0
  324. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/integration/mariadb/init.sql +0 -0
  325. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/integration/mysql/init.sql +0 -0
  326. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/integration/postgres/init.sql +0 -0
  327. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/integration/sqlserver/init.sql +0 -0
  328. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/integration/test_cloud_staging.py +0 -0
  329. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/shared/NAMESPACE +0 -0
  330. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/shared/conformance/README.md +0 -0
  331. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/shared/conformance/merge/atomic-entries.json +0 -0
  332. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/shared/conformance/merge/conflicts-and-labels.json +0 -0
  333. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/shared/conformance/merge/empty-sections.json +0 -0
  334. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/shared/conformance/merge/gitignore-and-assistants.json +0 -0
  335. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/shared/conformance/merge/maps-and-null-removal.json +0 -0
  336. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_cache.py +0 -0
  337. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_config_home.py +0 -0
  338. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_conformance.py +0 -0
  339. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_connections.py +0 -0
  340. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_db.py +0 -0
  341. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_dotenv.py +0 -0
  342. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_global_config.py +0 -0
  343. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_notebooks.py +0 -0
  344. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_outputs.py +0 -0
  345. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_packages.py +0 -0
  346. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_r_compat.py +0 -0
  347. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_r_live.py +0 -0
  348. {framework_py-0.1.0.dev1 → framework_py-0.1.0.dev3}/tests/test_secretservice.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: framework-py
3
- Version: 0.1.0.dev1
3
+ Version: 0.1.0.dev3
4
4
  Summary: Structured data science projects: a data catalog, integrity tracking, caching, outputs, and AI guardrails
5
5
  Project-URL: Homepage, https://framework.pub
6
6
  Project-URL: Source, https://github.com/frameworktools/framework-py
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "framework-py"
3
- version = "0.1.0.dev1"
3
+ version = "0.1.0.dev3"
4
4
  description = "Structured data science projects: a data catalog, integrity tracking, caching, outputs, and AI guardrails"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -85,7 +85,7 @@ strict = true
85
85
  files = ["src", "scripts"]
86
86
 
87
87
  [[tool.mypy.overrides]]
88
- module = ["pyarrow", "pyarrow.*", "keyring", "keyring.*", "secretstorage", "matplotlib", "matplotlib.*", "openpyxl", "pyreadstat", "boto3", "botocore", "botocore.*", "pyodbc", "pymysql", "psycopg", "psycopg.*", "duckdb"]
88
+ module = ["pyarrow", "pyarrow.*", "keyring", "keyring.*", "secretstorage", "jsonschema", "matplotlib", "matplotlib.*", "openpyxl", "pyreadstat", "boto3", "botocore", "botocore.*", "pyodbc", "pymysql", "psycopg", "psycopg.*", "duckdb"]
89
89
  ignore_missing_imports = true
90
90
 
91
91
  [tool.pytest.ini_options]
@@ -0,0 +1,377 @@
1
+ """Build the docs site archive for py.framework.pub.
2
+
3
+ Writes ``reference.json`` from the docstrings of everything in
4
+ ``framework.__all__``, checks it against ``docs-reference.v1.json``, and
5
+ packs ``docs/site`` with it into ``docs-site.tar.gz``. The format is R's
6
+ ``inst/schema/docs-site.md``.
7
+
8
+ python scripts/build_docs.py # check only
9
+ python scripts/build_docs.py --reference out.json # write reference.json
10
+ python scripts/build_docs.py --archive dist-docs/docs-site.tar.gz
11
+
12
+ Docstrings are Google style. The first line is the summary, the paragraphs
13
+ before the first section are the description, and ``Args:`` (or
14
+ ``Attributes:`` for classes), ``Returns:``, and ``Raises:`` become
15
+ parameters, returns, and a section.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import argparse
21
+ import dataclasses
22
+ import inspect
23
+ import io
24
+ import json
25
+ import re
26
+ import sys
27
+ import tarfile
28
+ from pathlib import Path
29
+ from typing import Any
30
+
31
+ import jsonschema
32
+ import yaml
33
+
34
+ import framework
35
+
36
+ ROOT = Path(__file__).resolve().parents[1]
37
+ SITE = ROOT / "docs" / "site"
38
+ SCHEMA = ROOT / "src" / "framework" / "_assets" / "schema" / "docs-reference.v1.json"
39
+
40
+ _SECTION = re.compile(r"^(Args|Arguments|Attributes|Returns|Yields|Raises|Examples?|Notes?):\s*$")
41
+ _ITEM = re.compile(r"^(\*{0,2}[A-Za-z_][A-Za-z0-9_]*)(?:\s*\(([^)]*)\))?:\s*(.*)$")
42
+
43
+
44
+ class DocsError(Exception):
45
+ pass
46
+
47
+
48
+ # Docstrings -------------------------------------------------------------------
49
+
50
+
51
+ def _markdown(text: str) -> str:
52
+ """reStructuredText inline code to Markdown, linking exported names."""
53
+ exported = set(framework.__all__)
54
+
55
+ def code(match: re.Match[str]) -> str:
56
+ inner = match.group(1)
57
+ name = inner.removesuffix("()")
58
+ if name in exported:
59
+ return f"[`{inner}`](ref:{name})"
60
+ return f"`{inner}`"
61
+
62
+ return re.sub(r"``(.+?)``", code, text).strip()
63
+
64
+
65
+ def _dedent_block(lines: list[str]) -> list[str]:
66
+ indents = [len(line) - len(line.lstrip()) for line in lines if line.strip()]
67
+ cut = min(indents, default=0)
68
+ return [line[cut:] for line in lines]
69
+
70
+
71
+ def parse_docstring(doc: str) -> dict[str, Any]:
72
+ """Split a Google-style docstring into summary, description, and sections."""
73
+ lines = doc.strip().splitlines()
74
+ summary = lines[0].strip() if lines else ""
75
+ body: list[str] = []
76
+ sections: dict[str, list[str]] = {}
77
+ current: list[str] = body
78
+ for line in lines[1:]:
79
+ match = _SECTION.match(line)
80
+ if match:
81
+ key = {"Arguments": "Args", "Example": "Examples", "Notes": "Note"}.get(
82
+ match.group(1), match.group(1)
83
+ )
84
+ current = sections.setdefault(key, [])
85
+ continue
86
+ current.append(line)
87
+ paragraphs = re.split(r"\n\s*\n", "\n".join(body).strip())
88
+ paragraphs = [p for p in paragraphs if p.strip()]
89
+ return {
90
+ "summary": summary,
91
+ "description": "\n\n".join(paragraphs[:2]),
92
+ "details": "\n\n".join(paragraphs[2:]),
93
+ "sections": {key: _dedent_block(value) for key, value in sections.items()},
94
+ }
95
+
96
+
97
+ def parse_items(lines: list[str]) -> list[tuple[str, str]]:
98
+ """``name: text`` items, with indented continuation lines folded in."""
99
+ items: list[tuple[str, list[str]]] = []
100
+ for line in lines:
101
+ if not line.strip():
102
+ if items:
103
+ items[-1][1].append("")
104
+ continue
105
+ match = _ITEM.match(line) if not line.startswith(" ") else None
106
+ if match:
107
+ items.append((match.group(1), [match.group(3)]))
108
+ elif items:
109
+ items[-1][1].append(line.strip())
110
+ return [
111
+ (name, re.sub(r"(?<!\n)\n(?!\n)", " ", "\n".join(text).strip())) for name, text in items
112
+ ]
113
+
114
+
115
+ # Entries ----------------------------------------------------------------------
116
+
117
+
118
+ def _annotation(value: Any) -> str | None:
119
+ if value is inspect.Parameter.empty:
120
+ return None
121
+ return value if isinstance(value, str) else str(inspect.formatannotation(value))
122
+
123
+
124
+ def _prefix(param: inspect.Parameter) -> str:
125
+ if param.kind is inspect.Parameter.VAR_POSITIONAL:
126
+ return "*"
127
+ if param.kind is inspect.Parameter.VAR_KEYWORD:
128
+ return "**"
129
+ return ""
130
+
131
+
132
+ def _parameter(param: inspect.Parameter) -> str:
133
+ """A parameter as written in the source, shortening long defaults."""
134
+ text = _prefix(param) + param.name
135
+ annotation = _annotation(param.annotation)
136
+ if annotation:
137
+ text += f": {annotation}"
138
+ if param.default is not param.empty:
139
+ default = repr(param.default)
140
+ if len(default) > 30:
141
+ default = f"{default[0]}...{default[-1]}" if default[0] in "([{" else "..."
142
+ text += f" = {default}" if annotation else f"={default}"
143
+ return text
144
+
145
+
146
+ def _usage(name: str, signature: inspect.Signature) -> str:
147
+ params: list[str] = []
148
+ for param in signature.parameters.values():
149
+ if param.name == "self":
150
+ continue
151
+ if param.kind == param.KEYWORD_ONLY and not any(p.startswith("*") for p in params):
152
+ params.append("*")
153
+ params.append(_parameter(param))
154
+ returns = _annotation(signature.return_annotation)
155
+ tail = f" -> {returns}" if returns else ""
156
+ one_line = f"{name}({', '.join(params)}){tail}"
157
+ if len(one_line) <= 88:
158
+ return one_line
159
+ inner = "".join(f" {p},\n" for p in params)
160
+ return f"{name}(\n{inner}){tail}"
161
+
162
+
163
+ def _signature(obj: Any) -> inspect.Signature | None:
164
+ try:
165
+ return inspect.signature(obj)
166
+ except (TypeError, ValueError):
167
+ return None
168
+
169
+
170
+ def build_entry(name: str, obj: Any, category: str, problems: list[str]) -> dict[str, Any]:
171
+ doc = inspect.getdoc(obj)
172
+ if not doc:
173
+ raise DocsError(f"{name} has no docstring")
174
+ parsed = parse_docstring(doc)
175
+ sections = parsed["sections"]
176
+ is_class = inspect.isclass(obj)
177
+ entry: dict[str, Any] = {
178
+ "id": name,
179
+ "name": name,
180
+ "kind": "class" if is_class else "function",
181
+ "category": category,
182
+ "summary": _markdown(parsed["summary"]),
183
+ }
184
+ for key in ("description", "details"):
185
+ if parsed[key]:
186
+ entry[key] = _markdown(parsed[key])
187
+
188
+ documented = dict(parse_items(sections.get("Attributes" if is_class else "Args", [])))
189
+ parameters: list[dict[str, Any]] = []
190
+ if is_class and dataclasses.is_dataclass(obj):
191
+ for field in dataclasses.fields(obj):
192
+ if field.name.startswith("_"):
193
+ continue
194
+ if field.name not in documented:
195
+ problems.append(f"{name}: attribute '{field.name}' is not documented")
196
+ item: dict[str, Any] = {
197
+ "name": field.name,
198
+ "description": _markdown(documented.get(field.name, "")),
199
+ }
200
+ if _annotation(field.type):
201
+ item["type"] = _annotation(field.type)
202
+ parameters.append(item)
203
+ elif not is_class:
204
+ signature = _signature(obj)
205
+ if signature is None:
206
+ raise DocsError(f"{name}: no signature")
207
+ entry["usage"] = _usage(name, signature)
208
+ for param in signature.parameters.values():
209
+ key = _prefix(param)
210
+ label = f"{key}{param.name}"
211
+ text = documented.get(label) or documented.get(param.name)
212
+ if text is None:
213
+ problems.append(f"{name}: parameter '{param.name}' is not documented")
214
+ item = {"name": label, "description": _markdown(text or "")}
215
+ if _annotation(param.annotation):
216
+ item["type"] = _annotation(param.annotation)
217
+ if param.default is not param.empty:
218
+ item["default"] = repr(param.default)
219
+ elif key == "":
220
+ item["required"] = True
221
+ parameters.append(item)
222
+ if parameters:
223
+ entry["parameters"] = parameters
224
+
225
+ for key in ("Returns", "Yields"):
226
+ if key in sections:
227
+ entry["returns"] = _markdown("\n".join(sections[key]))
228
+ if "Note" in sections:
229
+ entry["note"] = _markdown("\n".join(sections["Note"]))
230
+ if "Raises" in sections:
231
+ raises = "\n".join(
232
+ f"- `{error}`: {_markdown(text)}" for error, text in parse_items(sections["Raises"])
233
+ )
234
+ entry["sections"] = [{"title": "Raises", "content": raises}]
235
+ if "Examples" in sections:
236
+ code = "\n".join(sections["Examples"]).strip()
237
+ code = "\n".join(re.sub(r"^(>>> |\.\.\. )", "", line) for line in code.splitlines())
238
+ entry["examples"] = [{"code": code}]
239
+ return entry
240
+
241
+
242
+ def build_reference(categories: list[dict[str, Any]], problems: list[str]) -> dict[str, Any]:
243
+ exported = list(framework.__all__)
244
+ placed: dict[str, str] = {}
245
+ for category in categories:
246
+ for name in category["names"]:
247
+ if name in placed:
248
+ raise DocsError(f"{name} is in both {placed[name]} and {category['id']}")
249
+ placed[name] = category["id"]
250
+ for name in category.get("common", []):
251
+ if name not in category["names"]:
252
+ raise DocsError(f"{category['id']}: common name {name} is not in its names")
253
+ documented = [name for name in exported if not name.startswith("__")]
254
+ missing = sorted(set(documented) - set(placed))
255
+ unknown = sorted(set(placed) - set(documented))
256
+ if missing or unknown:
257
+ raise DocsError(
258
+ f"categories.yml: missing {missing or 'none'}; not exported {unknown or 'none'}"
259
+ )
260
+ entries = [
261
+ build_entry(name, getattr(framework, name), placed[name], problems)
262
+ for category in categories
263
+ for name in category["names"]
264
+ ]
265
+ return {
266
+ "schema": "docs-reference.v1",
267
+ "product": "py",
268
+ "version": framework.__version__,
269
+ "categories": [
270
+ {
271
+ key: value
272
+ for key, value in {
273
+ "id": category["id"],
274
+ "title": category["title"],
275
+ "description": category.get("description"),
276
+ "position": position,
277
+ "common": category.get("common"),
278
+ }.items()
279
+ if value is not None
280
+ }
281
+ for position, category in enumerate(categories, start=1)
282
+ ],
283
+ "entries": entries,
284
+ }
285
+
286
+
287
+ # Site -------------------------------------------------------------------------
288
+
289
+
290
+ def _prose(markdown: str) -> str:
291
+ """Markdown without fenced code blocks, whose lines are not headings or links."""
292
+ return re.sub(r"^(```|~~~).*?^\1[ \t]*$", "", markdown, flags=re.M | re.S)
293
+
294
+
295
+ def check_site(reference: dict[str, Any]) -> list[str]:
296
+ """Check site.yml, the guides' front matter, and every guide:/ref: link."""
297
+ problems: list[str] = []
298
+ site = yaml.safe_load((SITE / "site.yml").read_text(encoding="utf-8"))
299
+ sections = {section["id"] for section in site["sections"]}
300
+ guides: dict[str, Path] = {}
301
+ for path in sorted((SITE / "guides").glob("*.md")):
302
+ text = path.read_text(encoding="utf-8")
303
+ match = re.match(r"\A---\n(.*?)\n---\n", text, re.S)
304
+ if not match:
305
+ problems.append(f"{path.name}: no front matter")
306
+ continue
307
+ meta = yaml.safe_load(match.group(1)) or {}
308
+ for key in ("id", "title", "description", "section", "position"):
309
+ if key not in meta:
310
+ problems.append(f"{path.name}: front matter is missing {key}")
311
+ if meta.get("section") not in sections:
312
+ problems.append(f"{path.name}: unknown section {meta.get('section')}")
313
+ if meta.get("id") != path.stem:
314
+ problems.append(f"{path.name}: id {meta.get('id')} does not match the file name")
315
+ if re.search(r"^# ", _prose(text[match.end() :]), re.M):
316
+ problems.append(f"{path.name}: guides have no h1")
317
+ guides[path.stem] = path
318
+ ids = {entry["id"] for entry in reference["entries"]}
319
+ texts = [(path.name, _prose(path.read_text(encoding="utf-8"))) for path in guides.values()]
320
+ texts.append(("reference.json", json.dumps(reference)))
321
+ for source, text in texts:
322
+ for kind, target in re.findall(r"\((guide|ref):([^)#\s]+)", text):
323
+ if kind == "guide" and target not in guides:
324
+ problems.append(f"{source}: no guide {target}")
325
+ if kind == "ref" and target not in ids:
326
+ problems.append(f"{source}: no reference entry {target}")
327
+ for image in re.findall(r"\]\((images/[^)\s]+)\)", text):
328
+ if not (SITE / image).is_file():
329
+ problems.append(f"{source}: missing {image}")
330
+ return problems
331
+
332
+
333
+ def write_archive(reference: dict[str, Any], target: Path) -> None:
334
+ target.parent.mkdir(parents=True, exist_ok=True)
335
+ with tarfile.open(target, "w:gz") as archive:
336
+ for path in sorted(SITE.rglob("*")):
337
+ if path.is_file() and path.name != "categories.yml":
338
+ archive.add(path, arcname=f"docs-site/{path.relative_to(SITE).as_posix()}")
339
+ data = (json.dumps(reference, indent=2, ensure_ascii=False) + "\n").encode("utf-8")
340
+ info = tarfile.TarInfo("docs-site/reference.json")
341
+ info.size = len(data)
342
+ archive.addfile(info, io.BytesIO(data))
343
+
344
+
345
+ def main(argv: list[str] | None = None) -> int:
346
+ parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0])
347
+ parser.add_argument("--reference", type=Path, help="write reference.json here")
348
+ parser.add_argument("--archive", type=Path, help="write docs-site.tar.gz here")
349
+ parser.add_argument("--schema", type=Path, default=SCHEMA, help="docs-reference.v1.json")
350
+ args = parser.parse_args(argv)
351
+ problems: list[str] = []
352
+ try:
353
+ categories = yaml.safe_load((SITE / "categories.yml").read_text(encoding="utf-8"))
354
+ reference = build_reference(categories, problems)
355
+ except DocsError as error:
356
+ print(f"error: {error}", file=sys.stderr)
357
+ return 1
358
+ schema = json.loads(args.schema.read_text(encoding="utf-8"))
359
+ errors = sorted(
360
+ jsonschema.Draft202012Validator(schema).iter_errors(reference), key=lambda e: e.path
361
+ )
362
+ problems += [f"reference.json: {list(e.path)}: {e.message}" for e in errors]
363
+ problems += check_site(reference)
364
+ if problems:
365
+ print("\n".join(f"error: {problem}" for problem in problems), file=sys.stderr)
366
+ return 1
367
+ if args.reference:
368
+ args.reference.write_text(json.dumps(reference, indent=2, ensure_ascii=False) + "\n")
369
+ if args.archive:
370
+ write_archive(reference, args.archive)
371
+ guides = len(list((SITE / "guides").glob("*.md")))
372
+ print(f"{len(reference['entries'])} reference entries and {guides} guides are valid")
373
+ return 0
374
+
375
+
376
+ if __name__ == "__main__":
377
+ sys.exit(main())
@@ -28,6 +28,8 @@ WORKTREE = "worktree"
28
28
  # Runtime files go in the package; test-only files go in tests/shared.
29
29
  ASSETS: dict[str, str] = {
30
30
  "inst/schema/*.json": "src/framework/_assets/schema",
31
+ # The docs site format (docs/site, scripts/build_docs.py).
32
+ "inst/schema/docs-site.md": "docs",
31
33
  "inst/templates/init.sql": "src/framework/_assets",
32
34
  "inst/hooks/pre-commit": "src/framework/_assets/hooks",
33
35
  "inst/conformance/README.md": "tests/shared/conformance",
@@ -37,7 +37,12 @@ def _parser() -> argparse.ArgumentParser:
37
37
  create.add_argument(
38
38
  "--interactive",
39
39
  action="store_true",
40
- help="prompt for missing answers, initialize git, and register the project",
40
+ help=(
41
+ "with --name, ask for the type when --type is missing (the project is "
42
+ "registered and gets a git repository either way, unless your defaults turn "
43
+ "git off); with --from-layers, initialize git and register the project "
44
+ "instead of running headless"
45
+ ),
41
46
  )
42
47
 
43
48
  bootstrap = commands.add_parser("bootstrap", help="prepare a cloned project")
@@ -12,23 +12,31 @@ set -u
12
12
 
13
13
  cd "$(git rev-parse --show-toplevel)" || exit 1
14
14
 
15
+ # Each runner returns 127 when its runtime or the framework package is
16
+ # missing, so the next runtime gets a turn and the message below can say why
17
+
15
18
  run_r() {
16
19
  command -v Rscript >/dev/null 2>&1 || return 127
20
+ # framework 1.x from CRAN has no shared hook entry point
21
+ probe='ok <- requireNamespace("framework", quietly = TRUE) && exists(".hook_run", envir = asNamespace("framework"))'
22
+ Rscript -e "$probe; quit(status = if (ok) 0 else 127)" >/dev/null 2>&1 || return 127
17
23
  Rscript -e 'quit(status = framework:::.hook_run("pre-commit"))'
18
24
  }
19
25
 
20
26
  run_python() {
21
27
  if [ -x .venv/bin/python ]; then
22
- .venv/bin/python -m framework hook pre-commit
28
+ set -- .venv/bin/python
23
29
  elif [ -x .venv/Scripts/python.exe ]; then
24
- .venv/Scripts/python.exe -m framework hook pre-commit
30
+ set -- .venv/Scripts/python.exe
25
31
  elif [ -f uv.lock ] && command -v uv >/dev/null 2>&1; then
26
- uv run --frozen python -m framework hook pre-commit
32
+ set -- uv run --frozen python
27
33
  elif command -v python3 >/dev/null 2>&1; then
28
- python3 -m framework hook pre-commit
34
+ set -- python3
29
35
  else
30
36
  return 127
31
37
  fi
38
+ "$@" -c 'import framework' >/dev/null 2>&1 || return 127
39
+ "$@" -m framework hook pre-commit
32
40
  }
33
41
 
34
42
  has_rproj() {
@@ -52,8 +60,8 @@ if [ "$status" -eq 127 ] && { [ -f pyproject.toml ] || [ -f uv.lock ] || [ -d .v
52
60
  fi
53
61
 
54
62
  if [ "$status" -eq 127 ]; then
55
- echo "Framework hook: no R or Python runtime with framework installed was found." >&2
56
- echo "Install one, or run 'git commit --no-verify' if you are sure this commit is safe." >&2
63
+ echo "Framework hook: found neither R with framework 2.0 or later nor Python with framework-py." >&2
64
+ echo "Install one of them, or run 'git commit --no-verify' if you are sure this commit is safe." >&2
57
65
  exit 1
58
66
  fi
59
67
  exit "$status"
@@ -0,0 +1,137 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://framework.pub/schema/docs-reference.v1.json",
4
+ "title": "Framework docs reference",
5
+ "description": "The generated function or command reference for one product's docs site (docs/site/reference.json). Text fields hold CommonMark with GFM tables.",
6
+ "type": "object",
7
+ "required": ["schema", "product", "version", "categories", "entries"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "schema": { "const": "docs-reference.v1" },
11
+ "product": { "enum": ["r", "py", "cli"] },
12
+ "version": { "type": "string", "minLength": 1, "description": "The release this reference was built from, such as 2.0.0 or 0.1.0.dev1." },
13
+ "categories": {
14
+ "type": "array",
15
+ "items": { "$ref": "#/$defs/category" }
16
+ },
17
+ "entries": {
18
+ "type": "array",
19
+ "items": { "$ref": "#/$defs/entry" }
20
+ }
21
+ },
22
+ "$defs": {
23
+ "id": {
24
+ "type": "string",
25
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]*$",
26
+ "description": "URL-safe and unique within the product: /reference/{id}."
27
+ },
28
+ "markdown": { "type": "string" },
29
+ "category": {
30
+ "type": "object",
31
+ "required": ["id", "title", "position"],
32
+ "additionalProperties": false,
33
+ "properties": {
34
+ "id": { "$ref": "#/$defs/id" },
35
+ "title": { "type": "string", "minLength": 1 },
36
+ "description": { "type": "string", "description": "One line, shown under the title in the Reference dropdown." },
37
+ "position": { "type": "integer" },
38
+ "common": {
39
+ "type": "array",
40
+ "items": { "type": "string" },
41
+ "description": "Entry names listed first, under a Common heading."
42
+ }
43
+ }
44
+ },
45
+ "titled": {
46
+ "type": "object",
47
+ "required": ["title", "content"],
48
+ "additionalProperties": false,
49
+ "properties": {
50
+ "title": { "type": "string", "minLength": 1 },
51
+ "content": { "$ref": "#/$defs/markdown" }
52
+ }
53
+ },
54
+ "entry": {
55
+ "type": "object",
56
+ "required": ["id", "name", "kind", "category", "summary"],
57
+ "additionalProperties": false,
58
+ "properties": {
59
+ "id": { "$ref": "#/$defs/id" },
60
+ "name": { "type": "string", "minLength": 1, "description": "As users write it: data_read, AuditResult, or \"project bootstrap\"." },
61
+ "kind": { "enum": ["function", "class", "command"] },
62
+ "category": { "type": "string", "description": "A category id." },
63
+ "title": { "type": "string", "description": "A short heading. Defaults to name." },
64
+ "summary": { "type": "string", "minLength": 1, "description": "One line, used in lists and search results." },
65
+ "usage": { "type": "string", "description": "The signature or command line, shown as code." },
66
+ "description": { "$ref": "#/$defs/markdown", "description": "A paragraph or two (roxygen @description, a docstring's opening paragraphs)." },
67
+ "details": { "$ref": "#/$defs/markdown", "description": "The long body (roxygen @details)." },
68
+ "parameters": {
69
+ "type": "array",
70
+ "description": "Arguments, flags, or a class's fields, in signature order.",
71
+ "items": {
72
+ "type": "object",
73
+ "required": ["name", "description"],
74
+ "additionalProperties": false,
75
+ "properties": {
76
+ "name": { "type": "string", "minLength": 1, "description": "x, *, --path, or -p, --path." },
77
+ "type": { "type": "string" },
78
+ "default": { "type": "string", "description": "As code, such as NULL, None, or \".\"." },
79
+ "required": { "type": "boolean" },
80
+ "env": { "type": "string", "description": "An environment variable that sets it (commands)." },
81
+ "description": { "$ref": "#/$defs/markdown" }
82
+ }
83
+ }
84
+ },
85
+ "returns": { "$ref": "#/$defs/markdown" },
86
+ "note": { "$ref": "#/$defs/markdown" },
87
+ "sections": {
88
+ "type": "array",
89
+ "items": {
90
+ "type": "object",
91
+ "required": ["title", "content"],
92
+ "additionalProperties": false,
93
+ "properties": {
94
+ "title": { "type": "string", "minLength": 1 },
95
+ "content": { "$ref": "#/$defs/markdown" },
96
+ "subsections": { "type": "array", "items": { "$ref": "#/$defs/titled" } }
97
+ }
98
+ }
99
+ },
100
+ "examples": {
101
+ "type": "array",
102
+ "items": {
103
+ "type": "object",
104
+ "required": ["code"],
105
+ "additionalProperties": false,
106
+ "properties": {
107
+ "title": { "type": "string" },
108
+ "code": { "type": "string", "minLength": 1 },
109
+ "runnable": { "type": "boolean", "default": true, "description": "False for R's \\dontrun and for examples that need a server or credentials." }
110
+ }
111
+ }
112
+ },
113
+ "see_also": {
114
+ "type": "array",
115
+ "items": {
116
+ "oneOf": [
117
+ { "type": "string", "minLength": 1, "description": "An entry name in this product, or a link target such as py:ref:data_read." },
118
+ {
119
+ "type": "object",
120
+ "required": ["title", "url"],
121
+ "additionalProperties": false,
122
+ "properties": {
123
+ "title": { "type": "string", "minLength": 1 },
124
+ "url": { "type": "string", "pattern": "^https://" }
125
+ }
126
+ }
127
+ ]
128
+ }
129
+ },
130
+ "aliases": { "type": "array", "items": { "type": "string" } },
131
+ "lifecycle": { "enum": ["stable", "deprecated", "experimental"], "default": "stable" },
132
+ "replaced_by": { "type": "string", "description": "The entry name to use instead, for deprecated entries." },
133
+ "since": { "type": "string", "description": "The version that added it." }
134
+ }
135
+ }
136
+ }
137
+ }