Skip to content

Commit

Permalink
chage iterable typing to sequence; improve tests
Browse files Browse the repository at this point in the history
  • Loading branch information
OlivierBinette committed Nov 26, 2023
1 parent a88ac26 commit 9589542
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 26 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,15 @@ df

## Changelog

### 1.1.1 (2023-11-25)

- Change `Iterable` typing to `Sequence` to account for order and allow multiple passes over data.
- Improve tests.

### 1.1.0 (2023-11-25)

- Fix read function return type: now return list of lists instead of generator
- Fix read function return type: now return list of lists instead of generator.

### 1.0.0 (2023-11-25)

- Initial release
- Initial release.
2 changes: 1 addition & 1 deletion csvmeta/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
from csvmeta.write import DEFAULT_DIALECT, write

__all__ = ["read", "metadata", "write", "DEFAULT_DIALECT"]
__version__ = "1.1.0"
__version__ = "1.1.1"
22 changes: 10 additions & 12 deletions csvmeta/read.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import csv
import json
import os
from typing import Iterable, Union
from typing import Sequence, Union

from csvmeta.write import DEFAULT_DIALECT


def read(dirpath: str) -> Iterable[Iterable[str]]:
def read(dirpath: str) -> Sequence[Sequence[str]]:
"""
Read CSV data from the specified directory path.
Expand All @@ -19,18 +19,16 @@ def read(dirpath: str) -> Iterable[Iterable[str]]:
Returns
-------
Iterable[Iterable[str]]
An iterable of rows, where each row is an iterable of string values. The header is always returned as the first row.
Sequence[Sequence[str]]
A sequence of rows, where each row is a sequence of string values. The header is always returned as the first row.
"""
meta = metadata(dirpath)
dialect = meta.get("dialect", DEFAULT_DIALECT)

reader = _read_csv(dirpath, dialect)
return _read_csv(dirpath, dialect)

return list(reader)


def _read_csv(dirpath: str, dialect: Union[str, dict]) -> Iterable[Iterable[str]]:
def _read_csv(dirpath: str, dialect: Union[str, dict]) -> Sequence[Sequence[str]]:
"""
Internal function to read a CSV file using the specified dialect.
Expand All @@ -43,17 +41,17 @@ def _read_csv(dirpath: str, dialect: Union[str, dict]) -> Iterable[Iterable[str]
Returns
-------
Iterable[Iterable[str]]
An iterable of rows, where each row is an iterable of string values.
Sequence[Sequence[str]]
A sequence of rows, where each row is a sequence of string values.
"""
csv_filepath = os.path.join(dirpath, "data.csv")
with open(csv_filepath, newline="") as csvfile:
if isinstance(dialect, str):
reader = csv.reader(csvfile, dialect=dialect)
else:
reader = csv.reader(csvfile, **dialect)
for row in reader:
yield row

return list(reader)


def metadata(dirpath: str) -> dict:
Expand Down
10 changes: 5 additions & 5 deletions csvmeta/write.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import csv
import json
import os
from typing import Any, Iterable, Union
from typing import Any, Sequence, Union

_DialectType = Union[str, dict]

DEFAULT_DIALECT = "unix"


def write(
dirpath: str, rowsdata: Iterable[Iterable[Any]], dialect: _DialectType = DEFAULT_DIALECT, **additional_metadata
dirpath: str, rowsdata: Sequence[Sequence[Any]], dialect: _DialectType = DEFAULT_DIALECT, **additional_metadata
) -> None:
"""
Write CSV data and optional metadata.
Expand All @@ -18,7 +18,7 @@ def write(
----------
dirpath : str
The directory path where the CSV file and metadata will be saved.
rowsdata : Iterable[Iterable[Any]]
rowsdata : Sequence[Sequence[Any]]
The data to be written to the CSV file.
dialect : str | dict, optional
The dialect to be used for writing the CSV file, by default DEFAULT_DIALECT (unix). See https://docs.python.org/3/library/csv.html#csv-fmt-params for valid parameters and more information.
Expand All @@ -32,15 +32,15 @@ def write(
_write_metadata(dirpath, dialect, **additional_metadata)


def _write_csv(dirpath: str, rowsdata: Iterable[Iterable[Any]], dialect: _DialectType = DEFAULT_DIALECT) -> None:
def _write_csv(dirpath: str, rowsdata: Sequence[Sequence[Any]], dialect: _DialectType = DEFAULT_DIALECT) -> None:
"""
Internal function to write data to a CSV file.
Parameters
----------
dirpath : str
The directory path where the CSV file will be saved.
rowsdata : Iterable[Iterable[Any]]
rowsdata : Sequence[Sequence[Any]]
The data to be written to the CSV file.
dialect : str | dict, optional
The dialect to be used for writing the CSV file, by default DEFAULT_DIALECT.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "csvmeta"
version = "1.1.0"
version = "1.1.1"
description = "Lightweight csv read/write, keeping track of csv dialect and other metadata."
authors = [{ name = "Olivier Binette", email = "[email protected]" }]
readme = "README.md"
Expand Down
16 changes: 12 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
DIALECTS_LIST = [
"excel",
"unix",
{"delimiter": "|", "quotechar": "'", "quoting": csv.QUOTE_NONE, "lineterminator": "\n"},
{"delimiter": "|", "escapechar": "\\", "quotechar": "'", "quoting": csv.QUOTE_NONE, "lineterminator": "\n"},
{
"delimiter": ",",
"doublequote": False,
"escapechar": "\\",
"doublequote": True,
"lineterminator": "\r\n",
"quotechar": '"',
"quoting": 0, # Minimal quoting
Expand Down Expand Up @@ -39,7 +38,16 @@ def example_schema():
@pytest.fixture
def example_csv_data():
# Return example CSV data
return [["Header1", "Header2"], ["Value1", "Value2"], ["Value3", "Value4"]]
return [
["Header1", "Header2"],
["Value1", None],
[0, 2 + 3j],
[True, False],
[1.0, Exception],
[dict(a=1, b=2), [3, 4]],
[{1, "a"}, (1, 2, 3)],
[csv.Dialect, csv.excel],
]


@pytest.fixture
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def test_read_csv(tmpdir, example_csv_data, example_metadata, dialect):

# Verify the read data matches the example data
for expected_row, row in zip(example_csv_data, result):
assert list(row) == expected_row
assert list(row) == [str(x) if x is not None else "" for x in expected_row]


def test_metadata(tmpdir, example_metadata):
Expand Down

0 comments on commit 9589542

Please sign in to comment.