openstatspec 0.1.0__tar.gz → 0.2.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.
- openstatspec-0.2.0/.github/verify_release_ref.py +63 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/.github/workflows/ci.yml +77 -1
- {openstatspec-0.1.0 → openstatspec-0.2.0}/.github/workflows/release.yml +30 -11
- openstatspec-0.2.0/CHANGELOG.md +59 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/PKG-INFO +25 -4
- {openstatspec-0.1.0 → openstatspec-0.2.0}/README.md +22 -3
- openstatspec-0.2.0/docs/architecture.md +30 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/docs/release-readiness.md +11 -5
- {openstatspec-0.1.0 → openstatspec-0.2.0}/docs/sav-profile.md +8 -6
- openstatspec-0.2.0/docs/sql-transformation-workflow.md +204 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/pyproject.toml +3 -3
- openstatspec-0.2.0/src/openstatspec/__init__.py +22 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/src/openstatspec/api.py +63 -0
- openstatspec-0.2.0/src/openstatspec/cli.py +130 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/src/openstatspec/spss/raw_dictionary.py +259 -28
- {openstatspec-0.1.0 → openstatspec-0.2.0}/src/openstatspec/spss/sav.py +7 -1
- openstatspec-0.2.0/src/openstatspec/sql/capabilities.py +426 -0
- openstatspec-0.2.0/src/openstatspec/sql/catalog_api.py +163 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/src/openstatspec/sql/normative.py +70 -6
- {openstatspec-0.1.0 → openstatspec-0.2.0}/src/openstatspec/sql/profiles.py +20 -3
- {openstatspec-0.1.0 → openstatspec-0.2.0}/src/openstatspec/sql/wide.py +260 -106
- openstatspec-0.2.0/src/openstatspec/sql/workflow.py +2572 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/tests/conformance.py +19 -6
- openstatspec-0.2.0/tests/test_atomic_import.py +358 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/tests/test_cli.py +2 -2
- {openstatspec-0.1.0 → openstatspec-0.2.0}/tests/test_official_conformance.py +4 -2
- openstatspec-0.2.0/tests/test_release_ref.py +97 -0
- openstatspec-0.2.0/tests/test_sql_profiles.py +423 -0
- openstatspec-0.2.0/tests/test_sql_services.py +326 -0
- openstatspec-0.2.0/tests/test_sql_workflow.py +1737 -0
- openstatspec-0.2.0/tests/test_vls_compatible_names.py +143 -0
- openstatspec-0.1.0/CHANGELOG.md +0 -28
- openstatspec-0.1.0/docs/architecture.md +0 -14
- openstatspec-0.1.0/src/openstatspec/__init__.py +0 -6
- openstatspec-0.1.0/src/openstatspec/cli.py +0 -42
- openstatspec-0.1.0/src/openstatspec/sql/capabilities.py +0 -260
- openstatspec-0.1.0/tests/test_atomic_import.py +0 -115
- openstatspec-0.1.0/tests/test_sql_profiles.py +0 -112
- openstatspec-0.1.0/tests/test_sql_services.py +0 -77
- {openstatspec-0.1.0 → openstatspec-0.2.0}/.gitignore +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/THIRD_PARTY_NOTICES.md +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/docs/pyspssio-spike.md +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/src/openstatspec/core/__init__.py +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/src/openstatspec/core/results.py +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/src/openstatspec/spss/__init__.py +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/src/openstatspec/spss/dictionary.py +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/src/openstatspec/sql/__init__.py +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/tests/test_attribute_catalog.py +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/tests/test_document_round_trip.py +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/tests/test_loss_reports.py +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/tests/test_normative_catalog.py +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/tests/test_pyspssio_catalog_authority.py +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/tests/test_sav_sqlite.py +0 -0
- {openstatspec-0.1.0 → openstatspec-0.2.0}/tests/test_spss_catalog_preflight.py +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Fail closed unless the requested release tag names HEAD and the package version."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
import tomllib
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _git(*arguments: str) -> str:
|
|
13
|
+
completed = subprocess.run(
|
|
14
|
+
["git", *arguments],
|
|
15
|
+
check=False,
|
|
16
|
+
stdout=subprocess.PIPE,
|
|
17
|
+
stderr=subprocess.PIPE,
|
|
18
|
+
text=True,
|
|
19
|
+
)
|
|
20
|
+
if completed.returncode:
|
|
21
|
+
detail = completed.stderr.strip() or completed.stdout.strip()
|
|
22
|
+
raise RuntimeError(detail or f"git {' '.join(arguments)} failed")
|
|
23
|
+
return completed.stdout.strip()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def verify_release_ref() -> None:
|
|
27
|
+
release_tag = os.environ.get("RELEASE_TAG", "")
|
|
28
|
+
version = str(
|
|
29
|
+
tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))["project"]["version"]
|
|
30
|
+
)
|
|
31
|
+
expected_tag = f"v{version}"
|
|
32
|
+
if release_tag != expected_tag:
|
|
33
|
+
raise RuntimeError(
|
|
34
|
+
f"release tag {release_tag!r} does not match package version {version!r}"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
tag_ref = f"refs/tags/{release_tag}"
|
|
38
|
+
exists = subprocess.run(
|
|
39
|
+
["git", "show-ref", "--verify", "--quiet", tag_ref],
|
|
40
|
+
check=False,
|
|
41
|
+
)
|
|
42
|
+
if exists.returncode:
|
|
43
|
+
raise RuntimeError(f"release tag ref {tag_ref!r} does not exist")
|
|
44
|
+
|
|
45
|
+
tag_commit = _git("rev-parse", "--verify", f"{tag_ref}^{{commit}}")
|
|
46
|
+
head_commit = _git("rev-parse", "--verify", "HEAD^{commit}")
|
|
47
|
+
if tag_commit != head_commit:
|
|
48
|
+
raise RuntimeError(
|
|
49
|
+
f"release tag {release_tag!r} resolves to {tag_commit}, not HEAD {head_commit}"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def main() -> int:
|
|
54
|
+
try:
|
|
55
|
+
verify_release_ref()
|
|
56
|
+
except (KeyError, OSError, RuntimeError, tomllib.TOMLDecodeError) as error:
|
|
57
|
+
print(f"release ref verification failed: {error}", file=sys.stderr)
|
|
58
|
+
return 1
|
|
59
|
+
return 0
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
raise SystemExit(main())
|
|
@@ -20,7 +20,7 @@ jobs:
|
|
|
20
20
|
uses: actions/checkout@v7
|
|
21
21
|
with: &specification-checkout
|
|
22
22
|
repository: OpenStatSpec/specification
|
|
23
|
-
ref:
|
|
23
|
+
ref: fef0dc6f4b17ff7141dad3f49d0524c63efbfed5
|
|
24
24
|
path: openstatspec-specification
|
|
25
25
|
- name: Checkout required SPSS engine
|
|
26
26
|
uses: actions/checkout@v7
|
|
@@ -138,3 +138,79 @@ jobs:
|
|
|
138
138
|
env:
|
|
139
139
|
OPENSTATSPEC_MARIADB_URL: mysql+pymysql://openstatspec:openstatspec@localhost:3306/openstatspec
|
|
140
140
|
steps: *sql-test-steps
|
|
141
|
+
|
|
142
|
+
dolt-integration:
|
|
143
|
+
name: Dolt 2.2.2 integration
|
|
144
|
+
runs-on: ubuntu-latest
|
|
145
|
+
env:
|
|
146
|
+
OPENSTATSPEC_DOLT_URL: mysql+pymysql://openstatspec:openstatspec@127.0.0.1:13308/openstatspec
|
|
147
|
+
steps:
|
|
148
|
+
- uses: actions/checkout@v7
|
|
149
|
+
- name: Checkout OpenStatSpec specification fixtures
|
|
150
|
+
uses: actions/checkout@v7
|
|
151
|
+
with: *specification-checkout
|
|
152
|
+
- name: Checkout required SPSS engine
|
|
153
|
+
uses: actions/checkout@v7
|
|
154
|
+
with: *engine-checkout
|
|
155
|
+
- uses: actions/setup-python@v7
|
|
156
|
+
with:
|
|
157
|
+
python-version: "3.12"
|
|
158
|
+
- name: Initialize Dolt 2.2.2
|
|
159
|
+
run: |
|
|
160
|
+
mkdir -p "$RUNNER_TEMP/openstatspec-dolt"
|
|
161
|
+
docker run --rm \
|
|
162
|
+
--volume "$RUNNER_TEMP/openstatspec-dolt:/var/lib/dolt" \
|
|
163
|
+
--workdir /var/lib/dolt \
|
|
164
|
+
dolthub/dolt:2.2.2 init \
|
|
165
|
+
--name "OpenStatSpec CI" --email "ci@openstatspec.org"
|
|
166
|
+
docker run --rm \
|
|
167
|
+
--volume "$RUNNER_TEMP/openstatspec-dolt:/var/lib/dolt" \
|
|
168
|
+
--workdir /var/lib/dolt \
|
|
169
|
+
dolthub/dolt:2.2.2 sql \
|
|
170
|
+
-q "CREATE DATABASE openstatspec"
|
|
171
|
+
docker run --rm \
|
|
172
|
+
--volume "$RUNNER_TEMP/openstatspec-dolt:/var/lib/dolt" \
|
|
173
|
+
--workdir /var/lib/dolt \
|
|
174
|
+
dolthub/dolt:2.2.2 sql \
|
|
175
|
+
-q "CREATE USER 'openstatspec'@'%' IDENTIFIED BY 'openstatspec'; GRANT ALL PRIVILEGES ON openstatspec.* TO 'openstatspec'@'%'"
|
|
176
|
+
docker run --detach --name openstatspec-dolt \
|
|
177
|
+
--publish 127.0.0.1:13308:3306 \
|
|
178
|
+
--volume "$RUNNER_TEMP/openstatspec-dolt:/var/lib/dolt" \
|
|
179
|
+
--workdir /var/lib/dolt \
|
|
180
|
+
dolthub/dolt:2.2.2 sql-server -H 0.0.0.0 -l warning
|
|
181
|
+
- run: python -m pip install --upgrade pip
|
|
182
|
+
- run: python -m pip install ./openstatspec-pyspssio
|
|
183
|
+
- run: python -m pip install -e ".[dev,sql]"
|
|
184
|
+
- name: Wait for Dolt
|
|
185
|
+
run: |
|
|
186
|
+
python - <<'PY'
|
|
187
|
+
import time
|
|
188
|
+
import pymysql
|
|
189
|
+
|
|
190
|
+
for attempt in range(30):
|
|
191
|
+
try:
|
|
192
|
+
connection = pymysql.connect(
|
|
193
|
+
host="127.0.0.1",
|
|
194
|
+
port=13308,
|
|
195
|
+
user="openstatspec",
|
|
196
|
+
password="openstatspec",
|
|
197
|
+
database="openstatspec",
|
|
198
|
+
)
|
|
199
|
+
except pymysql.MySQLError:
|
|
200
|
+
if attempt == 29:
|
|
201
|
+
raise
|
|
202
|
+
time.sleep(2)
|
|
203
|
+
else:
|
|
204
|
+
connection.close()
|
|
205
|
+
break
|
|
206
|
+
PY
|
|
207
|
+
- run: python -m pytest -m services
|
|
208
|
+
- name: Show Dolt logs on failure and stop server
|
|
209
|
+
if: always()
|
|
210
|
+
run: |
|
|
211
|
+
if docker inspect openstatspec-dolt >/dev/null 2>&1; then
|
|
212
|
+
if [ "${{ job.status }}" != "success" ]; then
|
|
213
|
+
docker logs openstatspec-dolt
|
|
214
|
+
fi
|
|
215
|
+
docker rm --force openstatspec-dolt
|
|
216
|
+
fi
|
|
@@ -7,6 +7,12 @@ on:
|
|
|
7
7
|
push:
|
|
8
8
|
tags:
|
|
9
9
|
- "v*"
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
inputs:
|
|
12
|
+
release_ref:
|
|
13
|
+
description: "Existing release tag to rebuild and publish idempotently"
|
|
14
|
+
required: true
|
|
15
|
+
type: string
|
|
10
16
|
|
|
11
17
|
permissions:
|
|
12
18
|
contents: read
|
|
@@ -16,11 +22,32 @@ jobs:
|
|
|
16
22
|
runs-on: ubuntu-latest
|
|
17
23
|
steps:
|
|
18
24
|
- uses: actions/checkout@v7
|
|
25
|
+
with:
|
|
26
|
+
ref: refs/tags/${{ inputs.release_ref || github.ref_name }}
|
|
27
|
+
fetch-depth: 0
|
|
28
|
+
- uses: actions/setup-python@v7
|
|
29
|
+
with:
|
|
30
|
+
python-version: "3.13"
|
|
31
|
+
- name: Verify release tag exists and targets this package version
|
|
32
|
+
env:
|
|
33
|
+
RELEASE_TAG: ${{ inputs.release_ref || github.ref_name }}
|
|
34
|
+
run: |
|
|
35
|
+
set -eu
|
|
36
|
+
git fetch --force --no-tags origin "refs/tags/${RELEASE_TAG}:refs/tags/${RELEASE_TAG}"
|
|
37
|
+
python .github/verify_release_ref.py
|
|
38
|
+
- run: python -m pip install --upgrade pip build
|
|
39
|
+
- name: Verify required SPSS engine is publicly installable
|
|
40
|
+
run: >-
|
|
41
|
+
python -m pip download --only-binary=:all: --no-deps
|
|
42
|
+
--dest /tmp/openstatspec-engine-release
|
|
43
|
+
openstatspec-pyspssio==0.5.1.post2
|
|
44
|
+
- name: Build clean release distributions
|
|
45
|
+
run: python -m build
|
|
19
46
|
- name: Checkout normative specification fixtures
|
|
20
47
|
uses: actions/checkout@v7
|
|
21
48
|
with:
|
|
22
49
|
repository: OpenStatSpec/specification
|
|
23
|
-
ref:
|
|
50
|
+
ref: fef0dc6f4b17ff7141dad3f49d0524c63efbfed5
|
|
24
51
|
path: openstatspec-specification
|
|
25
52
|
- name: Checkout required SPSS engine
|
|
26
53
|
uses: actions/checkout@v7
|
|
@@ -28,19 +55,9 @@ jobs:
|
|
|
28
55
|
repository: TonisOrmisson/pyspssio
|
|
29
56
|
ref: e069adf33c70bcd9e8e6ee495106479463a84fa2
|
|
30
57
|
path: openstatspec-pyspssio
|
|
31
|
-
- uses: actions/setup-python@v7
|
|
32
|
-
with:
|
|
33
|
-
python-version: "3.13"
|
|
34
|
-
- run: python -m pip install --upgrade pip build
|
|
35
|
-
- name: Verify required SPSS engine is publicly installable
|
|
36
|
-
run: >-
|
|
37
|
-
python -m pip download --only-binary=:all: --no-deps
|
|
38
|
-
--dest /tmp/openstatspec-engine-release
|
|
39
|
-
openstatspec-pyspssio==0.5.1.post2
|
|
40
58
|
- run: python -m pip install ./openstatspec-pyspssio
|
|
41
59
|
- run: python -m pip install -e ".[dev]"
|
|
42
60
|
- run: python -m pytest -m "not services"
|
|
43
|
-
- run: python -m build
|
|
44
61
|
- run: python -m venv /tmp/openstatspec-release-smoke
|
|
45
62
|
- run: /tmp/openstatspec-release-smoke/bin/python -m pip install ./openstatspec-pyspssio
|
|
46
63
|
- run: /tmp/openstatspec-release-smoke/bin/python -m pip install dist/*.whl
|
|
@@ -64,3 +81,5 @@ jobs:
|
|
|
64
81
|
name: python-distributions
|
|
65
82
|
path: dist/
|
|
66
83
|
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
84
|
+
with:
|
|
85
|
+
skip-existing: true
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this reference implementation are documented here.
|
|
4
|
+
|
|
5
|
+
## 0.2.0 — 2026-07-30
|
|
6
|
+
|
|
7
|
+
This release extends the reference adapter while keeping imported source
|
|
8
|
+
datasets immutable and all unsupported paths fail-closed.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- An optional SQLite-only Transformation Workflow for immutable, versioned,
|
|
13
|
+
parameterized SELECT definitions; materialized derived datasets; lineage and
|
|
14
|
+
weights; public catalog APIs; and CLI operations.
|
|
15
|
+
- An independent Dolt core SQL profile for exact product version 2.2.2, with
|
|
16
|
+
service-backed coverage, conservative adapter limits, complete compensating
|
|
17
|
+
cleanup, and pre-DDL rejection of unsupported values. Transformation Workflow
|
|
18
|
+
support on Dolt is not claimed.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- SAV and ZSAV validation now rewrites legacy compatible names consistently
|
|
23
|
+
across type-2 records and subtype-13/subtype-14 long-name metadata.
|
|
24
|
+
- Transformation publication, interrupted-run reconciliation, retirement, and
|
|
25
|
+
physical-removal recovery now preserve auditable state and fail closed on
|
|
26
|
+
catalog or relation drift.
|
|
27
|
+
- Release automation builds distributions before test-only source checkouts and
|
|
28
|
+
supports idempotent rebuilds of an existing release tag.
|
|
29
|
+
|
|
30
|
+
### Specification basis
|
|
31
|
+
|
|
32
|
+
- CI and release validation are pinned to OpenStatSpec specification release
|
|
33
|
+
`v1.0.0-rc.1` at exact commit
|
|
34
|
+
`fef0dc6f4b17ff7141dad3f49d0524c63efbfed5`.
|
|
35
|
+
|
|
36
|
+
## 0.1.0 — 2026-07-29
|
|
37
|
+
|
|
38
|
+
First public reference implementation of the OpenStatSpec strict wide-table
|
|
39
|
+
SPSS profile.
|
|
40
|
+
|
|
41
|
+
### Included
|
|
42
|
+
|
|
43
|
+
- Import of unencrypted SAV and ZSAV sources into one dedicated wide SQL table
|
|
44
|
+
and its metadata catalog.
|
|
45
|
+
- Export of supported dataset semantics to SAV and ZSAV.
|
|
46
|
+
- SQLite, PostgreSQL, MySQL, and MariaDB profiles, including service-backed
|
|
47
|
+
PostgreSQL 17/18, MySQL 8.4/9.7, and MariaDB 11.4/11.8/12.3 CI coverage.
|
|
48
|
+
- Preflight checks for target profile limits, atomic imports, validation, a
|
|
49
|
+
command-line interface, and machine-readable capability and loss reports.
|
|
50
|
+
|
|
51
|
+
### Important boundaries
|
|
52
|
+
|
|
53
|
+
- This release promises semantic round-trip equivalence only for supported
|
|
54
|
+
features; it never promises byte-identical SAV/ZSAV output.
|
|
55
|
+
- The adapter requires explicit `allow_loss` consent before exporting known
|
|
56
|
+
unsupported or lossy dictionary semantics.
|
|
57
|
+
- Multiple-response sets, variable alignment, variable sets, and custom
|
|
58
|
+
attributes have explicit capability diagnostics; see the SAV profile.
|
|
59
|
+
- Encrypted SPSS files are not supported.
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openstatspec
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Reference adapter for the OpenStatSpec relational contract
|
|
5
5
|
Author: OpenStatSpec
|
|
6
6
|
License: Apache-2.0
|
|
7
7
|
Requires-Python: >=3.11
|
|
8
8
|
Requires-Dist: openstatspec-pyspssio==0.5.1.post2
|
|
9
9
|
Requires-Dist: pandas>=2.2
|
|
10
|
+
Requires-Dist: rfc8785>=0.1.4
|
|
10
11
|
Requires-Dist: sqlalchemy>=2.0
|
|
12
|
+
Requires-Dist: sqlglot>=30.14
|
|
11
13
|
Provides-Extra: dev
|
|
12
14
|
Requires-Dist: pytest>=8; extra == 'dev'
|
|
13
15
|
Provides-Extra: sql
|
|
@@ -58,19 +60,38 @@ openstatspec import responses.sav --database-url postgresql+psycopg://... --data
|
|
|
58
60
|
openstatspec export --database-url postgresql+psycopg://... --dataset-id responses-2026 --output responses-roundtrip.sav
|
|
59
61
|
```
|
|
60
62
|
|
|
61
|
-
##
|
|
63
|
+
## Optional database-first SQL workflow
|
|
64
|
+
|
|
65
|
+
Imported datasets remain immutable source records. The optional SQL
|
|
66
|
+
transformation profile can register versioned, parameterized SQLite SELECT queries,
|
|
67
|
+
materialize results, record lineage and weights, and expose
|
|
68
|
+
derived datasets through a public catalog API. It uses a separate profile
|
|
69
|
+
catalog and never presents SQL output as an imported source dataset.
|
|
70
|
+
Workflow operations support SQLite only in this milestone and fail closed on
|
|
71
|
+
PostgreSQL/MySQL/MariaDB; core import/export database support is unchanged.
|
|
72
|
+
|
|
73
|
+
See [the SQL transformation workflow](docs/sql-transformation-workflow.md) for
|
|
74
|
+
Python and CLI examples, migration behavior, hashing, atomicity, and the exact
|
|
75
|
+
implemented capability boundary.
|
|
76
|
+
|
|
77
|
+
## 0.2.0 support status
|
|
62
78
|
|
|
63
79
|
The adapter requires `openstatspec-pyspssio==0.5.1.post2` as its sole SPSS
|
|
64
80
|
engine. Its import module remains `pyspssio`; the exact source commit is recorded
|
|
65
81
|
in operation metadata. There is no fallback reader or writer. It supports unencrypted SAV and ZSAV import and
|
|
66
82
|
SAV/ZSAV export for the semantics exposed by that engine. SQLite is the local
|
|
67
83
|
reference path.
|
|
68
|
-
PostgreSQL, MySQL, and
|
|
69
|
-
conformance checks.
|
|
84
|
+
PostgreSQL, MySQL, MariaDB, and Dolt are each covered by separate service-backed CI
|
|
85
|
+
conformance checks. Dolt support is an independent core profile pinned to 2.2.2;
|
|
86
|
+
other Dolt versions and unknown MySQL-wire products fail closed. Use these explicit SQLAlchemy URLs:
|
|
70
87
|
|
|
71
88
|
- SQLite: `sqlite:///dataset.sqlite`
|
|
72
89
|
- PostgreSQL: `postgresql+psycopg://user:password@host/database`
|
|
73
90
|
- MySQL/MariaDB: `mysql+pymysql://user:password@host/database`
|
|
91
|
+
- Dolt 2.2.2: `mysql+pymysql://user:password@host/database` (detected by server identity)
|
|
92
|
+
|
|
93
|
+
The Dolt core profile supports strict wide-table import, validation, and export;
|
|
94
|
+
the separate Transformation Workflow is unsupported.
|
|
74
95
|
|
|
75
96
|
Run `openstatspec capabilities` before an integration to inspect the
|
|
76
97
|
machine-readable feature matrix. Export is deliberately strict: if known
|
|
@@ -41,19 +41,38 @@ openstatspec import responses.sav --database-url postgresql+psycopg://... --data
|
|
|
41
41
|
openstatspec export --database-url postgresql+psycopg://... --dataset-id responses-2026 --output responses-roundtrip.sav
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Optional database-first SQL workflow
|
|
45
|
+
|
|
46
|
+
Imported datasets remain immutable source records. The optional SQL
|
|
47
|
+
transformation profile can register versioned, parameterized SQLite SELECT queries,
|
|
48
|
+
materialize results, record lineage and weights, and expose
|
|
49
|
+
derived datasets through a public catalog API. It uses a separate profile
|
|
50
|
+
catalog and never presents SQL output as an imported source dataset.
|
|
51
|
+
Workflow operations support SQLite only in this milestone and fail closed on
|
|
52
|
+
PostgreSQL/MySQL/MariaDB; core import/export database support is unchanged.
|
|
53
|
+
|
|
54
|
+
See [the SQL transformation workflow](docs/sql-transformation-workflow.md) for
|
|
55
|
+
Python and CLI examples, migration behavior, hashing, atomicity, and the exact
|
|
56
|
+
implemented capability boundary.
|
|
57
|
+
|
|
58
|
+
## 0.2.0 support status
|
|
45
59
|
|
|
46
60
|
The adapter requires `openstatspec-pyspssio==0.5.1.post2` as its sole SPSS
|
|
47
61
|
engine. Its import module remains `pyspssio`; the exact source commit is recorded
|
|
48
62
|
in operation metadata. There is no fallback reader or writer. It supports unencrypted SAV and ZSAV import and
|
|
49
63
|
SAV/ZSAV export for the semantics exposed by that engine. SQLite is the local
|
|
50
64
|
reference path.
|
|
51
|
-
PostgreSQL, MySQL, and
|
|
52
|
-
conformance checks.
|
|
65
|
+
PostgreSQL, MySQL, MariaDB, and Dolt are each covered by separate service-backed CI
|
|
66
|
+
conformance checks. Dolt support is an independent core profile pinned to 2.2.2;
|
|
67
|
+
other Dolt versions and unknown MySQL-wire products fail closed. Use these explicit SQLAlchemy URLs:
|
|
53
68
|
|
|
54
69
|
- SQLite: `sqlite:///dataset.sqlite`
|
|
55
70
|
- PostgreSQL: `postgresql+psycopg://user:password@host/database`
|
|
56
71
|
- MySQL/MariaDB: `mysql+pymysql://user:password@host/database`
|
|
72
|
+
- Dolt 2.2.2: `mysql+pymysql://user:password@host/database` (detected by server identity)
|
|
73
|
+
|
|
74
|
+
The Dolt core profile supports strict wide-table import, validation, and export;
|
|
75
|
+
the separate Transformation Workflow is unsupported.
|
|
57
76
|
|
|
58
77
|
Run `openstatspec capabilities` before an integration to inspect the
|
|
59
78
|
machine-readable feature matrix. Export is deliberately strict: if known
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
`openstatspec.core` contains only pure concepts defined by the standard:
|
|
4
|
+
versioning, validation concepts, capability declarations, and loss reports.
|
|
5
|
+
`openstatspec.sql` owns database-target and strict wide-table/catalog work.
|
|
6
|
+
`openstatspec.spss` owns SAV/ZSAV source and export behavior.
|
|
7
|
+
|
|
8
|
+
The public workflow remains database-connected. A supported import receives an
|
|
9
|
+
SPSS source, a database URL or connection, and a dataset identity. It creates
|
|
10
|
+
one dedicated wide data table plus separate catalog metadata. Export identifies
|
|
11
|
+
the database dataset and writes a supported SPSS file.
|
|
12
|
+
|
|
13
|
+
No layer may silently substitute EAV, long-form views, JSON, pivots, automatic
|
|
14
|
+
harmonization, truncation, or partial import for the standard's strict mapping.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Optional SQL transformation profile
|
|
18
|
+
|
|
19
|
+
`openstatspec.sql.workflow` layers a separate, independently identified
|
|
20
|
+
catalog beside the core contract. It owns immutable transformation
|
|
21
|
+
definitions/versions, driver-bound runs, input snapshots, derived relations,
|
|
22
|
+
variables, lineage, weights, safe events, and append-only disposition events.
|
|
23
|
+
Its executable backend is SQLite only: foreign keys, transactional staging,
|
|
24
|
+
scope-aware AST validation, and the SQLite authorizer form one tested security
|
|
25
|
+
and atomicity boundary. Other core database profiles do not imply workflow
|
|
26
|
+
support.
|
|
27
|
+
It may read validated core or published derived datasets but never writes a SQL
|
|
28
|
+
result into the source-faithful core `dataset` relation. Read-only discovery
|
|
29
|
+
is provided by `openstatspec.sql.catalog_api`; historical `*_catalog`
|
|
30
|
+
relations remain private compatibility state.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# 0.
|
|
1
|
+
# 0.2.0 release readiness
|
|
2
2
|
|
|
3
3
|
This page records the expected release contract, not a publication event.
|
|
4
4
|
Creating a version tag remains a separate maintainer action.
|
|
@@ -20,9 +20,12 @@ database contract.
|
|
|
20
20
|
| PostgreSQL | `postgresql+psycopg://…` | PostgreSQL 17 and 18 service jobs |
|
|
21
21
|
| MySQL | `mysql+pymysql://…` | MySQL 8.4 and 9.7 service jobs |
|
|
22
22
|
| MariaDB | `mysql+pymysql://…` | MariaDB 11.4, 11.8, and 12.3 service jobs |
|
|
23
|
+
| Dolt | `mysql+pymysql://…` | Exact Dolt 2.2.2 service job |
|
|
23
24
|
|
|
24
25
|
Separate service matrices test the shared MySQL/MariaDB profile contract while
|
|
25
|
-
retaining distinct active-server identities and version claims.
|
|
26
|
+
retaining distinct active-server identities and version claims. Dolt is an
|
|
27
|
+
independent core profile that fails closed unless the product version is exactly
|
|
28
|
+
2.2.2; the optional Transformation Workflow remains SQLite-only. This does not
|
|
26
29
|
claim coverage for every server configuration. The machine-readable capability
|
|
27
30
|
declaration reports both the theoretical profile boundaries and effective
|
|
28
31
|
limits observed from the active connection.
|
|
@@ -49,13 +52,16 @@ machine-readable loss report with the export result.
|
|
|
49
52
|
1. Publish the pinned `openstatspec-pyspssio==0.5.1.post2` engine distribution
|
|
50
53
|
first and confirm that a clean environment can download it from PyPI. The
|
|
51
54
|
main package has no fallback SPSS engine.
|
|
52
|
-
2. Run `python -m pytest`.
|
|
55
|
+
2. Run `python -m pytest -m "not services"`.
|
|
53
56
|
3. Confirm the GitHub Actions matrix is green for PostgreSQL 17/18, MySQL
|
|
54
|
-
8.4/9.7,
|
|
57
|
+
8.4/9.7, MariaDB 11.4/11.8/12.3, and exact Dolt 2.2.2.
|
|
55
58
|
4. Build with `python -m build` and install the generated wheel in a clean
|
|
56
59
|
environment.
|
|
57
60
|
5. Confirm `openstatspec capabilities` reflects the intended support boundary.
|
|
58
|
-
6.
|
|
61
|
+
6. Confirm the `v0.2.0` tag matches package version `0.2.0`, and that CI and
|
|
62
|
+
release fixtures use specification release `v1.0.0-rc.1` at exact commit
|
|
63
|
+
`fef0dc6f4b17ff7141dad3f49d0524c63efbfed5`.
|
|
64
|
+
7. Review this document, the README, and CHANGELOG for accurate scope.
|
|
59
65
|
|
|
60
66
|
The tag-triggered release workflow repeats the non-service test suite, builds
|
|
61
67
|
the distributions, and installs the wheel with the exact required SPSS engine
|
|
@@ -13,12 +13,14 @@ unencrypted .sav and .zsav files, and writes both formats through the same imple
|
|
|
13
13
|
|
|
14
14
|
## Verified SQL profiles
|
|
15
15
|
|
|
16
|
-
SQLite has a local reference fixture. PostgreSQL, MySQL, and
|
|
16
|
+
SQLite has a local reference fixture. PostgreSQL, MySQL, MariaDB, and Dolt have
|
|
17
17
|
separate service-backed conformance checks in GitHub Actions that import,
|
|
18
|
-
validate, and export the supported fixture.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
validate, and export the supported fixture. Dolt is an independent core profile
|
|
19
|
+
pinned to exact server version 2.2.2 and detected over `mysql+pymysql` by active
|
|
20
|
+
server identity; other Dolt versions and unknown MySQL-wire products fail closed.
|
|
21
|
+
The core Dolt profile does not claim support for the separate Transformation
|
|
22
|
+
Workflow. An import that exceeds a target's strict single-table column or row
|
|
23
|
+
envelope fails before it creates a dataset.
|
|
22
24
|
|
|
23
25
|
## Fidelity contract
|
|
24
26
|
|
|
@@ -41,7 +43,7 @@ of this boundary. It records the pinned source commit and installed engine versi
|
|
|
41
43
|
| Ordered document text | Supported through a strict type-6 dictionary bridge plus the pinned fork | Import stores normalized document rows; export creates a temporary UTF-8 SAV source and has IBM I/O copy the records into SAV or ZSAV without invalidating ZSAV dictionary offsets. |
|
|
42
44
|
| Print and write formats independently | Supported as raw IBM I/O tuples | The adapter stores both tuples separately and writes them without collapsing either value. |
|
|
43
45
|
| Variable sets | Supported through raw IBM I/O | The adapter stores source sets in the extension catalog and writes them through the raw dictionary setter. Invalid target definitions fail before data are written. |
|
|
44
|
-
| Legacy compatible variable names | Supported through the strict dictionary bridge | The adapter
|
|
46
|
+
| Legacy compatible variable names | Supported through the strict dictionary bridge | The adapter atomically rewrites and reparses type-2, subtype-13, and VLS subtype-14 names as one consistent SAV/ZSAV dictionary; malformed or duplicate subtype-14 entries fail closed. |
|
|
45
47
|
| Source encoding | UTF-8 by default; legacy code page with an explicit OS locale | The caller supplies legacy_locale and the writer verifies that the emitted encoding matches the stored source encoding. Without it, export fails before output creation. |
|
|
46
48
|
| Custom attributes with one value | Supported | File and variable scalar attributes round trip through the normalized attribute catalog. |
|
|
47
49
|
| Custom-attribute value arrays | Supported through raw IBM I/O | The adapter represents an array as IBM SPSS `Name[1]`, `Name[2]`, … members and reconstructs the ordered array in the normalized catalog. |
|