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.
- qbvisor-0.3.0/.env.example +13 -0
- qbvisor-0.3.0/.github/workflows/ci.yml +115 -0
- qbvisor-0.3.0/.github/workflows/pages.yml +73 -0
- qbvisor-0.3.0/.github/workflows/release.yml +76 -0
- qbvisor-0.3.0/.gitignore +41 -0
- qbvisor-0.3.0/CHANGELOG.md +105 -0
- qbvisor-0.3.0/CONTRIBUTING.md +95 -0
- qbvisor-0.3.0/LICENSE.md +7 -0
- qbvisor-0.3.0/PKG-INFO +259 -0
- qbvisor-0.3.0/README.md +231 -0
- qbvisor-0.3.0/SECURITY.md +36 -0
- qbvisor-0.3.0/docs/api/README.md +43 -0
- qbvisor-0.3.0/docs/api/quickbase-oas-manifest.json +1261 -0
- qbvisor-0.3.0/docs/application-building.md +154 -0
- qbvisor-0.3.0/docs/backups-and-attachments.md +147 -0
- qbvisor-0.3.0/docs/configuration.md +104 -0
- qbvisor-0.3.0/docs/data-workflows.md +180 -0
- qbvisor-0.3.0/docs/declarative-schemas.md +206 -0
- qbvisor-0.3.0/docs/index.md +37 -0
- qbvisor-0.3.0/docs/logging-and-errors.md +114 -0
- qbvisor-0.3.0/docs/reference/backups.md +16 -0
- qbvisor-0.3.0/docs/reference/client.md +54 -0
- qbvisor-0.3.0/docs/reference/exceptions.md +23 -0
- qbvisor-0.3.0/docs/reference/index.md +36 -0
- qbvisor-0.3.0/docs/reference/logging.md +11 -0
- qbvisor-0.3.0/docs/reference/queries.md +30 -0
- qbvisor-0.3.0/docs/reference/schemas.md +25 -0
- qbvisor-0.3.0/docs/reference/transport.md +17 -0
- qbvisor-0.3.0/docs/release-policy.md +56 -0
- qbvisor-0.3.0/docs/releases/0.3.0.md +81 -0
- qbvisor-0.3.0/docs/releasing.md +105 -0
- qbvisor-0.3.0/docs/upgrading-to-0.3.md +113 -0
- qbvisor-0.3.0/mkdocs.yml +58 -0
- qbvisor-0.3.0/pyproject.toml +99 -0
- qbvisor-0.3.0/scripts/audit_quickbase_oas.py +345 -0
- qbvisor-0.3.0/scripts/verify_distribution.py +270 -0
- qbvisor-0.3.0/scripts/verify_docs.py +153 -0
- qbvisor-0.3.0/src/qbvisor/__init__.py +141 -0
- qbvisor-0.3.0/src/qbvisor/_attachments.py +83 -0
- qbvisor-0.3.0/src/qbvisor/_backup/__init__.py +23 -0
- qbvisor-0.3.0/src/qbvisor/_backup/attachments.py +303 -0
- qbvisor-0.3.0/src/qbvisor/_backup/reader.py +263 -0
- qbvisor-0.3.0/src/qbvisor/_backup/records.py +83 -0
- qbvisor-0.3.0/src/qbvisor/_backup/schema.py +143 -0
- qbvisor-0.3.0/src/qbvisor/_backup/workflow.py +184 -0
- qbvisor-0.3.0/src/qbvisor/_backup/workspace.py +190 -0
- qbvisor-0.3.0/src/qbvisor/_pagination.py +165 -0
- qbvisor-0.3.0/src/qbvisor/_records/__init__.py +1 -0
- qbvisor-0.3.0/src/qbvisor/_records/pagination.py +186 -0
- qbvisor-0.3.0/src/qbvisor/_records/upsert.py +331 -0
- qbvisor-0.3.0/src/qbvisor/_resources/__init__.py +1 -0
- qbvisor-0.3.0/src/qbvisor/_resources/apps.py +87 -0
- qbvisor-0.3.0/src/qbvisor/_resources/base.py +84 -0
- qbvisor-0.3.0/src/qbvisor/_resources/fields.py +102 -0
- qbvisor-0.3.0/src/qbvisor/_resources/relationships.py +129 -0
- qbvisor-0.3.0/src/qbvisor/_resources/tables.py +93 -0
- qbvisor-0.3.0/src/qbvisor/_schema/__init__.py +1 -0
- qbvisor-0.3.0/src/qbvisor/_schema/apply.py +364 -0
- qbvisor-0.3.0/src/qbvisor/_schema/dependencies.py +122 -0
- qbvisor-0.3.0/src/qbvisor/_schema/planner.py +1191 -0
- qbvisor-0.3.0/src/qbvisor/_schema/relationship_apply.py +327 -0
- qbvisor-0.3.0/src/qbvisor/_schema/state.py +128 -0
- qbvisor-0.3.0/src/qbvisor/_version.py +8 -0
- qbvisor-0.3.0/src/qbvisor/async_transport.py +293 -0
- qbvisor-0.3.0/src/qbvisor/backup.py +436 -0
- qbvisor-0.3.0/src/qbvisor/client.py +1529 -0
- qbvisor-0.3.0/src/qbvisor/exceptions.py +144 -0
- qbvisor-0.3.0/src/qbvisor/helpers.py +51 -0
- qbvisor-0.3.0/src/qbvisor/log_runner.py +166 -0
- qbvisor-0.3.0/src/qbvisor/metadata.py +238 -0
- qbvisor-0.3.0/src/qbvisor/models.py +49 -0
- qbvisor-0.3.0/src/qbvisor/py.typed +1 -0
- qbvisor-0.3.0/src/qbvisor/query_helper.py +192 -0
- qbvisor-0.3.0/src/qbvisor/query_value.py +37 -0
- qbvisor-0.3.0/src/qbvisor/schema.py +845 -0
- qbvisor-0.3.0/src/qbvisor/transport.py +416 -0
- qbvisor-0.3.0/tests/integration/conftest.py +564 -0
- qbvisor-0.3.0/tests/integration/test_sandbox_contract.py +757 -0
- qbvisor-0.3.0/tests/integration/test_schema_integration.py +384 -0
- qbvisor-0.3.0/tests/integration/test_transport_integration.py +32 -0
- qbvisor-0.3.0/tests/test_async_transport.py +228 -0
- qbvisor-0.3.0/tests/test_attachments.py +384 -0
- qbvisor-0.3.0/tests/test_backup_attachments.py +251 -0
- qbvisor-0.3.0/tests/test_backup_models.py +127 -0
- qbvisor-0.3.0/tests/test_backup_records.py +190 -0
- qbvisor-0.3.0/tests/test_backup_schema.py +127 -0
- qbvisor-0.3.0/tests/test_backup_workflow.py +173 -0
- qbvisor-0.3.0/tests/test_client_compatibility.py +1515 -0
- qbvisor-0.3.0/tests/test_client_facade.py +88 -0
- qbvisor-0.3.0/tests/test_exceptions.py +55 -0
- qbvisor-0.3.0/tests/test_metadata.py +106 -0
- qbvisor-0.3.0/tests/test_models.py +21 -0
- qbvisor-0.3.0/tests/test_oas_audit.py +103 -0
- qbvisor-0.3.0/tests/test_pagination.py +133 -0
- qbvisor-0.3.0/tests/test_public_api.py +55 -0
- qbvisor-0.3.0/tests/test_query_helper.py +59 -0
- qbvisor-0.3.0/tests/test_query_value.py +37 -0
- qbvisor-0.3.0/tests/test_record_pagination.py +133 -0
- qbvisor-0.3.0/tests/test_release_validation.py +62 -0
- qbvisor-0.3.0/tests/test_resource_contracts.py +40 -0
- qbvisor-0.3.0/tests/test_schema_apply.py +436 -0
- qbvisor-0.3.0/tests/test_schema_models.py +359 -0
- qbvisor-0.3.0/tests/test_schema_planner.py +774 -0
- qbvisor-0.3.0/tests/test_schema_relationship_apply.py +380 -0
- qbvisor-0.3.0/tests/test_transport.py +316 -0
- qbvisor-0.3.0/tests/test_upsert_batches.py +137 -0
- qbvisor-0.3.0/tests/typing/installed_package.py +6 -0
- 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
|
qbvisor-0.3.0/.gitignore
ADDED
|
@@ -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.
|
qbvisor-0.3.0/LICENSE.md
ADDED
|
@@ -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.
|