crosscontract 0.2.2__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 (115) hide show
  1. crosscontract-0.2.2/.github/CODEOWNERS +1 -0
  2. crosscontract-0.2.2/.github/ISSUE_TEMPLATE/bug_report.md +31 -0
  3. crosscontract-0.2.2/.github/ISSUE_TEMPLATE/discussion---design-proposal.md +24 -0
  4. crosscontract-0.2.2/.github/ISSUE_TEMPLATE/documentation-request.md +20 -0
  5. crosscontract-0.2.2/.github/ISSUE_TEMPLATE/feature_request.md +31 -0
  6. crosscontract-0.2.2/.github/ISSUE_TEMPLATE/improvement.md +20 -0
  7. crosscontract-0.2.2/.github/ISSUE_TEMPLATE/maintenance---chore.md +21 -0
  8. crosscontract-0.2.2/.github/ISSUE_TEMPLATE/qa---test-case.md +22 -0
  9. crosscontract-0.2.2/.github/copilot-instructions.md +76 -0
  10. crosscontract-0.2.2/.github/workflows/check_pr_title.yml +26 -0
  11. crosscontract-0.2.2/.github/workflows/check_pr_to_main.yml +18 -0
  12. crosscontract-0.2.2/.github/workflows/deploy_docs.yml +53 -0
  13. crosscontract-0.2.2/.github/workflows/publish_pypi.yml +59 -0
  14. crosscontract-0.2.2/.github/workflows/release_main_branch.yml +31 -0
  15. crosscontract-0.2.2/.github/workflows/test_and_coverage.yml +75 -0
  16. crosscontract-0.2.2/.github/workflows/versioning.yml +37 -0
  17. crosscontract-0.2.2/.gitignore +210 -0
  18. crosscontract-0.2.2/.pre-commit-config.yaml +15 -0
  19. crosscontract-0.2.2/.python-version +1 -0
  20. crosscontract-0.2.2/.vscode/launch.json +33 -0
  21. crosscontract-0.2.2/.vscode/settings.json +27 -0
  22. crosscontract-0.2.2/CHANGELOG.md +73 -0
  23. crosscontract-0.2.2/LICENSE +21 -0
  24. crosscontract-0.2.2/PKG-INFO +23 -0
  25. crosscontract-0.2.2/README.md +6 -0
  26. crosscontract-0.2.2/docs/about.md +3 -0
  27. crosscontract-0.2.2/docs/client/index.md +26 -0
  28. crosscontract-0.2.2/docs/contracts/gdp_example.yaml +31 -0
  29. crosscontract-0.2.2/docs/contracts/index.md +40 -0
  30. crosscontract-0.2.2/docs/contracts/metadata.md +63 -0
  31. crosscontract-0.2.2/docs/contracts/schema.md +21 -0
  32. crosscontract-0.2.2/docs/index.md +98 -0
  33. crosscontract-0.2.2/docs/notebooks/.gitignore +2 -0
  34. crosscontract-0.2.2/docs/reference/client.md +7 -0
  35. crosscontract-0.2.2/docs/reference/contracts.md +30 -0
  36. crosscontract-0.2.2/mkdocs.yml +74 -0
  37. crosscontract-0.2.2/notebooks/.gitkeep +0 -0
  38. crosscontract-0.2.2/notebooks/client_tutorial.ipynb +1557 -0
  39. crosscontract-0.2.2/notebooks/contract_tutorial.ipynb +295 -0
  40. crosscontract-0.2.2/pyproject.toml +108 -0
  41. crosscontract-0.2.2/scripts/copy_notebooks_to_docs.py +21 -0
  42. crosscontract-0.2.2/src/crosscontract/__init__.py +14 -0
  43. crosscontract-0.2.2/src/crosscontract/contracts/__init__.py +9 -0
  44. crosscontract-0.2.2/src/crosscontract/contracts/contracts/__init__.py +4 -0
  45. crosscontract-0.2.2/src/crosscontract/contracts/contracts/base_contract.py +103 -0
  46. crosscontract-0.2.2/src/crosscontract/contracts/contracts/cross_contract.py +64 -0
  47. crosscontract-0.2.2/src/crosscontract/contracts/schema/__init__.py +29 -0
  48. crosscontract-0.2.2/src/crosscontract/contracts/schema/adapters/__init__.py +18 -0
  49. crosscontract-0.2.2/src/crosscontract/contracts/schema/adapters/abstract_adapter.py +30 -0
  50. crosscontract-0.2.2/src/crosscontract/contracts/schema/adapters/pandera_adapter.py +557 -0
  51. crosscontract-0.2.2/src/crosscontract/contracts/schema/adapters/pydantic_adapter.py +288 -0
  52. crosscontract-0.2.2/src/crosscontract/contracts/schema/adapters/sqlalchemy_adapter.py +168 -0
  53. crosscontract-0.2.2/src/crosscontract/contracts/schema/adapters/utils.py +30 -0
  54. crosscontract-0.2.2/src/crosscontract/contracts/schema/exceptions/__init__.py +1 -0
  55. crosscontract-0.2.2/src/crosscontract/contracts/schema/exceptions/validation_error.py +222 -0
  56. crosscontract-0.2.2/src/crosscontract/contracts/schema/field_descriptors/__init__.py +20 -0
  57. crosscontract-0.2.2/src/crosscontract/contracts/schema/field_descriptors/descriptors.py +66 -0
  58. crosscontract-0.2.2/src/crosscontract/contracts/schema/field_descriptors/field_descriptors.py +89 -0
  59. crosscontract-0.2.2/src/crosscontract/contracts/schema/fields/__init__.py +18 -0
  60. crosscontract-0.2.2/src/crosscontract/contracts/schema/fields/base.py +61 -0
  61. crosscontract-0.2.2/src/crosscontract/contracts/schema/fields/datetime_field.py +37 -0
  62. crosscontract-0.2.2/src/crosscontract/contracts/schema/fields/list_field.py +55 -0
  63. crosscontract-0.2.2/src/crosscontract/contracts/schema/fields/numeric_field.py +44 -0
  64. crosscontract-0.2.2/src/crosscontract/contracts/schema/fields/string_field.py +48 -0
  65. crosscontract-0.2.2/src/crosscontract/contracts/schema/reference/__init__.py +4 -0
  66. crosscontract-0.2.2/src/crosscontract/contracts/schema/reference/foreign_key.py +150 -0
  67. crosscontract-0.2.2/src/crosscontract/contracts/schema/reference/primary_key.py +52 -0
  68. crosscontract-0.2.2/src/crosscontract/contracts/schema/schema.py +253 -0
  69. crosscontract-0.2.2/src/crosscontract/contracts/schema/validation/__init__.py +3 -0
  70. crosscontract-0.2.2/src/crosscontract/contracts/schema/validation/validate_dataframe.py +81 -0
  71. crosscontract-0.2.2/src/crosscontract/contracts/utils.py +35 -0
  72. crosscontract-0.2.2/src/crosscontract/contracts/valid_items.py +14 -0
  73. crosscontract-0.2.2/src/crosscontract/crossclient/__init__.py +3 -0
  74. crosscontract-0.2.2/src/crosscontract/crossclient/crossclient.py +146 -0
  75. crosscontract-0.2.2/src/crosscontract/crossclient/exceptions/__init__.py +24 -0
  76. crosscontract-0.2.2/src/crosscontract/crossclient/exceptions/exception_factory.py +104 -0
  77. crosscontract-0.2.2/src/crosscontract/crossclient/exceptions/exceptions.py +104 -0
  78. crosscontract-0.2.2/src/crosscontract/crossclient/logger.py +4 -0
  79. crosscontract-0.2.2/src/crosscontract/crossclient/services/__init__.py +4 -0
  80. crosscontract-0.2.2/src/crosscontract/crossclient/services/contract_resource.py +303 -0
  81. crosscontract-0.2.2/src/crosscontract/crossclient/services/contract_service.py +267 -0
  82. crosscontract-0.2.2/src/crosscontract/py.typed +0 -0
  83. crosscontract-0.2.2/src/tests/__init__.py +1 -0
  84. crosscontract-0.2.2/src/tests/contracts/contracts/test_contracts.py +113 -0
  85. crosscontract-0.2.2/src/tests/contracts/frictionless_package_standard_v2.json +2886 -0
  86. crosscontract-0.2.2/src/tests/contracts/frictionless_table_standard_v1.json +1516 -0
  87. crosscontract-0.2.2/src/tests/contracts/frictionless_table_standard_v2.json +2431 -0
  88. crosscontract-0.2.2/src/tests/contracts/schema/__init__.py +0 -0
  89. crosscontract-0.2.2/src/tests/contracts/schema/adapters/test_integration_pandera.py +139 -0
  90. crosscontract-0.2.2/src/tests/contracts/schema/adapters/test_integration_pandera_references.py +195 -0
  91. crosscontract-0.2.2/src/tests/contracts/schema/adapters/test_integration_pydantic.py +190 -0
  92. crosscontract-0.2.2/src/tests/contracts/schema/adapters/test_pandera_pandas_adapter.py +300 -0
  93. crosscontract-0.2.2/src/tests/contracts/schema/adapters/test_pydantic_adapater.py +683 -0
  94. crosscontract-0.2.2/src/tests/contracts/schema/adapters/test_sqlaqlchemy_adapter.py +204 -0
  95. crosscontract-0.2.2/src/tests/contracts/schema/adapters/test_utils_adapter.py +20 -0
  96. crosscontract-0.2.2/src/tests/contracts/schema/exceptions/__init__.py +0 -0
  97. crosscontract-0.2.2/src/tests/contracts/schema/exceptions/test_validation_error.py +377 -0
  98. crosscontract-0.2.2/src/tests/contracts/schema/reference/__init__.py +0 -0
  99. crosscontract-0.2.2/src/tests/contracts/schema/reference/test_foreign_key.py +229 -0
  100. crosscontract-0.2.2/src/tests/contracts/schema/reference/test_primary_key.py +28 -0
  101. crosscontract-0.2.2/src/tests/contracts/schema/test_descriptors.py +125 -0
  102. crosscontract-0.2.2/src/tests/contracts/schema/test_schema.py +339 -0
  103. crosscontract-0.2.2/src/tests/contracts/schema/validation/__init__.py +0 -0
  104. crosscontract-0.2.2/src/tests/contracts/schema/validation/test_pandas_validation.py +192 -0
  105. crosscontract-0.2.2/src/tests/contracts/simple_contract.yaml +39 -0
  106. crosscontract-0.2.2/src/tests/contracts/test_utils.py +46 -0
  107. crosscontract-0.2.2/src/tests/crossclient/conftest.py +69 -0
  108. crosscontract-0.2.2/src/tests/crossclient/contracts/__init__.py +0 -0
  109. crosscontract-0.2.2/src/tests/crossclient/contracts/test_contract_resource.py +444 -0
  110. crosscontract-0.2.2/src/tests/crossclient/contracts/test_contracts_service.py +341 -0
  111. crosscontract-0.2.2/src/tests/crossclient/exceptions/__init__.py +0 -0
  112. crosscontract-0.2.2/src/tests/crossclient/exceptions/test_exception_factory.py +183 -0
  113. crosscontract-0.2.2/src/tests/crossclient/exceptions/test_exceptions.py +60 -0
  114. crosscontract-0.2.2/src/tests/crossclient/test_crossclient.py +138 -0
  115. crosscontract-0.2.2/uv.lock +3360 -0
@@ -0,0 +1 @@
1
+ * @jabrell
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report a software bug or issue
4
+ title: "\U0001F41E Bug: [describe the issue]"
5
+ labels: bug
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ ### Describe the Bug
11
+ A clear and concise description of what the bug is.
12
+
13
+ ### Steps to Reproduce
14
+ 1. Go to '...'
15
+ 2. Click on '...'
16
+ 3. Scroll down to '...'
17
+ 4. See error
18
+
19
+ ### Expected Behavior
20
+ What you expected to happen instead.
21
+
22
+ ### Screenshots or Logs
23
+ If applicable, add screenshots or logs to help explain the issue.
24
+
25
+ ### Environment
26
+ - Device: [eg. Laptop 13", iPhone 15, iPad Air]
27
+ - OS: [e.g. Windows 11, macOS 14]
28
+ - Browser/app version: [e.g. Chrome 115, v2.3.1]
29
+
30
+ ### Additional context
31
+ Add any other context about the problem here.
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: Discussion / Design Proposal
3
+ about: Share an idea or proposal for feedback
4
+ title: "\U0001F4AD Discussion: [topic or idea]"
5
+ labels: question
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ ### Topic
11
+ Briefly describe the concept, idea, or challenge.
12
+
13
+ ### Problem Statement
14
+ What problem are we trying to solve or avoid?
15
+
16
+ ### Proposed Direction
17
+ Outline your suggested approach or solution.
18
+
19
+ ### Alternatives Considered
20
+ Any other directions you thought of or rejected?
21
+
22
+ ### Open Questions
23
+ - [ ] What are the trade-offs?
24
+ - [ ] What do we need to learn or test?
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: Documentation Request
3
+ about: Request updates or additions to documentation
4
+ title: "\U0001F4DA Docs: [topic or file name]"
5
+ labels: documentation
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ ### Topic or Page
11
+ Which doc or section needs an update?
12
+
13
+ ### Problem or Gap
14
+ What’s currently unclear, outdated, or missing?
15
+
16
+ ### Suggested Changes
17
+ List specific edits, new sections, or examples to add.
18
+
19
+ ### Supporting Links or Content
20
+ If relevant, include screenshots, code, or references.
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an new feature or capability
4
+ title: "\U0001F31F Feature: [suggested feature name]"
5
+ labels: feature
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ ### User Story
11
+ **As a [role],**
12
+ **I want [an action or feature],**
13
+ **So that [a reason or benefit].**
14
+
15
+ ### Description
16
+ A detailed explanation of the feature you'd like to see.
17
+
18
+ ### Acceptance Criteria
19
+ - [ ] Criteria 1: Describe the first acceptance criterion here.
20
+ - [ ] Criteria 2: Describe the second acceptance criterion here.
21
+ - [ ] Criteria 3: Describe additional criteria as needed.
22
+
23
+ ### Definition of Done
24
+ - [ ] All acceptance criteria are met.
25
+ - [ ] Code is reviewed and approved.
26
+ - [ ] Necessary tests are written and pass.
27
+ - [ ] Documentation is updated, if applicable.
28
+ - [ ] Feature is deployed to the [environment name].
29
+
30
+ ### Additional Context
31
+ Add any related links, screenshots, or prior discussions.
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: Improvement
3
+ about: Propose improvements to existing features
4
+ title: "\U0001F501 Improve: [feature/component name]"
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ ### Current Behavior
11
+ Briefly describe what the current functionality is and any issues with it.
12
+
13
+ ### Suggested Improvement
14
+ Describe how this feature could be improved, optimized, or simplified.
15
+
16
+ ### Why This Matters
17
+ Explain the impact or benefit of this change to users or maintainers.
18
+
19
+ ### Related Issues or Feedback
20
+ List any related discussions, issues, or user requests.
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: Maintenance / Chore
3
+ about: Internal development or maintenance task
4
+ title: "\U0001F6E0️ Chore: [task name]"
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ ### Task Description
11
+ Explain what needs to be done and why.
12
+
13
+ ### Context
14
+ Is this related to refactoring, tech debt, infra updates, etc.?
15
+
16
+ ### Dependencies
17
+ Does this task block or depend on other issues?
18
+
19
+ ### Definition of Done
20
+ - [ ] Clear outcome or artifact produced
21
+ - [ ] No user-visible changes unless noted
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: QA / Test Case
3
+ about: Add or request test scenarios or QA validation
4
+ title: "\U0001F9EA Test Case: [area or component]"
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ ### What to Test
11
+ Describe the functionality or area that needs testing.
12
+
13
+ ###Test Scenarios
14
+ - [ ] Scenario 1: ...
15
+ - [ ] Scenario 2: ...
16
+ - [ ] Scenario 3: ...
17
+
18
+ ### Expected Results
19
+ Describe what each test should confirm or validate.
20
+
21
+ ### Environment / Test Notes
22
+ Mention browsers, platforms, or edge cases to consider.
@@ -0,0 +1,76 @@
1
+ # GitHub Copilot Instructions
2
+
3
+ You are an expert **Senior Python Software Engineer** specializing in distributed systems, data modeling, and API design. You are responsible for maintaining a Python Package that provides high-integrity data contracts and SDKs.
4
+
5
+ ## 1. Interaction Protocol (CRITICAL)
6
+
7
+ - **Plan First:** For logic changes, refactoring, or new features, **do not write code immediately**. Outline a step-by-step plan.
8
+ - **Confirm:** Explicitly ask: _"Does this plan align with your intent, or should we adjust?"_ Wait for approval.
9
+ - **Clarify:** If requirements are vague, ask clarifying questions immediately.
10
+
11
+ ## 2. Project Structure (The Map)
12
+
13
+ The project is a Monorepo managed by `uv`. Always check relative paths against this map:
14
+
15
+ - **Root Configs:** `pyproject.toml`, `uv.lock`, `mkdocs.yml` (Documentation).
16
+ - **Libraries & Packages:**
17
+ - `src/crosscontract/contracts/`: Data Contracts, Schema definitions, and Pydantic models.
18
+ - `src/crosscontract/crossclient/`: Synchronous HTTP client SDK.
19
+ - **Data & Scripts:**
20
+ - `notebooks/`: Notebooks for illustration and experimentation.
21
+ - **Documentation:**
22
+ - `docs/`: MkDocs documentation source files.
23
+
24
+ ## 3. Tech Stack & Standards
25
+
26
+ - **Language:** Python 3.12+ (Use modern type hinting: PEP 604 union types `int | str`, `Generic` types, and `TypedDict`).
27
+ - **Data Contracts (Pydantic v2):**
28
+ - **Models:** Use `ConfigDict(extra='forbid', str_strip_whitespace=True)` for strict validation.
29
+ - **Polymorphism:** Use `Annotated[Union[...], Field(discriminator="type")]` for polymorphic list fields (e.g., `FieldUnion`).
30
+ - **Frictionless Compat:** `TableSchema` models may use camelCase fields (e.g., `primaryKey`) to match JSON schema standards directly.
31
+ - **Validation:** Use `model_validator(mode='after')` for cross-field validation.
32
+ - **Data Validation:**
33
+ - Use **Pandera** (`pandera.pandas`) for DataFrame-level validation.
34
+ - **API Client:**
35
+ - Use `httpx.Client` for **synchronous** operations.
36
+ - **Error Handling:** Raise `CrossClientError` base exception. Map 422 responses to `ValidationError` containing detailed structure.
37
+ - **Context Manager:** The client is designed to be used as a context manager (`with CrossClient(...) as client:`).
38
+ - **Package Manager:** **uv**.
39
+ - Use `uv sync` or `uv add`. Do not suggest `pip`.
40
+
41
+ ## 4. Code Style & Linting
42
+
43
+ - **Linting:** Strictly follow `ruff` rules. Configured in `pyproject.toml`.
44
+ - **Imports:** Grouping: 1. Stdlib, 2. Third-party (include `pydantic`, `pandas`, `httpx`), 3. Workspace packages (`crosscontract`), 4. Local modules.
45
+ - **Typing:** **Strict typing is required.** Use `Any` only as a last resort. Use `Self` for method return types where applicable.
46
+ - **Naming:** Follow PEP8. Exceptions allowed for specific Schema fields (camelCase) where mapping to external JSON standards is required.
47
+
48
+ ## 5. Documentation (MkDocs)
49
+
50
+ - **Google Style:** All public APIs must have Google-style docstrings.
51
+ - **Admonitions:** Use MkDocs Material syntax (e.g., `!!! note "Title"`) in docstrings and `.md` files.
52
+ - **Root Config:** `mkdocs.yml` in the root directory controls the docs site.
53
+ - **Documentation:** When adding features, identify which file in `docs/` needs an update.
54
+
55
+ ## 6. Testing
56
+
57
+ - **Pattern:** Use **Arrange-Act-Assert (AAA)**.
58
+ - **Tooling:** Use `pytest` for all tests. Use `respx` for mocking HTTP requests.
59
+ - **Contract Testing:** Ensure every Pydantic model has a test case for:
60
+ 1. Valid data (Happy path).
61
+ 2. Invalid data (Edge cases/Validation errors).
62
+ 3. Serialization to/from JSON.
63
+ - **Isolation:** Mock external API calls using `respx` to test the client without hitting real endpoints.
64
+ - **Organization:** Mirror source structure under `tests/`. Group related cases in classes.
65
+
66
+ ## 7. Frictionless Mapping Reference (Internal)
67
+
68
+ When implementing Frictionless schemas in Pydantic:
69
+
70
+ - `name` -> Field name
71
+ - `type` -> Python type hint (mapped via `FieldUnion` discriminators)
72
+ - `title` -> `Field(title=...)`
73
+ - `constraints.required` -> Non-optional type hint
74
+ - `description` -> `Field(description=...)`
75
+ - `constraints.enum` -> `Literal` or `Enum`
76
+ - `primaryKey` -> `primaryKey` field in `TableSchema`
@@ -0,0 +1,26 @@
1
+ name: Lint PR Title
2
+
3
+ on:
4
+ workflow_call:
5
+
6
+ jobs:
7
+ validate_title:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: amannn/action-semantic-pull-request@v5
11
+ env:
12
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
13
+ with:
14
+ # The complete recommended list
15
+ types: |
16
+ feat
17
+ fix
18
+ docs
19
+ style
20
+ refactor
21
+ perf
22
+ test
23
+ ci
24
+ chore
25
+ revert
26
+ requireScope: false
@@ -0,0 +1,18 @@
1
+ # Orchestrator workflow for the main branch.
2
+ # Runs tests on every PR to the main branch.
3
+ name: Check PR Main Branch
4
+
5
+ on:
6
+ pull_request:
7
+ branches:
8
+ - main
9
+ types:
10
+ - opened
11
+ - edited
12
+ - synchronize
13
+
14
+ jobs:
15
+ lint_pr_title:
16
+ uses: ./.github/workflows/check_pr_title.yml
17
+ test_and_coverage:
18
+ uses: ./.github/workflows/test_and_coverage.yml
@@ -0,0 +1,53 @@
1
+ # Reusable workflow that builds the MkDocs documentation site and deploys
2
+ # it to GitHub Pages. Requires 'workflow_call' or 'workflow_dispatch'.
3
+ name: Build and Deploy Docs
4
+
5
+ on:
6
+ workflow_call:
7
+ inputs:
8
+ ref:
9
+ description: "The git ref to check out (tag, branch, or SHA)"
10
+ required: false
11
+ type: string
12
+ default: ""
13
+ workflow_dispatch:
14
+ permissions:
15
+ contents: write
16
+ pages: write
17
+ id-token: write
18
+
19
+ jobs:
20
+ deploy:
21
+ environment:
22
+ name: github-pages
23
+ url: ${{ steps.deployment.outputs.page_url }}
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - name: Checkout repository
27
+ uses: actions/checkout@v6
28
+
29
+ - name: Install uv
30
+ uses: astral-sh/setup-uv@v7
31
+ with:
32
+ enable-cache: true
33
+ cache-dependency-glob: "uv.lock"
34
+
35
+ - name: Set up Python
36
+ run: uv python install 3.12
37
+
38
+ - name: Install dependencies
39
+ run: uv sync --group docs
40
+
41
+ - name: Build Docs
42
+ # Change 'gh-deploy' to 'build'. This creates the 'site' folder.
43
+ run: uv run mkdocs build
44
+
45
+ - name: Upload artifact
46
+ uses: actions/upload-pages-artifact@v3
47
+ with:
48
+ # MkDocs builds to the 'site' directory by default
49
+ path: "./site"
50
+
51
+ - name: Deploy to GitHub Pages
52
+ id: deployment
53
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,59 @@
1
+ # Standalone workflow to publish the package to PyPI.
2
+ # Triggered manually. Defaults to the latest release tag.
3
+ name: Publish to PyPI
4
+
5
+ on:
6
+ workflow_dispatch:
7
+ inputs:
8
+ version:
9
+ description: "Version tag to publish (e.g. v0.2.1). Defaults to latest release."
10
+ required: false
11
+ type: string
12
+ default: ""
13
+
14
+ jobs:
15
+ resolve_version:
16
+ runs-on: ubuntu-latest
17
+ outputs:
18
+ tag: ${{ steps.resolve.outputs.tag }}
19
+ steps:
20
+ - name: Get latest release tag
21
+ id: resolve
22
+ env:
23
+ GH_TOKEN: ${{ github.token }}
24
+ run: |
25
+ if [ -n "${{ inputs.version }}" ]; then
26
+ echo "tag=${{ inputs.version }}" >> $GITHUB_OUTPUT
27
+ else
28
+ LATEST=$(gh release view --repo ${{ github.repository }} --json tagName -q .tagName)
29
+ echo "tag=$LATEST" >> $GITHUB_OUTPUT
30
+ fi
31
+ - name: Validate tag exists
32
+ if: inputs.version != ''
33
+ env:
34
+ GH_TOKEN: ${{ github.token }}
35
+ run: |
36
+ if ! gh release view ${{ inputs.version }} --repo ${{ github.repository }} > /dev/null 2>&1; then
37
+ echo "Error: version '${{ inputs.version }}' not found in releases"
38
+ exit 1
39
+ fi
40
+
41
+ publish:
42
+ needs: resolve_version
43
+ runs-on: ubuntu-latest
44
+ environment:
45
+ name: pypi-test
46
+ url: https://test.pypi.org/p/crosscontract
47
+ permissions:
48
+ id-token: write
49
+ steps:
50
+ - uses: actions/checkout@v4
51
+ with:
52
+ ref: ${{ needs.resolve_version.outputs.tag }}
53
+ - uses: astral-sh/setup-uv@v5
54
+ - run: uv build
55
+ - name: Inspect wheel contents
56
+ run: unzip -l dist/*.whl
57
+ - uses: pypa/gh-action-pypi-publish@release/v1
58
+ with:
59
+ repository-url: https://test.pypi.org/legacy/
@@ -0,0 +1,31 @@
1
+ # Orchestrator workflow to deploy a new release when changes are pushed to the
2
+ # main branch. It runs tests, creates a release if needed, and deploys docs if
3
+ #the release was successful.
4
+ name: Release Main Branch
5
+
6
+ on:
7
+ workflow_dispatch:
8
+ push:
9
+ branches:
10
+ - main
11
+
12
+ jobs:
13
+ test_and_coverage:
14
+ uses: ./.github/workflows/test_and_coverage.yml
15
+
16
+ release:
17
+ needs: test_and_coverage
18
+ if: success()
19
+ uses: ./.github/workflows/versioning.yml
20
+ permissions:
21
+ contents: write
22
+ secrets: inherit
23
+
24
+ deploy_docs:
25
+ needs: release
26
+ if: >-
27
+ success() &&
28
+ (needs.release.outputs.released == 'true' || needs.release.result == 'success')
29
+ uses: ./.github/workflows/deploy_docs.yml
30
+ with:
31
+ ref: ${{ needs.release.outputs.released == 'true' && needs.release.outputs.tag || github.ref }}
@@ -0,0 +1,75 @@
1
+ # Reusable workflow that runs the test suite and generates coverage reports
2
+ # for Python 3.12 and 3.13. It includes pre-commit checks.
3
+ name: Test and Coverage
4
+
5
+ on:
6
+ workflow_call:
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ pre-commit:
11
+ name: Check Pre-commit Hooks
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Checkout repository
15
+ uses: actions/checkout@v6
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v7
19
+ with:
20
+ enable-cache: true
21
+ cache-dependency-glob: "uv.lock"
22
+
23
+ - name: Set up Python
24
+ run: uv python install 3.12
25
+
26
+ - name: Install dependencies
27
+ run: uv sync
28
+
29
+ - name: Run pre-commit
30
+ run: uv run pre-commit run --all-files
31
+
32
+ test:
33
+ name: Test (Python ${{ matrix.python-version }})
34
+ runs-on: ubuntu-latest
35
+ strategy:
36
+ fail-fast: false
37
+ matrix:
38
+ python-version:
39
+ - "3.11"
40
+ - "3.12"
41
+ - "3.13"
42
+
43
+ steps:
44
+ - name: Checkout repository
45
+ uses: actions/checkout@v6
46
+
47
+ - name: Install uv
48
+ uses: astral-sh/setup-uv@v7
49
+ with:
50
+ enable-cache: true
51
+ cache-dependency-glob: "uv.lock"
52
+
53
+ - name: Set up Python ${{ matrix.python-version }}
54
+ run: uv python install ${{ matrix.python-version }}
55
+
56
+ - name: Install dependencies
57
+ run: uv sync
58
+
59
+ - name: Run tests with coverage
60
+ run: |
61
+ set -o pipefail
62
+ uv run coverage run -m pytest | tee pytest.log
63
+
64
+ - name: Generate Reports
65
+ if: success() || failure()
66
+ run: |
67
+ echo "## Test Summary (Python ${{ matrix.python-version }})" >> $GITHUB_STEP_SUMMARY
68
+ echo '```' >> $GITHUB_STEP_SUMMARY
69
+ cat pytest.log >> $GITHUB_STEP_SUMMARY
70
+ echo '```' >> $GITHUB_STEP_SUMMARY
71
+
72
+ echo "## Coverage Summary (Python ${{ matrix.python-version }})" >> $GITHUB_STEP_SUMMARY
73
+ echo '```' >> $GITHUB_STEP_SUMMARY
74
+ uv run coverage report >> $GITHUB_STEP_SUMMARY
75
+ echo '```' >> $GITHUB_STEP_SUMMARY
@@ -0,0 +1,37 @@
1
+ name: Versioning
2
+
3
+ on:
4
+ workflow_call:
5
+ outputs:
6
+ released:
7
+ description: "True if a release was created"
8
+ value: ${{ jobs.versioning.outputs.released }}
9
+ tag:
10
+ description: "The tag created (e.g. v1.0.1)"
11
+ value: ${{ jobs.versioning.outputs.tag }}
12
+
13
+ jobs:
14
+ versioning:
15
+ runs-on: ubuntu-latest
16
+ permissions:
17
+ contents: write # Required to push the new version commit and tag
18
+ outputs:
19
+ released: ${{ steps.release.outputs.released }}
20
+ tag: ${{ steps.release.outputs.tag }}
21
+
22
+ steps:
23
+ - name: Generate token
24
+ id: generate-token
25
+ uses: actions/create-github-app-token@v2
26
+ with:
27
+ app-id: ${{ secrets.APP_ID }}
28
+ private-key: ${{ secrets.APP_PRIVATE_KEY }}
29
+ - uses: actions/checkout@v6.0.2
30
+ with:
31
+ fetch-depth: 0
32
+ token: ${{ steps.generate-token.outputs.token }}
33
+ - name: Python Semantic Release
34
+ id: release
35
+ uses: python-semantic-release/python-semantic-release@v10.5.3
36
+ with:
37
+ github_token: ${{ steps.generate-token.outputs.token }}