pyfabric 0.1.0__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 (167) hide show
  1. pyfabric-0.1.0/.codespellrc +12 -0
  2. pyfabric-0.1.0/.gitattributes +18 -0
  3. pyfabric-0.1.0/.github/CODEOWNERS +2 -0
  4. pyfabric-0.1.0/.github/dependabot.yml +22 -0
  5. pyfabric-0.1.0/.github/workflows/ci.yml +70 -0
  6. pyfabric-0.1.0/.github/workflows/dependency-review.yml +17 -0
  7. pyfabric-0.1.0/.github/workflows/publish.yml +59 -0
  8. pyfabric-0.1.0/.gitignore +215 -0
  9. pyfabric-0.1.0/.markdownlint-cli2.jsonc +25 -0
  10. pyfabric-0.1.0/.pre-commit-config.yaml +42 -0
  11. pyfabric-0.1.0/CLAUDE.md +178 -0
  12. pyfabric-0.1.0/CONTRIBUTING.md +120 -0
  13. pyfabric-0.1.0/LICENSE +21 -0
  14. pyfabric-0.1.0/PKG-INFO +258 -0
  15. pyfabric-0.1.0/README.md +193 -0
  16. pyfabric-0.1.0/docs/api.md +359 -0
  17. pyfabric-0.1.0/docs/prompts.md +203 -0
  18. pyfabric-0.1.0/docs/roadmap.md +57 -0
  19. pyfabric-0.1.0/docs/testing.md +215 -0
  20. pyfabric-0.1.0/docs/vision.md +47 -0
  21. pyfabric-0.1.0/examples/workspace_demo.py +23 -0
  22. pyfabric-0.1.0/pyproject.toml +211 -0
  23. pyfabric-0.1.0/src/pyfabric/__init__.py +10 -0
  24. pyfabric-0.1.0/src/pyfabric/_version.py +24 -0
  25. pyfabric-0.1.0/src/pyfabric/claude_install.py +336 -0
  26. pyfabric-0.1.0/src/pyfabric/claude_memory/MEMORY.md +8 -0
  27. pyfabric-0.1.0/src/pyfabric/claude_memory/descriptions_required.md +81 -0
  28. pyfabric-0.1.0/src/pyfabric/claude_memory/first_refresh_cred_binding.md +61 -0
  29. pyfabric-0.1.0/src/pyfabric/claude_memory/notebook_required_settings_files.md +63 -0
  30. pyfabric-0.1.0/src/pyfabric/claude_memory/notebook_wheel_resources_pattern.md +179 -0
  31. pyfabric-0.1.0/src/pyfabric/claude_memory/onelake_vs_sql_endpoint.md +46 -0
  32. pyfabric-0.1.0/src/pyfabric/claude_memory/open_mirror_landing_zone.md +210 -0
  33. pyfabric-0.1.0/src/pyfabric/claude_memory/pyfabric.md +86 -0
  34. pyfabric-0.1.0/src/pyfabric/claude_memory/wheel_sqlconn_pattern.md +86 -0
  35. pyfabric-0.1.0/src/pyfabric/cli.py +280 -0
  36. pyfabric-0.1.0/src/pyfabric/client/__init__.py +1 -0
  37. pyfabric-0.1.0/src/pyfabric/client/auth.py +293 -0
  38. pyfabric-0.1.0/src/pyfabric/client/graph.py +157 -0
  39. pyfabric-0.1.0/src/pyfabric/client/http.py +260 -0
  40. pyfabric-0.1.0/src/pyfabric/client/livy.py +166 -0
  41. pyfabric-0.1.0/src/pyfabric/client/ontology/__init__.py +135 -0
  42. pyfabric-0.1.0/src/pyfabric/client/ontology/_id_gen.py +19 -0
  43. pyfabric-0.1.0/src/pyfabric/client/ontology/builder.py +447 -0
  44. pyfabric-0.1.0/src/pyfabric/client/ontology/crud.py +70 -0
  45. pyfabric-0.1.0/src/pyfabric/client/ontology/parts.py +591 -0
  46. pyfabric-0.1.0/src/pyfabric/client/ontology_sync.py +376 -0
  47. pyfabric-0.1.0/src/pyfabric/data/__init__.py +17 -0
  48. pyfabric-0.1.0/src/pyfabric/data/lakehouse.py +549 -0
  49. pyfabric-0.1.0/src/pyfabric/data/local_lakehouse.py +666 -0
  50. pyfabric-0.1.0/src/pyfabric/data/onelake.py +495 -0
  51. pyfabric-0.1.0/src/pyfabric/data/open_mirror.py +526 -0
  52. pyfabric-0.1.0/src/pyfabric/data/processing_log.py +209 -0
  53. pyfabric-0.1.0/src/pyfabric/data/schema.py +321 -0
  54. pyfabric-0.1.0/src/pyfabric/data/sql.py +199 -0
  55. pyfabric-0.1.0/src/pyfabric/data/sqlconn.py +85 -0
  56. pyfabric-0.1.0/src/pyfabric/demo.py +288 -0
  57. pyfabric-0.1.0/src/pyfabric/items/__init__.py +1 -0
  58. pyfabric-0.1.0/src/pyfabric/items/bundle.py +243 -0
  59. pyfabric-0.1.0/src/pyfabric/items/crud.py +216 -0
  60. pyfabric-0.1.0/src/pyfabric/items/environment.py +376 -0
  61. pyfabric-0.1.0/src/pyfabric/items/mirrored_database.py +342 -0
  62. pyfabric-0.1.0/src/pyfabric/items/normalize.py +285 -0
  63. pyfabric-0.1.0/src/pyfabric/items/notebook.py +366 -0
  64. pyfabric-0.1.0/src/pyfabric/items/report.py +1129 -0
  65. pyfabric-0.1.0/src/pyfabric/items/semantic_model.py +750 -0
  66. pyfabric-0.1.0/src/pyfabric/items/types.py +198 -0
  67. pyfabric-0.1.0/src/pyfabric/items/validate.py +160 -0
  68. pyfabric-0.1.0/src/pyfabric/items/validate_tmdl.py +116 -0
  69. pyfabric-0.1.0/src/pyfabric/logging.py +179 -0
  70. pyfabric-0.1.0/src/pyfabric/py.typed +0 -0
  71. pyfabric-0.1.0/src/pyfabric/testing/__init__.py +14 -0
  72. pyfabric-0.1.0/src/pyfabric/testing/analyze.py +76 -0
  73. pyfabric-0.1.0/src/pyfabric/testing/duckdb_spark.py +268 -0
  74. pyfabric-0.1.0/src/pyfabric/testing/fixtures.py +252 -0
  75. pyfabric-0.1.0/src/pyfabric/testing/mock_notebookutils.py +122 -0
  76. pyfabric-0.1.0/src/pyfabric/testing/plugin.py +9 -0
  77. pyfabric-0.1.0/src/pyfabric/workspace/__init__.py +1 -0
  78. pyfabric-0.1.0/src/pyfabric/workspace/workspaces.py +155 -0
  79. pyfabric-0.1.0/tests/__init__.py +0 -0
  80. pyfabric-0.1.0/tests/client/__init__.py +0 -0
  81. pyfabric-0.1.0/tests/client/test_auth.py +151 -0
  82. pyfabric-0.1.0/tests/client/test_auth_errors.py +101 -0
  83. pyfabric-0.1.0/tests/client/test_graph_errors.py +84 -0
  84. pyfabric-0.1.0/tests/client/test_http.py +191 -0
  85. pyfabric-0.1.0/tests/client/test_http_errors.py +184 -0
  86. pyfabric-0.1.0/tests/client/test_livy.py +36 -0
  87. pyfabric-0.1.0/tests/client/test_livy_errors.py +124 -0
  88. pyfabric-0.1.0/tests/client/test_ontology.py +445 -0
  89. pyfabric-0.1.0/tests/client/test_ontology_parts.py +374 -0
  90. pyfabric-0.1.0/tests/conftest.py +217 -0
  91. pyfabric-0.1.0/tests/data/__init__.py +0 -0
  92. pyfabric-0.1.0/tests/data/test_lakehouse.py +161 -0
  93. pyfabric-0.1.0/tests/data/test_lakehouse_ddl.py +308 -0
  94. pyfabric-0.1.0/tests/data/test_local_lakehouse_push.py +148 -0
  95. pyfabric-0.1.0/tests/data/test_local_lakehouse_rename_schema.py +91 -0
  96. pyfabric-0.1.0/tests/data/test_local_lakehouse_schema_drift.py +336 -0
  97. pyfabric-0.1.0/tests/data/test_onelake.py +32 -0
  98. pyfabric-0.1.0/tests/data/test_onelake_walk_cache.py +326 -0
  99. pyfabric-0.1.0/tests/data/test_open_mirror.py +270 -0
  100. pyfabric-0.1.0/tests/data/test_open_mirror_write_rows.py +425 -0
  101. pyfabric-0.1.0/tests/data/test_processing_log.py +114 -0
  102. pyfabric-0.1.0/tests/data/test_sample_db.py +150 -0
  103. pyfabric-0.1.0/tests/data/test_schema.py +337 -0
  104. pyfabric-0.1.0/tests/data/test_schema_validation.py +123 -0
  105. pyfabric-0.1.0/tests/data/test_sql_errors.py +194 -0
  106. pyfabric-0.1.0/tests/data/test_sqlconn.py +59 -0
  107. pyfabric-0.1.0/tests/data/test_upload_retry.py +112 -0
  108. pyfabric-0.1.0/tests/fixtures/create_sample_db.py +164 -0
  109. pyfabric-0.1.0/tests/fixtures/mirrors/mirror_custom.MirroredDatabase/mirroring.json +15 -0
  110. pyfabric-0.1.0/tests/fixtures/mirrors/mirror_default.MirroredDatabase/mirroring.json +15 -0
  111. pyfabric-0.1.0/tests/fixtures/notebooks/nb_full.Notebook/notebook-content.py +52 -0
  112. pyfabric-0.1.0/tests/fixtures/notebooks/nb_minimal.Notebook/notebook-content.py +9 -0
  113. pyfabric-0.1.0/tests/fixtures/workspace/df_example.Dataflow/.platform +12 -0
  114. pyfabric-0.1.0/tests/fixtures/workspace/df_example.Dataflow/mashup.pq +1 -0
  115. pyfabric-0.1.0/tests/fixtures/workspace/df_example.Dataflow/queryMetadata.json +11 -0
  116. pyfabric-0.1.0/tests/fixtures/workspace/env_example.Environment/.platform +11 -0
  117. pyfabric-0.1.0/tests/fixtures/workspace/env_example.Environment/Libraries/PublicLibraries/environment.yml +3 -0
  118. pyfabric-0.1.0/tests/fixtures/workspace/env_example.Environment/Setting/Sparkcompute.yml +6 -0
  119. pyfabric-0.1.0/tests/fixtures/workspace/lh_example.Lakehouse/.platform +11 -0
  120. pyfabric-0.1.0/tests/fixtures/workspace/lh_example.Lakehouse/lakehouse.metadata.json +1 -0
  121. pyfabric-0.1.0/tests/fixtures/workspace/nb_example.Notebook/.platform +11 -0
  122. pyfabric-0.1.0/tests/fixtures/workspace/nb_example.Notebook/notebook-content.py +11 -0
  123. pyfabric-0.1.0/tests/fixtures/workspace/pl_example.DataPipeline/.platform +11 -0
  124. pyfabric-0.1.0/tests/fixtures/workspace/pl_example.DataPipeline/pipeline-content.json +5 -0
  125. pyfabric-0.1.0/tests/fixtures/workspace/rpt_example.Report/.platform +11 -0
  126. pyfabric-0.1.0/tests/fixtures/workspace/rpt_example.Report/report.json +4 -0
  127. pyfabric-0.1.0/tests/fixtures/workspace/sm_example.SemanticModel/.platform +11 -0
  128. pyfabric-0.1.0/tests/fixtures/workspace/sm_example.SemanticModel/model.bim +7 -0
  129. pyfabric-0.1.0/tests/fixtures/workspace/vl_example.VariableLibrary/.platform +11 -0
  130. pyfabric-0.1.0/tests/fixtures/workspace/vl_example.VariableLibrary/settings.json +6 -0
  131. pyfabric-0.1.0/tests/fixtures/workspace/vl_example.VariableLibrary/valueSets/DEV.json +5 -0
  132. pyfabric-0.1.0/tests/fixtures/workspace/vl_example.VariableLibrary/variables.json +11 -0
  133. pyfabric-0.1.0/tests/fixtures/workspace/wh_example.Warehouse/.platform +11 -0
  134. pyfabric-0.1.0/tests/fixtures/workspace_invalid/bad_platform.Notebook/.platform +1 -0
  135. pyfabric-0.1.0/tests/fixtures/workspace_invalid/bad_platform.Notebook/notebook-content.py +1 -0
  136. pyfabric-0.1.0/tests/fixtures/workspace_invalid/nb_no_content.Notebook/.platform +11 -0
  137. pyfabric-0.1.0/tests/fixtures/workspace_invalid/wrong_name.Lakehouse/.platform +11 -0
  138. pyfabric-0.1.0/tests/fixtures/workspace_invalid/wrong_name.Lakehouse/lakehouse.metadata.json +1 -0
  139. pyfabric-0.1.0/tests/items/__init__.py +0 -0
  140. pyfabric-0.1.0/tests/items/test_bundle_errors.py +81 -0
  141. pyfabric-0.1.0/tests/items/test_crud.py +108 -0
  142. pyfabric-0.1.0/tests/items/test_environment.py +258 -0
  143. pyfabric-0.1.0/tests/items/test_mirrored_database.py +338 -0
  144. pyfabric-0.1.0/tests/items/test_normalize.py +191 -0
  145. pyfabric-0.1.0/tests/items/test_notebook.py +339 -0
  146. pyfabric-0.1.0/tests/items/test_report.py +785 -0
  147. pyfabric-0.1.0/tests/items/test_semantic_model.py +605 -0
  148. pyfabric-0.1.0/tests/items/test_types.py +158 -0
  149. pyfabric-0.1.0/tests/items/test_validate.py +350 -0
  150. pyfabric-0.1.0/tests/items/test_validate_e2e.py +73 -0
  151. pyfabric-0.1.0/tests/items/test_validate_pairwise.py +133 -0
  152. pyfabric-0.1.0/tests/items/test_validate_tmdl.py +129 -0
  153. pyfabric-0.1.0/tests/test_claude_install.py +225 -0
  154. pyfabric-0.1.0/tests/test_cli.py +43 -0
  155. pyfabric-0.1.0/tests/test_cli_normalize.py +106 -0
  156. pyfabric-0.1.0/tests/test_demo.py +247 -0
  157. pyfabric-0.1.0/tests/test_logging.py +120 -0
  158. pyfabric-0.1.0/tests/test_pyproject_metadata.py +44 -0
  159. pyfabric-0.1.0/tests/test_version.py +9 -0
  160. pyfabric-0.1.0/tests/testing/__init__.py +0 -0
  161. pyfabric-0.1.0/tests/testing/test_analyze.py +15 -0
  162. pyfabric-0.1.0/tests/testing/test_attach_duckdb_lakehouse.py +134 -0
  163. pyfabric-0.1.0/tests/testing/test_duckdb_spark.py +157 -0
  164. pyfabric-0.1.0/tests/testing/test_mock_notebookutils.py +89 -0
  165. pyfabric-0.1.0/tests/testing/test_snapshot_delta.py +179 -0
  166. pyfabric-0.1.0/tests/workspace/__init__.py +0 -0
  167. pyfabric-0.1.0/tests/workspace/test_workspaces.py +56 -0
@@ -0,0 +1,12 @@
1
+ [codespell]
2
+ # Skip generated, vendored, and binary content. Notebook fixture files
3
+ # contain raw cell-marker syntax and synthetic IDs that confuse codespell.
4
+ skip = .git,*.pyc,*.pyo,.venv,build,dist,*.egg-info,.test-report.json,tests/fixtures/notebooks/**,src/pyfabric/_version.py
5
+ # Allowlist project-specific words. Add sparingly — every entry here is
6
+ # a future false positive someone has to read past.
7
+ # - falsy: legitimate jargon (truthy/falsy)
8
+ # - caf: matches the literal "café" (café) in test_logging.py's UTF-8
9
+ # round-trip test; codespell sees the ASCII prefix only.
10
+ # - skool: the Skool community platform (https://www.skool.com), used
11
+ # as an example data source in claude_memory/open_mirror_landing_zone.md.
12
+ ignore-words-list = falsy,caf,skool
@@ -0,0 +1,18 @@
1
+ # Normalize all text files to LF in the repository
2
+ * text=auto eol=lf
3
+
4
+ # Explicitly mark binary files
5
+ *.png binary
6
+ *.jpg binary
7
+ *.whl binary
8
+
9
+ # Ensure key file types use LF everywhere
10
+ *.py text eol=lf
11
+ *.toml text eol=lf
12
+ *.yml text eol=lf
13
+ *.yaml text eol=lf
14
+ *.md text eol=lf
15
+ *.txt text eol=lf
16
+ *.cfg text eol=lf
17
+ *.ini text eol=lf
18
+ *.json text eol=lf
@@ -0,0 +1,2 @@
1
+ # All changes require review from an admin
2
+ * @hughdecatte
@@ -0,0 +1,22 @@
1
+ version: 2
2
+ updates:
3
+ # Keep GitHub Actions current (no CVE tracking for Actions)
4
+ - package-ecosystem: "github-actions"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
8
+ groups:
9
+ github-actions:
10
+ patterns:
11
+ - "*"
12
+
13
+ # Python deps: security updates ONLY (CVE-driven)
14
+ # Version updates are handled by Dependabot security updates (repo setting),
15
+ # not dependabot.yml version updates. This entry ensures the dependency
16
+ # graph stays current for vulnerability scanning without auto-bumping
17
+ # versions that have no known CVEs.
18
+ - package-ecosystem: "pip"
19
+ directory: "/"
20
+ schedule:
21
+ interval: "weekly"
22
+ open-pull-requests-limit: 0 # Disable version update PRs
@@ -0,0 +1,70 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ci-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ lint:
18
+ name: Lint & Format
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v6
22
+ - uses: actions/setup-python@v6
23
+ with:
24
+ python-version: "3.12"
25
+ - run: pip install -e ".[dev]"
26
+ - run: ruff check .
27
+ - run: ruff format --check .
28
+
29
+ docs-lint:
30
+ name: Docs Lint (codespell + markdownlint)
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - uses: actions/checkout@v6
34
+ - uses: actions/setup-python@v6
35
+ with:
36
+ python-version: "3.12"
37
+ - run: pip install codespell==2.3.0
38
+ - run: codespell --config=.codespellrc
39
+ - uses: DavidAnson/markdownlint-cli2-action@v17
40
+
41
+ type-check:
42
+ name: Type Check
43
+ runs-on: ubuntu-latest
44
+ steps:
45
+ - uses: actions/checkout@v6
46
+ - uses: actions/setup-python@v6
47
+ with:
48
+ python-version: "3.12"
49
+ - run: pip install -e ".[dev]"
50
+ - run: mypy src/
51
+
52
+ test:
53
+ name: Test (Python ${{ matrix.python-version }})
54
+ runs-on: ubuntu-latest
55
+ strategy:
56
+ fail-fast: false
57
+ matrix:
58
+ python-version: ["3.11", "3.12", "3.13"]
59
+ steps:
60
+ - uses: actions/checkout@v6
61
+ - uses: actions/setup-python@v6
62
+ with:
63
+ python-version: ${{ matrix.python-version }}
64
+ - run: pip install -e ".[dev]"
65
+ - run: pytest --cov=src/pyfabric --cov-branch --cov-report=term-missing --json-report --json-report-file=test-report.json
66
+ - uses: actions/upload-artifact@v7
67
+ if: always()
68
+ with:
69
+ name: test-report-py${{ matrix.python-version }}
70
+ path: test-report.json
@@ -0,0 +1,17 @@
1
+ name: Dependency Review
2
+
3
+ on: [pull_request]
4
+
5
+ permissions:
6
+ contents: read
7
+
8
+ jobs:
9
+ dependency-review:
10
+ name: Dependency Review
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v6
14
+ - uses: actions/dependency-review-action@v4
15
+ with:
16
+ fail-on-severity: high
17
+ deny-licenses: GPL-3.0, AGPL-3.0
@@ -0,0 +1,59 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build distribution
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: write
13
+ steps:
14
+ - uses: actions/checkout@v6
15
+ with:
16
+ fetch-depth: 0 # Required for hatch-vcs to derive version from tags
17
+ - uses: actions/setup-python@v6
18
+ with:
19
+ python-version: "3.12"
20
+ - run: python -m pip install --upgrade pip
21
+ - run: pip install build pip-audit
22
+ - run: pip-audit
23
+ - run: python -m build
24
+ - uses: anchore/sbom-action@v0
25
+ with:
26
+ path: dist/
27
+ format: spdx-json
28
+ output-file: sbom.spdx.json
29
+ - uses: actions/upload-artifact@v7
30
+ with:
31
+ name: dist
32
+ path: dist/
33
+ - uses: actions/upload-artifact@v7
34
+ with:
35
+ name: sbom
36
+ path: sbom.spdx.json
37
+
38
+ publish:
39
+ name: Publish to PyPI
40
+ needs: build
41
+ runs-on: ubuntu-latest
42
+ environment:
43
+ name: pypi
44
+ url: https://pypi.org/p/pyfabric
45
+ permissions:
46
+ id-token: write
47
+ attestations: write
48
+ contents: read
49
+ steps:
50
+ - uses: actions/download-artifact@v8
51
+ with:
52
+ name: dist
53
+ path: dist/
54
+ - uses: actions/attest-build-provenance@v4
55
+ with:
56
+ subject-path: dist/*
57
+ - uses: pypa/gh-action-pypi-publish@release/v1
58
+ with:
59
+ attestations: true
@@ -0,0 +1,215 @@
1
+ # hatch-vcs generated version file
2
+ src/pyfabric/_version.py
3
+
4
+ # Test artifacts
5
+ .test-report.json
6
+ .logs/
7
+ tests/fixtures/sample.duckdb
8
+
9
+ # Byte-compiled / optimized / DLL files
10
+ __pycache__/
11
+ *.py[codz]
12
+ *$py.class
13
+
14
+ # C extensions
15
+ *.so
16
+
17
+ # Distribution / packaging
18
+ .Python
19
+ build/
20
+ develop-eggs/
21
+ dist/
22
+ downloads/
23
+ eggs/
24
+ .eggs/
25
+ lib/
26
+ lib64/
27
+ parts/
28
+ sdist/
29
+ var/
30
+ wheels/
31
+ share/python-wheels/
32
+ *.egg-info/
33
+ .installed.cfg
34
+ *.egg
35
+ MANIFEST
36
+
37
+ # PyInstaller
38
+ # Usually these files are written by a python script from a template
39
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
40
+ *.manifest
41
+ *.spec
42
+
43
+ # Installer logs
44
+ pip-log.txt
45
+ pip-delete-this-directory.txt
46
+
47
+ # Unit test / coverage reports
48
+ htmlcov/
49
+ .tox/
50
+ .nox/
51
+ .coverage
52
+ .coverage.*
53
+ .cache
54
+ nosetests.xml
55
+ coverage.xml
56
+ *.cover
57
+ *.py.cover
58
+ .hypothesis/
59
+ .pytest_cache/
60
+ cover/
61
+
62
+ # Translations
63
+ *.mo
64
+ *.pot
65
+
66
+ # Django stuff:
67
+ *.log
68
+ local_settings.py
69
+ db.sqlite3
70
+ db.sqlite3-journal
71
+
72
+ # Flask stuff:
73
+ instance/
74
+ .webassets-cache
75
+
76
+ # Scrapy stuff:
77
+ .scrapy
78
+
79
+ # Sphinx documentation
80
+ docs/_build/
81
+
82
+ # PyBuilder
83
+ .pybuilder/
84
+ target/
85
+
86
+ # Jupyter Notebook
87
+ .ipynb_checkpoints
88
+
89
+ # IPython
90
+ profile_default/
91
+ ipython_config.py
92
+
93
+ # pyenv
94
+ # For a library or package, you might want to ignore these files since the code is
95
+ # intended to run in multiple environments; otherwise, check them in:
96
+ # .python-version
97
+
98
+ # pipenv
99
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
100
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
101
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
102
+ # install all needed dependencies.
103
+ #Pipfile.lock
104
+
105
+ # UV
106
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
107
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
108
+ # commonly ignored for libraries.
109
+ #uv.lock
110
+
111
+ # poetry
112
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
113
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
114
+ # commonly ignored for libraries.
115
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
116
+ #poetry.lock
117
+ #poetry.toml
118
+
119
+ # pdm
120
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
121
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
122
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
123
+ #pdm.lock
124
+ #pdm.toml
125
+ .pdm-python
126
+ .pdm-build/
127
+
128
+ # pixi
129
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
130
+ #pixi.lock
131
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
132
+ # in the .venv directory. It is recommended not to include this directory in version control.
133
+ .pixi
134
+
135
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
136
+ __pypackages__/
137
+
138
+ # Celery stuff
139
+ celerybeat-schedule
140
+ celerybeat.pid
141
+
142
+ # SageMath parsed files
143
+ *.sage.py
144
+
145
+ # Environments
146
+ .env
147
+ .envrc
148
+ .venv
149
+ env/
150
+ venv/
151
+ ENV/
152
+ env.bak/
153
+ venv.bak/
154
+
155
+ # Spyder project settings
156
+ .spyderproject
157
+ .spyproject
158
+
159
+ # Rope project settings
160
+ .ropeproject
161
+
162
+ # mkdocs documentation
163
+ /site
164
+
165
+ # mypy
166
+ .mypy_cache/
167
+ .dmypy.json
168
+ dmypy.json
169
+
170
+ # Pyre type checker
171
+ .pyre/
172
+
173
+ # pytype static type analyzer
174
+ .pytype/
175
+
176
+ # Cython debug symbols
177
+ cython_debug/
178
+
179
+ # PyCharm
180
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
181
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
182
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
183
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
184
+ #.idea/
185
+
186
+ # Abstra
187
+ # Abstra is an AI-powered process automation framework.
188
+ # Ignore directories containing user credentials, local state, and settings.
189
+ # Learn more at https://abstra.io/docs
190
+ .abstra/
191
+
192
+ # Visual Studio Code
193
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
194
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
195
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
196
+ # you could uncomment the following to ignore the entire vscode folder
197
+ # .vscode/
198
+
199
+ # Ruff stuff:
200
+ .ruff_cache/
201
+
202
+ # PyPI configuration file
203
+ .pypirc
204
+
205
+ # Cursor
206
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
207
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
208
+ # refer to https://docs.cursor.com/context/ignore-files
209
+ .cursorignore
210
+ .cursorindexingignore
211
+
212
+ # Marimo
213
+ marimo/_static/
214
+ marimo/_lsp/
215
+ __marimo__/
@@ -0,0 +1,25 @@
1
+ // markdownlint-cli2 configuration. Conservative ruleset — start strict,
2
+ // loosen only when a rule produces more noise than value.
3
+ {
4
+ "config": {
5
+ "default": true,
6
+ // MD013 (line length) is too noisy for technical writing with URLs,
7
+ // and we already line-wrap prose by hand.
8
+ "MD013": false,
9
+ // MD033 (no inline HTML) blocks legitimate uses like <details> and
10
+ // <kbd>. Enable case-by-case if a specific tag becomes a problem.
11
+ "MD033": false,
12
+ // MD041 (first line must be a top-level heading) breaks for files
13
+ // that lead with frontmatter (e.g. claude_memory/*.md).
14
+ "MD041": false
15
+ },
16
+ "globs": ["**/*.md"],
17
+ "ignores": [
18
+ ".venv/**",
19
+ "build/**",
20
+ "dist/**",
21
+ "*.egg-info/**",
22
+ "node_modules/**",
23
+ ".git/**"
24
+ ]
25
+ }
@@ -0,0 +1,42 @@
1
+ # See https://pre-commit.com for more information
2
+ # Run `pre-commit install` once after cloning to enable hooks.
3
+ repos:
4
+ - repo: https://github.com/astral-sh/ruff-pre-commit
5
+ rev: v0.15.10
6
+ hooks:
7
+ - id: ruff
8
+ args: [--fix, --exit-non-zero-on-fix]
9
+ - id: ruff-format
10
+
11
+ - repo: https://github.com/pre-commit/mirrors-mypy
12
+ rev: v1.20.0
13
+ hooks:
14
+ - id: mypy
15
+ args: [--config-file=pyproject.toml]
16
+ additional_dependencies:
17
+ - structlog>=24.0
18
+ - pytest>=8.0
19
+ pass_filenames: false
20
+ entry: mypy src/
21
+
22
+ - repo: https://github.com/codespell-project/codespell
23
+ rev: v2.3.0
24
+ hooks:
25
+ - id: codespell
26
+ additional_dependencies: [tomli]
27
+ args: [--config=.codespellrc]
28
+
29
+ - repo: https://github.com/DavidAnson/markdownlint-cli2
30
+ rev: v0.14.0
31
+ hooks:
32
+ - id: markdownlint-cli2
33
+
34
+ - repo: local
35
+ hooks:
36
+ - id: pytest
37
+ name: pytest
38
+ entry: python -m pytest --no-header -q
39
+ language: system
40
+ pass_filenames: false
41
+ always_run: true
42
+ stages: [pre-push]
@@ -0,0 +1,178 @@
1
+ # CLAUDE.md
2
+
3
+ Instructions for AI coding assistants (Claude, Copilot, etc.) working in
4
+ this repository.
5
+
6
+ ## Project Overview
7
+
8
+ pyfabric is a Python library for programmatically creating, validating,
9
+ and locally testing Microsoft Fabric items that are compatible with Fabric
10
+ git sync. Target users are AI coding assistants and developers who need to
11
+ generate and test Fabric item definitions locally.
12
+
13
+ ## What pyfabric is — and is not
14
+
15
+ pyfabric is a **dev-time / build-time** tool. It runs on the developer's
16
+ machine (or in CI), not inside Fabric. Its three jobs are:
17
+
18
+ 1. **Create** Fabric artifacts (notebooks, semantic models, reports,
19
+ variable libraries, lakehouse DDL) as files committed to a
20
+ git-synced workspace repo.
21
+ 2. **Test locally** — DuckDB lakehouse mock, OneLake helpers, schema
22
+ validation, transform logic — without standing up Fabric.
23
+ 3. **Manage Fabric operationally** from outside the platform — trigger
24
+ notebook runs via the Jobs API, refresh semantic models, audit
25
+ workspaces.
26
+
27
+ **pyfabric is NOT a notebook runtime dependency.** A Fabric Spark
28
+ notebook should not `import pyfabric`. Several past sessions have
29
+ wasted time trying to install pyfabric inside Fabric (in
30
+ `Resources/builtin/`, in custom Environments, via `%pip install
31
+ pyfabric` cells). The right pattern is:
32
+
33
+ - Notebooks stay thin — orchestration only.
34
+ - The project's transform / DDL / SQL helpers live in a project
35
+ wheel (e.g. `fabric_utils-*.whl`) shipped via
36
+ `Resources/builtin/` (see `claude_memory/notebook_wheel_resources_pattern.md`).
37
+ - That project wheel depends only on Fabric Spark runtime
38
+ pre-installed packages (`azure-identity`,
39
+ `azure-storage-file-datalake`, `pyarrow`, `requests`), not on
40
+ pyfabric.
41
+ - pyfabric stays on the dev machine, where it builds and validates
42
+ the notebook + the project wheel.
43
+
44
+ When you find yourself reaching for pyfabric inside a notebook,
45
+ that's a sign the logic should move into the project wheel where
46
+ it's locally testable; the notebook then calls the wheel.
47
+
48
+ ## Technical Stack
49
+
50
+ - **Python**: 3.11+ (use modern syntax: `match`, `X | Y` unions, `Self` from `typing`). Avoid 3.12-only syntax — Fabric Spark runtime 1.3 is 3.11. Specifically: do NOT use `type X = Y` (PEP 695, 3.12+) or `class Foo[T]` (PEP 695, 3.12+).
51
+ - **Build**: hatchling with hatch-vcs (version from git tags)
52
+ - **Layout**: src-layout (`src/pyfabric/`)
53
+ - **Linting**: ruff (configured in pyproject.toml)
54
+ - **Type checking**: mypy in strict mode
55
+ - **Logging**: structlog (JSON output, token masking, context binding)
56
+ - **Testing**: pytest (tests in `tests/`)
57
+ - **CI**: GitHub Actions (lint, type-check, test, dependency review)
58
+
59
+ ## Sub-package Structure
60
+
61
+ ```text
62
+ src/pyfabric/
63
+ client/ — Auth, REST API, HTTP client for Fabric service
64
+ items/ — Create, load, save, validate Fabric item definitions
65
+ data/ — OneLake DFS, SQL connections, lakehouse table I/O
66
+ workspace/ — Workspace-level operations
67
+ testing/ — pytest fixtures, DuckDB Spark mock for users
68
+ cli.py — CLI entry point
69
+ ```
70
+
71
+ ## Key Conventions
72
+
73
+ - All code must pass `ruff check`, `ruff format --check`, and `mypy --strict`
74
+ - All public functions and classes must have type annotations
75
+ - Use `X | None` not `typing.Optional[X]`; use `X | Y` not `typing.Union`
76
+ - Use `list`, `dict`, `tuple` not `typing.List`, `typing.Dict`, `typing.Tuple`
77
+ - `from __future__ import annotations` is NOT needed (Python 3.11+ supports `X | Y` unions natively via PEP 604)
78
+ - Prefer `pathlib.Path` over `os.path`
79
+ - Prefer dataclasses or named tuples over plain dicts for structured data
80
+ - Tests use pytest fixtures; avoid unittest.TestCase
81
+ - No mutable default arguments
82
+ - Use `import structlog` and `log = structlog.get_logger()` (NOT stdlib `logging`)
83
+ - Use `log.info("message", key=value)` for structured context (NOT f-strings in messages)
84
+
85
+ ## Running Checks
86
+
87
+ ```bash
88
+ ruff check . # Lint
89
+ ruff format --check . # Format check
90
+ mypy src/ # Type check
91
+ pytest # Run tests
92
+ ```
93
+
94
+ ## Version Management
95
+
96
+ Version is derived from git tags via hatch-vcs. Do NOT manually edit
97
+ version strings. The file `src/pyfabric/_version.py` is auto-generated
98
+ and must not be committed.
99
+
100
+ ## Dependencies
101
+
102
+ - Runtime dependencies go in `[project] dependencies` in pyproject.toml
103
+ - Optional dependency groups: `[azure]`, `[data]`, `[testing]`, `[all]`, `[dev]`
104
+ - Keep runtime dependencies minimal — heavy deps belong in optional groups
105
+
106
+ ## Fabric Item Structure (git sync format)
107
+
108
+ All Fabric items follow this directory structure:
109
+
110
+ ```text
111
+ {DisplayName}.{ItemType}/
112
+ .platform # Required: metadata + logicalId (UUID)
113
+ {definition_files...} # Item-specific content
114
+ ```
115
+
116
+ The `.platform` file uses schema version 2.0:
117
+
118
+ ```json
119
+ {
120
+ "$schema": "https://developer.microsoft.com/json-schemas/fabric/gitIntegration/platformProperties/2.0.0/schema.json",
121
+ "metadata": {
122
+ "type": "{ItemType}",
123
+ "displayName": "{DisplayName}"
124
+ },
125
+ "config": {
126
+ "version": "2.0",
127
+ "logicalId": "{UUID}"
128
+ }
129
+ }
130
+ ```
131
+
132
+ Supported item types: Notebook, Lakehouse, Dataflow, Environment,
133
+ VariableLibrary, SemanticModel, Report, DataPipeline, Warehouse,
134
+ MirroredDatabase, Map.
135
+
136
+ ## Provisioning Workflow (git-first)
137
+
138
+ pyfabric ships two complementary ways to create Fabric items:
139
+
140
+ 1. **Builder → git artifact** (`NotebookBuilder.save_to_disk()`,
141
+ `MirroredDatabaseBuilder.save_to_disk()`, etc.) writes a
142
+ `.platform` + definition files to a folder under your
143
+ git-synced workspace repo. **This is the primary path.**
144
+ 2. **REST helpers** (`create_item`, `create_mirrored_database`, …)
145
+ call the Fabric REST API directly. **Use only for scripted
146
+ automation in workspaces that are not git-synced.**
147
+
148
+ Mixing the two on the same workspace causes a duplicate-item
149
+ conflict: the REST-created item and the later git-synced item live
150
+ under different IDs, and Fabric will not merge them. The
151
+ git-synced item also receives a fresh ID, breaking any committed
152
+ references (e.g. notebook parameters that hard-code the mirror's
153
+ GUID).
154
+
155
+ ### Recommended order for a git-synced workspace
156
+
157
+ 1. Generate the artifact locally with the builder.
158
+ 2. Run local tests (producer logic, schema-compat, artifact shape,
159
+ `validate_workspace`).
160
+ 3. Commit + push to the workspace's git-synced branch.
161
+ 4. Have a human trigger the **manual git-sync** in the Fabric portal
162
+ (and bind any required OAuth credentials on first refresh — see
163
+ `claude_memory/first_refresh_cred_binding.md`).
164
+ 5. Only then perform data-plane mutations (upload landing-zone
165
+ files, `start_mirroring`, `update_definition`, …) — these
166
+ target the just-synced item by its real GUID.
167
+
168
+ AI assistants using pyfabric in a git-synced workspace should
169
+ **pause after step 3** and wait for the user to confirm the sync
170
+ before issuing any REST mutation that would create or modify an
171
+ item.
172
+
173
+ ## What NOT to Do
174
+
175
+ - Do not add `__version__ = "..."` manually anywhere
176
+ - Do not create setup.py or setup.cfg
177
+ - Do not commit `src/pyfabric/_version.py`
178
+ - Do not use `datetime.utcnow()` — use `datetime.now(timezone.utc)`