Skip to content

Commit 0359a53

Browse files
committed
Support ZSAV export
1 parent 10d230e commit 0359a53

3 files changed

Lines changed: 8 additions & 3 deletions

File tree

‎src/openstatspec/api.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
def capabilities() -> Mapping[str, Any]:
1313
return CapabilityDeclaration(
1414
specification="OpenStatSpec strict wide-table SPSS profile (initial)",
15-
formats={"SAV": {"import": True, "export": True}, "ZSAV": {"import": True, "export": False}},
15+
formats={"SAV": {"import": True, "export": True}, "ZSAV": {"import": True, "export": True}},
1616
database_profiles=declared_profiles(),
1717
).as_dict()
1818

‎src/openstatspec/spss/sav.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ def import_sav_dataset(*, source: str | Path, database_url: str, dataset_id: str
8686

8787
def export_sav_dataset(*, database_url: str, dataset_id: str, destination: str | Path) -> dict[str, Any]:
8888
destination_path = Path(destination)
89-
if destination_path.suffix.lower() != ".sav":
90-
raise UnsupportedOperationError("This initial profile exports SAV only; ZSAV output is not yet supported.")
89+
if destination_path.suffix.lower() not in {".sav", ".zsav"}:
90+
raise UnsupportedOperationError("Export destinations must use the .sav or .zsav extension.")
9191
dataset, variables, rows = read_wide_dataset(database_url=database_url, dataset_id=dataset_id)
9292
import pandas as pd
9393
frame = pd.DataFrame(
@@ -108,6 +108,7 @@ def export_sav_dataset(*, database_url: str, dataset_id: str, destination: str |
108108
}
109109
pyreadstat.write_sav(
110110
frame, destination_path, file_label=dataset["file_label"], column_labels=labels,
111+
compress=destination_path.suffix.lower() == ".zsav",
111112
variable_format=formats, variable_measure=measures,
112113
variable_display_width=displays, variable_value_labels=value_labels,
113114
missing_ranges=missing_ranges, note=json.loads(dataset["documents"]),

‎tests/test_sav_sqlite.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ def test_sav_round_trip_uses_one_wide_table_and_catalog(tmp_path) -> None:
4949
assert meta.variable_value_labels == {"age": {34.0: "thirty-four"}}
5050
assert meta.original_variable_types == {"age": "F8.0", "name": "A12"}
5151
assert meta.variable_measure == {"age": "scale", "name": "nominal"}
52+
zsav = tmp_path / "roundtrip.zsav"
53+
openstatspec.export_sav(database_url=database, dataset_id="tiny", destination=zsav)
54+
compressed_frame, _ = pyreadstat.read_sav(zsav, user_missing=True)
55+
assert compressed_frame["name"].tolist() == ["Ada", ""]
5256
assert meta.missing_ranges == {"age": [{"lo": 34.0, "hi": 34.0}]}
5357
assert meta.notes == ["Fixture note"]
5458

0 commit comments

Comments
 (0)