Skip to content

Commit

Permalink
Merge pull request #3 from UniExeterRSE/iss2-field-ordering
Browse files Browse the repository at this point in the history
Issue 2: field ordering
  • Loading branch information
thawes-rse authored Sep 25, 2023
2 parents 2841adb + bc52a8b commit 9813403
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 11 deletions.
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 = "csv-db"
version = "0.1.0.rc3"
version = "0.1.0.rc4"
description = 'A Python package for working with a simple databse backed by a csv file.'
readme = "README.md"
requires-python = ">=3.9"
Expand Down
26 changes: 16 additions & 10 deletions src/csv_db/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,35 +48,39 @@ class CsvDB(object):

def __init__(self, path: Path, fields: Collection[str]):
self._path = pathlib.Path(path)
self._fields = fields
self._fields_arg = "fields" # should match the name of the argument in __init__
self._validate_fields()
self._fields = self._make_fields(fields)

def _validate_fields(self) -> None:
"""Perform checks on the supplied fields and, if present, those in the csv file.
def _make_fields(self, fields: Collection[str]) -> None:
"""Make the fields to store reference in database operations.
Along the way, this method performs checks on the supplied fields and, if present,
those in the csv file. The checks performed are:
Checks that:
* The collection of field names is not empty.
* None of the field names are missing, i.e. the empty string.
* None of the field names are repeated.
* The supplied fields agree with those in the csv file, if the latter is present.
If all relevant checks pass, then the fields as ordered in the csv file are
returned. Otherwise, the supplied `fields` are returned.
"""

if len(self._fields) == 0:
if len(fields) == 0:
raise ValueError(
f"Argument '{self._fields_arg}' defines an empty collection."
)

if self._any_missing(self._fields):
if self._any_missing(fields):
raise ValueError(f"Argument '{self._fields_arg}' contains empty field names.")

if repeated_fields := self._make_repetitions_str(self._fields):
if repeated_fields := self._make_repetitions_str(fields):
raise ValueError(
f"Argument '{self._fields_arg}' contains repeated fields: {repeated_fields}."
)

if not self._path.exists():
return
return fields

with open(self._path, mode="r") as csvfile:
file_fields = tuple(csvfile.readline().strip().split(","))
Expand All @@ -91,11 +95,13 @@ def _validate_fields(self) -> None:
f"Database file {self._path} contains repeated fields: {repeated_fields}."
)

if not set(self._fields) == set(file_fields):
if not set(fields) == set(file_fields):
raise FieldsMismatchError(
f"'{self._fields_arg}' does not agree with the fields defined in {self._path}."
)

return file_fields

@staticmethod
def _any_missing(coll: Collection[str]) -> bool:
"""Returns ``True`` if the empty string is in the collection `coll`."""
Expand Down
10 changes: 10 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,16 @@ def test_retrieve_missing_field_error(self):
):
self.db2.retrieve(field, "1")

def test_retrieve_field_order_in_file_differs_to_instantiation(self):
"""Test that a record can be correctly retrieved when it belongs to a csv file
where the order of fields differs from that given at instantiation of a new
database."""

write_csv_row(self.path3, ["1", "a"], mode="a")
self.assertEqual(
{self.pkey: "1", self.col1: "a"}, self.dbrev.retrieve(self.pkey, "1")
)

def test_update_replaces_correct_record(self):
"""Test that the record with the specified field value gets updated and no other
records get updated."""
Expand Down

0 comments on commit 9813403

Please sign in to comment.