Skip to content

Commit 41e39df

Browse files
committed
Require pyspssio as Python SPSS engine
1 parent 423a976 commit 41e39df

5 files changed

Lines changed: 91 additions & 82 deletions

File tree

‎README.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ openstatspec export --database-url postgresql+psycopg://... --dataset-id respons
3939

4040
## 0.1.0 support status
4141

42-
The adapter supports unencrypted SAV and ZSAV import and SAV/ZSAV export for
43-
the semantics exposed by its SPSS engine. SQLite is the local reference path.
42+
The adapter requires pyspssio 0.5.1 as its sole SPSS engine. There is no
43+
fallback reader or writer. It supports unencrypted SAV and ZSAV import and
44+
SAV/ZSAV export for the semantics exposed by that engine. SQLite is the local
45+
reference path.
4446
PostgreSQL, MySQL, and MariaDB are each covered by separate service-backed CI
4547
conformance checks. Use these explicit SQLAlchemy URLs:
4648

@@ -56,3 +58,6 @@ intentional lossy export auditable.
5658

5759
See [the SAV profile](docs/sav-profile.md) for feature boundaries and
5860
[release readiness](docs/release-readiness.md) for the pre-tag checklist.
61+
Read [third-party notices](THIRD_PARTY_NOTICES.md) before distributing a
62+
bundled application: the required engine includes IBM redistributables under
63+
separate terms.

‎THIRD_PARTY_NOTICES.md‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Third-party notices
2+
3+
OpenStatSpec Python source code is licensed under Apache-2.0. Its required
4+
SPSS engine is a separate third-party distribution:
5+
6+
| Component | Version | Applicable terms |
7+
| --- | --- | --- |
8+
| pyspssio | 0.5.1 | MIT for the Python wrapper, except for its IBM I/O Module files |
9+
| IBM I/O Modules for IBM SPSS Statistics Data Files | 28.0.1.0, bundled by pyspssio | IBM International License Agreement for Non-Warranted Programs and the accompanying License Information / REDIST files |
10+
11+
pyspssio ships the IBM licence, redistribution list, and third-party notices
12+
inside its installed distribution, normally under pyspssio/spssio/license/.
13+
Those materials are authoritative. They are not relicensed by this repository's
14+
Apache-2.0 licence.
15+
16+
## Distribution responsibility
17+
18+
OpenStatSpec requires pyspssio==0.5.1; it has no alternate SPSS engine. This
19+
repository does not vendor, alter, or publish the IBM binaries. Anyone who
20+
distributes an application bundle containing the installed engine must review
21+
and comply with the IBM materials supplied with that engine. In particular, the
22+
IBM redistribution conditions require object-code-only distribution as part of
23+
the distributor's application, preservation of notices, restrictions on use
24+
and onward distribution, and end-user terms that protect IBM at least as much
25+
as the IBM agreement. They also include other conditions, including support,
26+
indemnity, and trademark restrictions.
27+
28+
Do not remove the pyspssio licence directory or notices from a bundled
29+
installation. Do not describe IBM or its trademarks as endorsing OpenStatSpec.
30+
31+
This is a factual third-party notice, not legal advice. A party preparing a
32+
binary or application distribution should have its own legal review of the
33+
exact LA_en, REDIST, and notices files installed with the selected pyspssio
34+
release.

‎docs/pyspssio-spike.md‎

Lines changed: 25 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
1-
# `pyspssio` engine spike
1+
# pyspssio engine assessment
22

3-
**Status:** investigated only; not a runtime dependency and not selected by the
4-
public adapter.
3+
**Status:** selected as the required, sole Python SPSS engine.
54

6-
This is a bounded technical spike for evaluating
7-
[`pyspssio`](https://pypi.org/project/pyspssio/) 0.5.1 as a future SPSS
8-
engine. The existing `pyreadstat` engine remains unchanged.
5+
OpenStatSpec Python uses [pyspssio](https://pypi.org/project/pyspssio/) 0.5.1
6+
for both SAV and ZSAV import and export. There is no alternate SPSS engine.
97

10-
## Environment and runtime result
8+
## Probe result
119

12-
The probe used Python 3.12 and `pyspssio==0.5.1` in a local development
13-
virtual environment. The wheel includes IBM SPSS I/O Modules 28.0.1.0 native
14-
libraries for Linux, macOS and Windows. No installed IBM SPSS Statistics
15-
application was needed for the probe.
16-
17-
A local round trip created both a `.sav` and a `.zsav`, then read each
18-
back. The following metadata survived in both files:
10+
A local round trip created both .sav and .zsav, then read each back. The
11+
following metadata survived in the probe:
1912

2013
- UTF-8 encoding, variable names and storage widths;
2114
- variable and value labels;
@@ -25,51 +18,27 @@ back. The following metadata survived in both files:
2518
- case-weight variable;
2619
- a dichotomous multiple-response set.
2720

28-
The public API used was `read_metadata()`, `read_sav()` and
29-
`write_sav()`; it supports both `.sav` and `.zsav` according to the
30-
suffix.
31-
32-
## Material limitations found
33-
34-
This is not yet a complete-fidelity engine.
35-
36-
1. **Variable sets did not round trip.** A `var_sets` definition supplied to
37-
`write_sav()` was absent from the metadata read back. The upstream source
38-
itself notes a dictionary-commit / 8-byte-compatible-name limitation for
39-
variable sets.
40-
2. **Print and write formats are not independently represented by the public
41-
API.** `Header.var_formats` reads the print format; its setter calls both
42-
`spssSetVarPrintFormat` and `spssSetVarWriteFormat` with the same value.
43-
An OpenStatSpec exporter must retain and restore the two formats separately.
44-
3. **No public document-text or file-label property was found** in
45-
`Header`. These must be added upstream or accessed through a supported
46-
lower-level binding before this engine can satisfy the full profile.
47-
4. The functional probe covers one modern Unicode file. It does not establish
48-
compatibility for legacy code-page SAV files, long-string edge cases, or
49-
arbitrary pre-existing SPSS files.
50-
51-
## License and CI boundary
21+
The public API used was read_metadata(), read_sav(), and write_sav().
5222

53-
The Python wrapper is MIT, but its wheel contains IBM I/O Modules under a
54-
separate IBM licence. In particular, the accompanying redistribution terms
55-
apply to the bundled native libraries and are not covered by this repository's
56-
Apache-2.0 licence.
23+
## Required conformance work
5724

58-
Therefore this spike intentionally:
25+
This engine selection does not relax the OpenStatSpec profile. Every claimed
26+
feature must have a hermetic round-trip fixture. Current engine/API questions
27+
that require explicit tests or upstream work include:
5928

60-
- does **not** add `pyspssio` to project dependencies;
61-
- does **not** run it in GitHub Actions; and
62-
- does **not** change adapter capability claims.
29+
1. variable-set round trips;
30+
2. independent print and write formats;
31+
3. file label and document text;
32+
4. legacy code-page files and long-string edge cases.
6333

64-
Adopting it requires a maintainer licence/distribution review and an explicit
65-
optional-engine packaging decision. CI can then test it only on platforms and
66-
under terms approved for installing the bundled IBM modules.
34+
Until a feature is proved, the adapter must report it as unsupported rather
35+
than silently losing it.
6736

68-
## Next implementation slice
37+
## Licence boundary
6938

70-
If approved after that review, add a private `PyspssioEngine` behind the
71-
existing engine boundary, initially with a hermetic SAV/ZSAV metadata fixture.
72-
Do not make it default until the implementation proves or deliberately reports
73-
each of these separately: file label/documents, variable sets, independent
74-
print/write formats, custom attributes, multiple-response sets, roles,
75-
alignment, display width and legacy encodings.
39+
The pyspssio wrapper is MIT, except for IBM I/O Module files bundled in its
40+
wheel. Those redistributables have their own IBM terms. pyspssio is a required
41+
runtime dependency, not an optional plugin; OpenStatSpec does not copy or
42+
modify its IBM binaries. See [third-party notices](../THIRD_PARTY_NOTICES.md)
43+
for the distribution boundary and the location of the authoritative installed
44+
terms.

‎docs/sav-profile.md‎

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,35 @@
22

33
The Python adapter implements a strict, source-faithful wide-table mapping.
44
One SAV or ZSAV dataset becomes one table; every source variable is a physical
5-
column and `__case_ordinal` preserves case order. The adapter never pivots,
5+
column and __case_ordinal preserves case order. The adapter never pivots,
66
chunks, or creates a cell/EAV representation.
77

8-
## Verified SQLite path
8+
## SPSS engine
99

10-
The SQLite reference path has a round-trip fixture covering numeric and string
11-
values, system-missing numerics, blank strings, labels, value labels, formats,
12-
measurement level, user-missing rules, file notes, and source encoding
13-
metadata. User-missing values remain stored values; their interpretation is
14-
kept as metadata and is restored to SAV on export.
10+
OpenStatSpec Python requires pyspssio 0.5.1 as its sole SPSS engine. There is
11+
no fallback reader or writer. The engine reads unencrypted .sav and .zsav
12+
files, and writes both formats through the same implementation.
1513

1614
## Verified SQL profiles
1715

1816
SQLite has a local reference fixture. PostgreSQL, MySQL, and MariaDB have
1917
separate service-backed conformance checks in GitHub Actions that import,
20-
validate, and export the same supported fixture. MySQL 8.4 and MariaDB 11.4
21-
exercise the shared profile contract; this does not claim coverage for every
22-
server configuration. An import that exceeds a
23-
target's strict single-table column limit fails before it creates a dataset.
24-
25-
## Explicit current boundaries
26-
27-
- Imports accept unencrypted `.sav` and `.zsav` sources through pyreadstat.
28-
- Exports write SAV and ZSAV; ZSAV output uses the engine's compressed
29-
SAV writer path.
30-
- The writer restores metadata supported by pyreadstat. SPSS dictionary
31-
constructs that pyreadstat does not expose as stable writer inputs—such as
32-
multiple-response sets and variable sets—are not silently claimed as
33-
round-tripped and require a later profile implementation.
34-
- Encryption and byte-identical reproduction are out of scope. The contract is
35-
semantic equivalence of supported values, order, and dictionary metadata.
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.
22+
23+
## Fidelity contract
24+
25+
The adapter must preserve and validate only the source semantics that the
26+
selected engine exposes and that a conformance fixture proves. Unsupported
27+
semantics fail explicitly; they never silently disappear. Encryption and
28+
byte-identical reproduction are outside the contract. The contract is semantic
29+
equivalence of supported values, order, and dictionary metadata.
30+
31+
## Distribution
32+
33+
The required engine includes IBM I/O Module redistributables under terms that
34+
are separate from OpenStatSpec's Apache-2.0 source licence. See
35+
[third-party notices](../THIRD_PARTY_NOTICES.md) before distributing a bundled
36+
application.

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ readme = "README.md"
1010
requires-python = ">=3.11"
1111
license = {text = "Apache-2.0"}
1212
authors = [{name = "OpenStatSpec"}]
13-
dependencies = ["SQLAlchemy>=2.0", "pandas>=2.2", "pyreadstat>=1.3"]
13+
dependencies = ["SQLAlchemy>=2.0", "pandas>=2.2", "pyspssio==0.5.1"]
1414

1515
[project.optional-dependencies]
1616
dev = ["pytest>=8"]

0 commit comments

Comments
 (0)