Skip to content

Commit b5d0d67

Browse files
committed
Add fail-closed Dolt 2.2.2 support
1 parent 88b9284 commit b5d0d67

14 files changed

Lines changed: 1309 additions & 186 deletions

‎.github/workflows/ci.yml‎

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,79 @@ jobs:
138138
env:
139139
OPENSTATSPEC_MARIADB_URL: mysql+pymysql://openstatspec:openstatspec@localhost:3306/openstatspec
140140
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

‎CHANGELOG.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ SPSS profile.
1414
- Export of supported dataset semantics to SAV and ZSAV.
1515
- Consistent legacy compatible-name rewriting across type-2, subtype-13, and
1616
VLS subtype-14 records, with fail-closed SAV/ZSAV validation.
17-
- SQLite, PostgreSQL, MySQL, and MariaDB profiles, including service-backed
18-
PostgreSQL 17/18, MySQL 8.4/9.7, and MariaDB 11.4/11.8/12.3 CI coverage.
17+
- SQLite, PostgreSQL, MySQL, MariaDB, and independent Dolt profiles, including
18+
service-backed PostgreSQL 17/18, MySQL 8.4/9.7, MariaDB 11.4/11.8/12.3, and
19+
pinned Dolt 2.2.2 CI coverage. Dolt Transformation Workflow support is not claimed.
1920
- Preflight checks for target profile limits, atomic imports, validation, a
2021
command-line interface, and machine-readable capability and loss reports.
2122

‎README.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,17 @@ engine. Its import module remains `pyspssio`; the exact source commit is recorde
6262
in operation metadata. There is no fallback reader or writer. It supports unencrypted SAV and ZSAV import and
6363
SAV/ZSAV export for the semantics exposed by that engine. SQLite is the local
6464
reference path.
65-
PostgreSQL, MySQL, and MariaDB are each covered by separate service-backed CI
66-
conformance checks. Use these explicit SQLAlchemy URLs:
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:
6768

6869
- SQLite: `sqlite:///dataset.sqlite`
6970
- PostgreSQL: `postgresql+psycopg://user:password@host/database`
7071
- 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.
7176

7277
Run `openstatspec capabilities` before an integration to inspect the
7378
machine-readable feature matrix. Export is deliberately strict: if known

‎docs/sav-profile.md‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ unencrypted .sav and .zsav files, and writes both formats through the same imple
1313

1414
## Verified SQL profiles
1515

16-
SQLite has a local reference fixture. PostgreSQL, MySQL, and MariaDB have
16+
SQLite has a local reference fixture. PostgreSQL, MySQL, MariaDB, and Dolt have
1717
separate service-backed conformance checks in GitHub Actions that import,
18-
validate, and export the supported fixture. MySQL 8.4 and MariaDB 11.4 exercise
19-
the shared profile contract; this does not claim coverage for every server
20-
configuration. An import that exceeds a target's strict single-table column
21-
limit fails before it creates a dataset.
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.
2224

2325
## Fidelity contract
2426

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ openstatspec = "openstatspec.cli:main"
2222
[tool.pytest.ini_options]
2323
testpaths = ["tests"]
2424
addopts = "-q"
25-
markers = ["services: requires a configured PostgreSQL or MySQL/MariaDB service"]
25+
markers = ["services: requires a configured PostgreSQL, MySQL, MariaDB, or Dolt service"]
2626

2727
[tool.hatch.build.targets.wheel]
2828
packages = ["src/openstatspec"]

‎src/openstatspec/spss/sav.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
variable_attribute_pairs,
3939
)
4040
from ..core import UnsupportedOperationError
41+
from ..sql.capabilities import effective_profile
42+
from ..sql.profiles import preflight
4143
from ..sql.wide import (
4244
create_wide_dataset,
4345
physical_name,
@@ -262,7 +264,11 @@ def export_sav_dataset(
262264
destination_path = Path(destination)
263265
if destination_path.suffix.lower() not in {".sav", ".zsav"}:
264266
raise UnsupportedOperationError("Export destinations must use the .sav or .zsav extension.")
265-
dataset, variables, rows = read_wide_dataset(database_url=database_url, dataset_id=dataset_id)
267+
profile, _active = effective_profile(database_url)
268+
dataset, variables, rows = read_wide_dataset(
269+
database_url=database_url, dataset_id=dataset_id, profile=profile,
270+
)
271+
preflight(profile, variables, rows=rows)
266272
validate_spss_catalog(
267273
variables,
268274
case_weight_variable=dataset.get("case_weight_variable"),

0 commit comments

Comments
 (0)