qbvisor 0.3.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 (108) hide show
  1. qbvisor-0.3.0/.env.example +13 -0
  2. qbvisor-0.3.0/.github/workflows/ci.yml +115 -0
  3. qbvisor-0.3.0/.github/workflows/pages.yml +73 -0
  4. qbvisor-0.3.0/.github/workflows/release.yml +76 -0
  5. qbvisor-0.3.0/.gitignore +41 -0
  6. qbvisor-0.3.0/CHANGELOG.md +105 -0
  7. qbvisor-0.3.0/CONTRIBUTING.md +95 -0
  8. qbvisor-0.3.0/LICENSE.md +7 -0
  9. qbvisor-0.3.0/PKG-INFO +259 -0
  10. qbvisor-0.3.0/README.md +231 -0
  11. qbvisor-0.3.0/SECURITY.md +36 -0
  12. qbvisor-0.3.0/docs/api/README.md +43 -0
  13. qbvisor-0.3.0/docs/api/quickbase-oas-manifest.json +1261 -0
  14. qbvisor-0.3.0/docs/application-building.md +154 -0
  15. qbvisor-0.3.0/docs/backups-and-attachments.md +147 -0
  16. qbvisor-0.3.0/docs/configuration.md +104 -0
  17. qbvisor-0.3.0/docs/data-workflows.md +180 -0
  18. qbvisor-0.3.0/docs/declarative-schemas.md +206 -0
  19. qbvisor-0.3.0/docs/index.md +37 -0
  20. qbvisor-0.3.0/docs/logging-and-errors.md +114 -0
  21. qbvisor-0.3.0/docs/reference/backups.md +16 -0
  22. qbvisor-0.3.0/docs/reference/client.md +54 -0
  23. qbvisor-0.3.0/docs/reference/exceptions.md +23 -0
  24. qbvisor-0.3.0/docs/reference/index.md +36 -0
  25. qbvisor-0.3.0/docs/reference/logging.md +11 -0
  26. qbvisor-0.3.0/docs/reference/queries.md +30 -0
  27. qbvisor-0.3.0/docs/reference/schemas.md +25 -0
  28. qbvisor-0.3.0/docs/reference/transport.md +17 -0
  29. qbvisor-0.3.0/docs/release-policy.md +56 -0
  30. qbvisor-0.3.0/docs/releases/0.3.0.md +81 -0
  31. qbvisor-0.3.0/docs/releasing.md +105 -0
  32. qbvisor-0.3.0/docs/upgrading-to-0.3.md +113 -0
  33. qbvisor-0.3.0/mkdocs.yml +58 -0
  34. qbvisor-0.3.0/pyproject.toml +99 -0
  35. qbvisor-0.3.0/scripts/audit_quickbase_oas.py +345 -0
  36. qbvisor-0.3.0/scripts/verify_distribution.py +270 -0
  37. qbvisor-0.3.0/scripts/verify_docs.py +153 -0
  38. qbvisor-0.3.0/src/qbvisor/__init__.py +141 -0
  39. qbvisor-0.3.0/src/qbvisor/_attachments.py +83 -0
  40. qbvisor-0.3.0/src/qbvisor/_backup/__init__.py +23 -0
  41. qbvisor-0.3.0/src/qbvisor/_backup/attachments.py +303 -0
  42. qbvisor-0.3.0/src/qbvisor/_backup/reader.py +263 -0
  43. qbvisor-0.3.0/src/qbvisor/_backup/records.py +83 -0
  44. qbvisor-0.3.0/src/qbvisor/_backup/schema.py +143 -0
  45. qbvisor-0.3.0/src/qbvisor/_backup/workflow.py +184 -0
  46. qbvisor-0.3.0/src/qbvisor/_backup/workspace.py +190 -0
  47. qbvisor-0.3.0/src/qbvisor/_pagination.py +165 -0
  48. qbvisor-0.3.0/src/qbvisor/_records/__init__.py +1 -0
  49. qbvisor-0.3.0/src/qbvisor/_records/pagination.py +186 -0
  50. qbvisor-0.3.0/src/qbvisor/_records/upsert.py +331 -0
  51. qbvisor-0.3.0/src/qbvisor/_resources/__init__.py +1 -0
  52. qbvisor-0.3.0/src/qbvisor/_resources/apps.py +87 -0
  53. qbvisor-0.3.0/src/qbvisor/_resources/base.py +84 -0
  54. qbvisor-0.3.0/src/qbvisor/_resources/fields.py +102 -0
  55. qbvisor-0.3.0/src/qbvisor/_resources/relationships.py +129 -0
  56. qbvisor-0.3.0/src/qbvisor/_resources/tables.py +93 -0
  57. qbvisor-0.3.0/src/qbvisor/_schema/__init__.py +1 -0
  58. qbvisor-0.3.0/src/qbvisor/_schema/apply.py +364 -0
  59. qbvisor-0.3.0/src/qbvisor/_schema/dependencies.py +122 -0
  60. qbvisor-0.3.0/src/qbvisor/_schema/planner.py +1191 -0
  61. qbvisor-0.3.0/src/qbvisor/_schema/relationship_apply.py +327 -0
  62. qbvisor-0.3.0/src/qbvisor/_schema/state.py +128 -0
  63. qbvisor-0.3.0/src/qbvisor/_version.py +8 -0
  64. qbvisor-0.3.0/src/qbvisor/async_transport.py +293 -0
  65. qbvisor-0.3.0/src/qbvisor/backup.py +436 -0
  66. qbvisor-0.3.0/src/qbvisor/client.py +1529 -0
  67. qbvisor-0.3.0/src/qbvisor/exceptions.py +144 -0
  68. qbvisor-0.3.0/src/qbvisor/helpers.py +51 -0
  69. qbvisor-0.3.0/src/qbvisor/log_runner.py +166 -0
  70. qbvisor-0.3.0/src/qbvisor/metadata.py +238 -0
  71. qbvisor-0.3.0/src/qbvisor/models.py +49 -0
  72. qbvisor-0.3.0/src/qbvisor/py.typed +1 -0
  73. qbvisor-0.3.0/src/qbvisor/query_helper.py +192 -0
  74. qbvisor-0.3.0/src/qbvisor/query_value.py +37 -0
  75. qbvisor-0.3.0/src/qbvisor/schema.py +845 -0
  76. qbvisor-0.3.0/src/qbvisor/transport.py +416 -0
  77. qbvisor-0.3.0/tests/integration/conftest.py +564 -0
  78. qbvisor-0.3.0/tests/integration/test_sandbox_contract.py +757 -0
  79. qbvisor-0.3.0/tests/integration/test_schema_integration.py +384 -0
  80. qbvisor-0.3.0/tests/integration/test_transport_integration.py +32 -0
  81. qbvisor-0.3.0/tests/test_async_transport.py +228 -0
  82. qbvisor-0.3.0/tests/test_attachments.py +384 -0
  83. qbvisor-0.3.0/tests/test_backup_attachments.py +251 -0
  84. qbvisor-0.3.0/tests/test_backup_models.py +127 -0
  85. qbvisor-0.3.0/tests/test_backup_records.py +190 -0
  86. qbvisor-0.3.0/tests/test_backup_schema.py +127 -0
  87. qbvisor-0.3.0/tests/test_backup_workflow.py +173 -0
  88. qbvisor-0.3.0/tests/test_client_compatibility.py +1515 -0
  89. qbvisor-0.3.0/tests/test_client_facade.py +88 -0
  90. qbvisor-0.3.0/tests/test_exceptions.py +55 -0
  91. qbvisor-0.3.0/tests/test_metadata.py +106 -0
  92. qbvisor-0.3.0/tests/test_models.py +21 -0
  93. qbvisor-0.3.0/tests/test_oas_audit.py +103 -0
  94. qbvisor-0.3.0/tests/test_pagination.py +133 -0
  95. qbvisor-0.3.0/tests/test_public_api.py +55 -0
  96. qbvisor-0.3.0/tests/test_query_helper.py +59 -0
  97. qbvisor-0.3.0/tests/test_query_value.py +37 -0
  98. qbvisor-0.3.0/tests/test_record_pagination.py +133 -0
  99. qbvisor-0.3.0/tests/test_release_validation.py +62 -0
  100. qbvisor-0.3.0/tests/test_resource_contracts.py +40 -0
  101. qbvisor-0.3.0/tests/test_schema_apply.py +436 -0
  102. qbvisor-0.3.0/tests/test_schema_models.py +359 -0
  103. qbvisor-0.3.0/tests/test_schema_planner.py +774 -0
  104. qbvisor-0.3.0/tests/test_schema_relationship_apply.py +380 -0
  105. qbvisor-0.3.0/tests/test_transport.py +316 -0
  106. qbvisor-0.3.0/tests/test_upsert_batches.py +137 -0
  107. qbvisor-0.3.0/tests/typing/installed_package.py +6 -0
  108. qbvisor-0.3.0/uv.lock +1831 -0
@@ -0,0 +1,13 @@
1
+ # Runtime configuration
2
+ QB_REALM_HOSTNAME=your-realm.quickbase.com
3
+ QB_REALM_API_KEY=QB-USER-TOKEN replace-with-your-token
4
+ QB_APP_IDS={"Sandbox":"replace-with-your-app-id"}
5
+
6
+ # Dedicated persistent sandbox used by live integration tests
7
+ QBVISOR_TEST_REALM=your-realm.quickbase.com
8
+ QBVISOR_TEST_TOKEN=QB-USER-TOKEN replace-with-your-sandbox-token
9
+ QBVISOR_TEST_APP_ID=replace-with-your-sandbox-app-id
10
+
11
+ # Set only for an intentional live test run. Mutations must target an isolated sandbox.
12
+ QBVISOR_RUN_INTEGRATION=0
13
+ QBVISOR_ALLOW_SANDBOX_MUTATIONS=0
@@ -0,0 +1,115 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - main
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ci-${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ documentation:
18
+ name: Documentation
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - name: Check out repository
23
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
24
+ with:
25
+ persist-credentials: false
26
+
27
+ - name: Install uv and Python
28
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
29
+ with:
30
+ enable-cache: true
31
+ python-version: "3.12"
32
+
33
+ - name: Install dependencies
34
+ run: uv sync --frozen --all-groups
35
+
36
+ - name: Verify documentation sources
37
+ run: uv run --frozen python scripts/verify_docs.py
38
+
39
+ - name: Build documentation
40
+ run: uv run --frozen mkdocs build --strict
41
+
42
+ quality:
43
+ name: Quality (Python ${{ matrix.python-version }})
44
+ runs-on: ubuntu-latest
45
+ strategy:
46
+ fail-fast: false
47
+ matrix:
48
+ python-version:
49
+ - "3.12"
50
+ - "3.13"
51
+ - "3.14"
52
+
53
+ steps:
54
+ - name: Check out repository
55
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
56
+ with:
57
+ persist-credentials: false
58
+
59
+ - name: Install uv and Python
60
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
61
+ with:
62
+ enable-cache: true
63
+ python-version: ${{ matrix.python-version }}
64
+
65
+ - name: Install dependencies
66
+ run: uv sync --frozen --all-groups
67
+
68
+ - name: Check linting
69
+ run: uv run --frozen ruff check .
70
+
71
+ - name: Check formatting
72
+ run: uv run --frozen ruff format --check .
73
+
74
+ - name: Check typing
75
+ run: uv run --frozen mypy src/qbvisor
76
+
77
+ - name: Run tests
78
+ run: uv run --frozen pytest
79
+
80
+ build:
81
+ name: Build distribution
82
+ runs-on: ubuntu-latest
83
+
84
+ steps:
85
+ - name: Check out repository
86
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
87
+ with:
88
+ persist-credentials: false
89
+
90
+ - name: Install uv and Python
91
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
92
+ with:
93
+ enable-cache: true
94
+ python-version: "3.12"
95
+
96
+ - name: Build package
97
+ run: uv build
98
+
99
+ - name: Validate distribution metadata and contents
100
+ run: |
101
+ uv run --frozen twine check --strict dist/*
102
+ uv run --frozen python scripts/verify_distribution.py dist
103
+
104
+ - name: Verify wheel installation
105
+ run: |
106
+ wheel_path="$(find dist -name '*.whl' -print -quit)"
107
+ uv run --isolated --no-project --with "$wheel_path" \
108
+ python -c "import qbvisor; print(qbvisor.__version__)"
109
+
110
+ - name: Verify installed type information
111
+ run: |
112
+ wheel_path="$(find dist -name '*.whl' -print -quit)"
113
+ mypy_version="$(uv run --frozen mypy --version | awk '{print $2}')"
114
+ uv run --isolated --no-project --with "$wheel_path" --with "mypy==$mypy_version" \
115
+ mypy --config-file=/dev/null --strict tests/typing/installed_package.py
@@ -0,0 +1,73 @@
1
+ name: Documentation site
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ paths:
8
+ - ".github/workflows/pages.yml"
9
+ - "docs/**"
10
+ - "mkdocs.yml"
11
+ - "pyproject.toml"
12
+ - "scripts/verify_docs.py"
13
+ - "src/qbvisor/**"
14
+ - "uv.lock"
15
+ workflow_dispatch:
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ concurrency:
21
+ group: pages
22
+ cancel-in-progress: true
23
+
24
+ jobs:
25
+ build:
26
+ name: Build documentation site
27
+ runs-on: ubuntu-latest
28
+
29
+ steps:
30
+ - name: Check out repository
31
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
32
+ with:
33
+ persist-credentials: false
34
+
35
+ - name: Install uv and Python
36
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
37
+ with:
38
+ enable-cache: true
39
+ python-version: "3.12"
40
+
41
+ - name: Install dependencies
42
+ run: uv sync --frozen --all-groups
43
+
44
+ - name: Configure GitHub Pages
45
+ uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
46
+
47
+ - name: Verify documentation sources
48
+ run: uv run --frozen python scripts/verify_docs.py
49
+
50
+ - name: Build documentation
51
+ run: uv run --frozen mkdocs build --strict
52
+
53
+ - name: Upload documentation site
54
+ uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
55
+ with:
56
+ path: site/
57
+
58
+ deploy:
59
+ name: Deploy documentation site
60
+ needs:
61
+ - build
62
+ runs-on: ubuntu-latest
63
+ environment:
64
+ name: github-pages
65
+ url: ${{ steps.deployment.outputs.page_url }}
66
+ permissions:
67
+ pages: write
68
+ id-token: write
69
+
70
+ steps:
71
+ - name: Deploy to GitHub Pages
72
+ id: deployment
73
+ uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
@@ -0,0 +1,76 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types:
6
+ - published
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: release-${{ github.event.release.tag_name }}
13
+ cancel-in-progress: false
14
+
15
+ jobs:
16
+ build:
17
+ name: Build release distributions
18
+ if: ${{ !github.event.release.prerelease }}
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - name: Check out the release tag
23
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
24
+ with:
25
+ fetch-depth: 0
26
+ persist-credentials: false
27
+ ref: ${{ github.event.release.tag_name }}
28
+
29
+ - name: Install uv and Python
30
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
31
+ with:
32
+ enable-cache: true
33
+ python-version: "3.12"
34
+
35
+ - name: Verify the release commit is on main
36
+ run: git merge-base --is-ancestor "$GITHUB_SHA" origin/main
37
+
38
+ - name: Build distributions
39
+ run: uv build
40
+
41
+ - name: Validate release identity and distributions
42
+ env:
43
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
44
+ run: |
45
+ uv run --frozen twine check --strict dist/*
46
+ uv run --frozen python scripts/verify_distribution.py \
47
+ dist --release-tag "$RELEASE_TAG"
48
+
49
+ - name: Upload distributions
50
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
51
+ with:
52
+ name: python-package-distributions
53
+ path: dist/
54
+ if-no-files-found: error
55
+ retention-days: 7
56
+
57
+ publish:
58
+ name: Publish distributions to PyPI
59
+ needs:
60
+ - build
61
+ runs-on: ubuntu-latest
62
+ environment:
63
+ name: pypi
64
+ url: https://pypi.org/p/qbvisor
65
+ permissions:
66
+ id-token: write
67
+
68
+ steps:
69
+ - name: Download distributions
70
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
71
+ with:
72
+ name: python-package-distributions
73
+ path: dist/
74
+
75
+ - name: Publish distributions with attestations
76
+ uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1
@@ -0,0 +1,41 @@
1
+ # Python
2
+ __pycache__/
3
+ .venv/
4
+ .venv.nosync/
5
+ .uv-cache.nosync/
6
+ .mypy_cache/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .coverage*
10
+ htmlcov/
11
+ build/
12
+ dist/
13
+ site/
14
+ *.egg-info/
15
+ *.whl
16
+ *.py[cod]
17
+ *.pyo
18
+ *.pyd
19
+ .env
20
+ .env.*
21
+ !.env.example
22
+ *.log
23
+ *.csv
24
+ *.json
25
+ !docs/api/*.json
26
+
27
+ # Temp files
28
+ tmp/
29
+ temp/
30
+
31
+ # Log directories
32
+ logs/
33
+
34
+ # OS/IDE specific files
35
+ .DS_Store
36
+ .vscode/
37
+ .idea/
38
+
39
+ # Local API specifications and audit inputs
40
+ .cache/
41
+ .qbvisor/
@@ -0,0 +1,105 @@
1
+ # Changelog
2
+
3
+ This file records user-visible changes to qbvisor. The project follows
4
+ [Semantic Versioning](https://semver.org/) and keeps unreleased work under the `Unreleased`
5
+ heading.
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.3.0] - 2026-07-19
10
+
11
+ ### Added
12
+
13
+ - Add public package metadata, inline typing, release and security policies, and distribution
14
+ artifact validation ([#18]).
15
+ - Add trusted PyPI publishing with isolated OpenID Connect permissions, release identity checks,
16
+ artifact attestations, and a documented maintainer procedure ([#20]).
17
+ - Add task-focused guides, a generated public API reference, strict documentation validation, and
18
+ the `0.3.0` migration guide ([#19]).
19
+ - Publish the reviewed documentation site through GitHub Pages and expose its canonical URL in
20
+ package metadata ([#21]).
21
+ - Add a shared synchronous transport with pooled connections, explicit timeouts, structured
22
+ exceptions, and operation-aware retries ([#3]).
23
+ - Add app events, app roles, field usage, relationship lookup, relationship summary, and record
24
+ change endpoints ([#5], [#11], [#12]).
25
+ - Add versioned application backups with manifests, attachment capture, integrity verification,
26
+ and consistency checks ([#7]).
27
+ - Add declarative application and table schemas with reviewable plans, durable resource bindings,
28
+ relationship management, and native Quickbase formula fields ([#8], [#10]).
29
+ - Add a tracked Quickbase OpenAPI response-shape manifest and opt-in persistent sandbox contract
30
+ tests ([#2], [#3]).
31
+
32
+ ### Changed
33
+
34
+ - Move app, table, field, and relationship operations behind private resource services while
35
+ preserving `QuickBaseClient` as the public facade ([#6]).
36
+ - Return complete DataFrame queries and report results by default without changing their public
37
+ method signatures ([#14]).
38
+ - Scan record exports in stable Record ID order and write through temporary files before publishing
39
+ completed CSV files ([#13]).
40
+ - Batch record upserts by the exact serialized payload size, aggregate complete Quickbase outcomes,
41
+ and report partially completed or uncertain ranges ([#16], [#17]).
42
+ - Use bounded asynchronous I/O for attachment downloads while preserving the existing synchronous
43
+ entry points and result fields ([#4], [#15]).
44
+
45
+ ### Fixed
46
+
47
+ - Report the installed package version in the HTTP `User-Agent` instead of a stale hard-coded
48
+ version.
49
+ - Preserve attachment bytes across response encodings and base64 conversion ([#9]).
50
+ - Continue attachment discovery until Quickbase metadata confirms that all matching records have
51
+ been scanned ([#15]).
52
+ - Normalize record-change timestamps to conservative whole-second UTC values ([#12]).
53
+ - Invalidate and reuse table and field metadata without returning stale schema state ([#11]).
54
+
55
+ ### Security
56
+
57
+ - Keep authorization values and request bodies out of transport logs and public exception messages
58
+ ([#3]).
59
+ - Validate backup paths, attachment paths, and downloaded filenames before publishing files ([#7],
60
+ [#15]).
61
+
62
+ ## [0.2.0] - 2025-12-30
63
+
64
+ ### Added
65
+
66
+ - Add small logging entry hooks and publish the `0.2.0` package metadata.
67
+
68
+ ## [0.1.1] - 2025-06-19
69
+
70
+ ### Changed
71
+
72
+ - Expand query options, lower attachment concurrency for reliability, and expose more upsert
73
+ response information.
74
+
75
+ ## [0.1.0] - 2025-05-13
76
+
77
+ ### Added
78
+
79
+ - Publish the initial Quickbase client, query helpers, transport, tests, and project documentation.
80
+
81
+ [Unreleased]: https://github.com/ChrisEMetcalf/qbvisor/compare/v0.3.0...HEAD
82
+ [0.3.0]: https://github.com/ChrisEMetcalf/qbvisor/compare/v0.2.0...v0.3.0
83
+ [0.2.0]: https://github.com/ChrisEMetcalf/qbvisor/compare/v0.1.1...v0.2.0
84
+ [0.1.1]: https://github.com/ChrisEMetcalf/qbvisor/compare/v0.1.0...v0.1.1
85
+ [0.1.0]: https://github.com/ChrisEMetcalf/qbvisor/releases/tag/v0.1.0
86
+ [#2]: https://github.com/ChrisEMetcalf/qbvisor/pull/2
87
+ [#3]: https://github.com/ChrisEMetcalf/qbvisor/pull/3
88
+ [#4]: https://github.com/ChrisEMetcalf/qbvisor/pull/4
89
+ [#5]: https://github.com/ChrisEMetcalf/qbvisor/pull/5
90
+ [#6]: https://github.com/ChrisEMetcalf/qbvisor/pull/6
91
+ [#7]: https://github.com/ChrisEMetcalf/qbvisor/pull/7
92
+ [#8]: https://github.com/ChrisEMetcalf/qbvisor/pull/8
93
+ [#9]: https://github.com/ChrisEMetcalf/qbvisor/pull/9
94
+ [#10]: https://github.com/ChrisEMetcalf/qbvisor/pull/10
95
+ [#11]: https://github.com/ChrisEMetcalf/qbvisor/pull/11
96
+ [#12]: https://github.com/ChrisEMetcalf/qbvisor/pull/12
97
+ [#13]: https://github.com/ChrisEMetcalf/qbvisor/pull/13
98
+ [#14]: https://github.com/ChrisEMetcalf/qbvisor/pull/14
99
+ [#15]: https://github.com/ChrisEMetcalf/qbvisor/pull/15
100
+ [#16]: https://github.com/ChrisEMetcalf/qbvisor/pull/16
101
+ [#17]: https://github.com/ChrisEMetcalf/qbvisor/pull/17
102
+ [#18]: https://github.com/ChrisEMetcalf/qbvisor/pull/18
103
+ [#19]: https://github.com/ChrisEMetcalf/qbvisor/pull/19
104
+ [#20]: https://github.com/ChrisEMetcalf/qbvisor/pull/20
105
+ [#21]: https://github.com/ChrisEMetcalf/qbvisor/pull/21
@@ -0,0 +1,95 @@
1
+ # Contributing to qbvisor
2
+
3
+ qbvisor is shared infrastructure for developers who build on Quickbase. Changes should improve reliability, performance, idempotency, or developer experience.
4
+
5
+ ## Requirements
6
+
7
+ - Python 3.12, 3.13, or 3.14
8
+ - [uv](https://docs.astral.sh/uv/)
9
+
10
+ ## Setup
11
+
12
+ ```bash
13
+ uv sync --all-groups
14
+ ```
15
+
16
+ Run the local checks before opening a pull request:
17
+
18
+ ```bash
19
+ uv run ruff check .
20
+ uv run ruff format --check .
21
+ uv run mypy src/qbvisor
22
+ uv run pytest
23
+ uv run python scripts/verify_docs.py
24
+ uv run mkdocs build --strict
25
+ uv build
26
+ uv run twine check --strict dist/*
27
+ uv run python scripts/verify_distribution.py dist
28
+ ```
29
+
30
+ ## Compatibility
31
+
32
+ Existing public method names and call signatures should remain stable when practical. Clearly broken behavior may be corrected when the change includes regression tests and release notes.
33
+
34
+ `QuickBaseClient` is the supported high-level client. Preserve its public method names and call signatures unless a documented major release provides a migration path.
35
+
36
+ Record user-visible behavior in [CHANGELOG.md](CHANGELOG.md). Follow the versioning, Python support,
37
+ deprecation, and artifact requirements in [docs/release-policy.md](docs/release-policy.md).
38
+ Maintainers should use the controlled procedure in [docs/releasing.md](docs/releasing.md) for tags,
39
+ GitHub Releases, and PyPI publication.
40
+
41
+ ## Client architecture
42
+
43
+ `QuickBaseClient` is the stable public facade. Private modules under `qbvisor._resources` own request construction for apps, tables, fields, and relationships. These resource classes are implementation details: do not export them from `qbvisor`, document them as public interfaces, or require callers to construct them.
44
+
45
+ Public client methods should remain thin delegates while preserving their established signature, return shape, retry policy, error behavior, and metadata-cache effects. Resource services receive shared transport and metadata behavior through `ClientContext`; they must continue using the centralized client request path rather than creating sessions or duplicating error handling.
46
+
47
+ When moving an existing operation across this boundary, add a compatibility test for its exact request path, parameters, body, and documented top-level response shape. Schema mutations also require focused verification of label-to-ID resolution and cache invalidation.
48
+
49
+ ## Pull requests
50
+
51
+ Keep each pull request focused on one reviewable change. Describe:
52
+
53
+ - The problem being solved
54
+ - The direct and downstream effects
55
+ - Compatibility or migration concerns
56
+ - The checks used to verify the change
57
+
58
+ Changes require passing automated checks and an approving review before merge.
59
+
60
+ ## Integration testing
61
+
62
+ Unit tests and HTTP contract tests must not require Quickbase credentials.
63
+
64
+ Integration tests use a dedicated persistent sandbox application. Configure `QBVISOR_TEST_REALM`, `QBVISOR_TEST_TOKEN`, and `QBVISOR_TEST_APP_ID` locally; these values must never be committed.
65
+
66
+ Run the established sandbox contract without allowing fixture changes:
67
+
68
+ ```bash
69
+ QBVISOR_RUN_INTEGRATION=1 uv run pytest -m integration --no-cov
70
+ ```
71
+
72
+ Bootstrap missing persistent fixtures and run mutation contracts only with explicit approval:
73
+
74
+ ```bash
75
+ QBVISOR_RUN_INTEGRATION=1 QBVISOR_ALLOW_SANDBOX_MUTATIONS=1 \
76
+ uv run pytest -m integration --no-cov
77
+ ```
78
+
79
+ Mutation tests are outside the default suite. They must verify the configured realm and application ID, use uniquely named temporary resources, and clean up after themselves. Never run integration tests against a production application.
80
+
81
+ ## Quickbase API contract audit
82
+
83
+ The official Quickbase OAS is cached locally and excluded from version control. Refresh it and update the tracked response manifest with:
84
+
85
+ ```bash
86
+ uv run python scripts/audit_quickbase_oas.py --refresh --write
87
+ ```
88
+
89
+ Audit the existing cached document without network access with:
90
+
91
+ ```bash
92
+ uv run python scripts/audit_quickbase_oas.py
93
+ ```
94
+
95
+ Review changes to `docs/api/quickbase-oas-manifest.json` as API contract changes, not generated noise.
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2025 Chris Metcalf
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.