Skip to content

Commit

Permalink
Rename writing to unparsing
Browse files Browse the repository at this point in the history
  • Loading branch information
trossi committed May 16, 2024
1 parent 76c13ab commit a6af5fd
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 109 deletions.
4 changes: 2 additions & 2 deletions rdata/_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from typing import TYPE_CHECKING

from .conversion import convert_to_r_data
from .unparser import write
from .parser import RVersions
from .unparser import unparse_file

if TYPE_CHECKING:
import os
Expand All @@ -28,7 +28,7 @@ def write_rdata(
encoding=encoding,
versions=None if versions is None else RVersions(*versions),
)
write(
unparse_file(
path,
r_data,
rds=rds,
Expand Down
16 changes: 8 additions & 8 deletions rdata/tests/test_write.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Tests of writing and Python-to-R conversion."""
"""Tests of writing, unparsing, and Python-to-R conversion."""

from __future__ import annotations

Expand All @@ -11,7 +11,7 @@
import pytest

import rdata
from rdata.unparser import write_file
from rdata.unparser import unparse_data

if TYPE_CHECKING:
from collections.abc import Generator
Expand Down Expand Up @@ -53,8 +53,8 @@ def decompress_data(data: memoryview) -> bytes:
fnames = sorted([fpath.name for fpath in TESTDATA_PATH.glob("*.rd?")])

@pytest.mark.parametrize("fname", fnames, ids=fnames)
def test_write(fname: str) -> None:
"""Test writing RData object to a file."""
def test_unparse(fname: str) -> None:
"""Test unparsing RData object to a file."""
with (TESTDATA_PATH / fname).open("rb") as f:
data = decompress_data(f.read())
rds = data[:2] != b"RD"
Expand All @@ -64,7 +64,7 @@ def test_write(fname: str) -> None:

fd = io.BytesIO()
try:
write_file(fd, r_data, file_format=fmt, rds=rds)
unparse_data(fd, r_data, file_format=fmt, rds=rds)
except NotImplementedError as e:
pytest.xfail(str(e))

Expand Down Expand Up @@ -133,19 +133,19 @@ def test_convert_to_r_unsupported_encoding() -> None:
rdata.conversion.convert_to_r_data("ä", encoding="CP1250")


def test_write_big_int() -> None:
def test_unparse_big_int() -> None:
"""Test checking too large integers."""
big_int = 2**32
r_data = rdata.conversion.convert_to_r_data(big_int)
fd = io.BytesIO()
with pytest.raises(ValueError, match="(?i)not castable"):
write_file(fd, r_data, file_format="xdr")
unparse_data(fd, r_data, file_format="xdr")


@pytest.mark.parametrize("compression", [*valid_compressions, None, "fail"])
@pytest.mark.parametrize("fmt", [*valid_formats, None, "fail"])
@pytest.mark.parametrize("rds", [True, False])
def test_write_real_file(compression: str, fmt: str, rds: bool) -> None: # noqa: FBT001
def test_write_file(compression: str, fmt: str, rds: bool) -> None: # noqa: FBT001
"""Test writing RData object to a real file with compression."""
expectation = no_error()
if fmt not in valid_formats:
Expand Down
30 changes: 15 additions & 15 deletions rdata/unparser/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Utilities for writing a rdata file."""
"""Utilities for unparsing a rdata file."""

from __future__ import annotations

Expand All @@ -9,11 +9,11 @@

from rdata.parser import RData

from ._ascii import WriterASCII
from ._xdr import WriterXDR
from ._ascii import UnparserASCII
from ._xdr import UnparserXDR


def write(
def unparse_file(
path: os.PathLike[Any] | str,
r_data: RData,
*,
Expand All @@ -22,18 +22,18 @@ def write(
compression: str = "gzip",
) -> None:
"""
Write RData object to a file.
Unparse RData object to a file.
Parameters
----------
path:
File path to be written
File path to be created
r_data:
RData object
file_format:
File format (ascii or xdr)
rds:
Whether to write RDS or RDA file
Whether to create RDS or RDA file
compression:
Compression (gzip, bzip2, xz, or none)
"""
Expand All @@ -52,18 +52,18 @@ def write(
raise ValueError(msg)

with open(path, "wb") as f:
write_file(f, r_data, file_format=file_format, rds=rds)
unparse_data(f, r_data, file_format=file_format, rds=rds)


def write_file(
def unparse_data(
fileobj: IO[Any],
r_data: RData,
*,
file_format: str = "xdr",
rds: bool = True,
) -> None:
"""
Write RData object to a file object.
Unparse RData object to a file object.
Parameters
----------
Expand All @@ -74,15 +74,15 @@ def write_file(
file_format:
File format (ascii or xdr)
"""
Writer: type[WriterXDR | WriterASCII] # noqa: N806
Unparser: type[UnparserXDR | UnparserASCII] # noqa: N806

if file_format == "ascii":
from ._ascii import WriterASCII as Writer
from ._ascii import UnparserASCII as Unparser
elif file_format == "xdr":
from ._xdr import WriterXDR as Writer
from ._xdr import UnparserXDR as Unparser
else:
msg = f"Unknown file format: {file_format}"
raise ValueError(msg)

w = Writer(fileobj) # type: ignore [arg-type]
w.write_r_data(r_data, rds=rds)
unparser = Unparser(fileobj) # type: ignore [arg-type]
unparser.unparse_r_data(r_data, rds=rds)
34 changes: 17 additions & 17 deletions rdata/unparser/_ascii.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Writer for files in ASCII format."""
"""Unparser for files in ASCII format."""

from __future__ import annotations

Expand All @@ -7,37 +7,37 @@

import numpy as np

from ._unparser import Writer
from ._unparser import Unparser

if TYPE_CHECKING:
import io

import numpy.typing as npt


class WriterASCII(Writer):
"""Writer for files in ASCII format."""
class UnparserASCII(Unparser):
"""Unparser for files in ASCII format."""

def __init__(
self,
file: io.BytesIO,
) -> None:
"""Writer for files in ASCII format."""
"""Unparser for files in ASCII format."""
self.file = file

def _writeline(self, line: str) -> None:
def _add_line(self, line: str) -> None:
r"""Write a line with trailing \n."""
# Write in binary mode to be compatible with
# compression (e.g. when file = gzip.open())
self.file.write(f"{line}\n".encode("ascii"))

def write_magic(self, rda_version: int | None) -> None:
"""Write magic bits."""
def unparse_magic(self, rda_version: int | None) -> None:
"""Unparse magic bits."""
if rda_version is not None:
self._writeline(f"RDA{rda_version}")
self._writeline("A")
self._add_line(f"RDA{rda_version}")
self._add_line("A")

def _write_array_values(self, array: npt.NDArray[Any]) -> None:
def _unparse_array_values(self, array: npt.NDArray[Any]) -> None:
# Convert boolean to int
if np.issubdtype(array.dtype, np.bool_):
array = array.astype(np.int32)
Expand All @@ -47,7 +47,7 @@ def _write_array_values(self, array: npt.NDArray[Any]) -> None:
assert array.dtype == np.complex128
array = array.view(np.float64)

# Write data
# Unparse data
for value in array:
if np.issubdtype(array.dtype, np.integer):
line = "NA" if value is None or np.ma.is_masked(value) else str(value) # type: ignore [no-untyped-call]
Expand All @@ -61,11 +61,11 @@ def _write_array_values(self, array: npt.NDArray[Any]) -> None:
msg = f"Unknown dtype: {array.dtype}"
raise ValueError(msg)

self._writeline(line)
self._add_line(line)

def write_string(self, value: bytes) -> None:
"""Write a string."""
self.write_int(len(value))
def unparse_string(self, value: bytes) -> None:
"""Unparse a string."""
self.unparse_int(len(value))

# Ideally we could do here the reverse of parsing,
# i.e., value = value.decode('latin1').encode('unicode_escape').decode('ascii')
Expand All @@ -75,4 +75,4 @@ def write_string(self, value: bytes) -> None:
s = "".join(chr(byte) if chr(byte) in string.printable else rf"\{byte:03o}"
for byte in value)

self._writeline(s)
self._add_line(s)
Loading

0 comments on commit a6af5fd

Please sign in to comment.