Skip to content

Commit

Permalink
Add string format and parse methods to undate and undate interval
Browse files Browse the repository at this point in the history
  • Loading branch information
rlskoeser committed Aug 29, 2024
1 parent 640705c commit a8802d6
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
30 changes: 30 additions & 0 deletions src/undate/undate.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,27 @@ def __repr__(self) -> str:
return "<Undate '%s' (%s)>" % (self.label, self)
return "<Undate %s>" % self

@classmethod
def parse(cls, date_string, format) -> Union["Undate", "UndateInterval"]:
"""parse a string to an undate or undate interval using the specified format;
for now, only supports named formatters"""
formatter_cls = BaseDateFormat.available_formatters().get(format, None)
if formatter_cls:
# NOTE: some parsers may return intervals; is that ok here?
return formatter_cls().parse(date_string)

raise ValueError(f"Unsupported format '{format}'")

def format(self, format) -> str:
"""format this undate as a string using the specified format;
for now, only supports named formatters"""
formatter_cls = BaseDateFormat.available_formatters().get(format, None)
if formatter_cls:
# NOTE: some parsers may return intervals; is that ok here?
return formatter_cls().to_string(self)

raise ValueError(f"Unsupported format '{format}'")

def _comparison_type(self, other: object) -> "Undate":
"""Common logic for type handling in comparison methods.
Converts to Undate object if possible, otherwise raises
Expand Down Expand Up @@ -424,6 +445,15 @@ def __str__(self) -> str:
# using EDTF syntax for open ranges
return "%s/%s" % (self.earliest or "..", self.latest or "")

def format(self, format) -> str:
"""format this undate interval as a string using the specified format;
for now, only supports named formatters"""
formatter_cls = BaseDateFormat.available_formatters().get(format, None)
if formatter_cls:
return formatter_cls().to_string(self)

raise ValueError(f"Unsupported format '{format}'")

def __repr__(self) -> str:
if self.label:
return "<UndateInterval '%s' (%s)>" % (self.label, self)
Expand Down
54 changes: 54 additions & 0 deletions tests/test_undate.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,46 @@ def test_is_known_day(self):
assert Undate(month=1, day="X5").is_known("day") is False
assert Undate(month=1, day="XX").is_known("day") is False

def test_parse(self):
assert Undate.parse("1984", "EDTF") == Undate(1984)
assert Undate.parse("1984-04", "EDTF") == Undate(1984, 4)
assert Undate.parse("1984-04", "EDTF") == Undate(1984, 4)
assert Undate.parse("2000/2001", "EDTF") == UndateInterval(
Undate(2000), Undate(2001)
)

assert Undate.parse("1984", "ISO8601") == Undate(1984)
assert Undate.parse("1984-04", "ISO8601") == Undate(1984, 4)
assert Undate.parse("--12-31", "ISO8601") == Undate(month=12, day=31)

# unsupported format
with pytest.raises(ValueError, match="Unsupported format"):
Undate.parse("1984", "foobar")
with pytest.raises(ValueError, match="Unsupported format"):
Undate.parse("1984", "%Y-%m")

def test_format(self):
# EDTF format
assert Undate(1984).format("EDTF") == "1984"
assert Undate(1984, 4).format("EDTF") == "1984-04"
assert Undate(1984, 4, 15).format("EDTF") == "1984-04-15"
assert Undate("19XX").format("EDTF") == "19XX"
assert Undate(1984, "XX").format("EDTF") == "1984-XX"
assert Undate(1984, 4, "XX").format("EDTF") == "1984-04-XX"
assert Undate(month=12, day=31).format("EDTF") == "XXXX-12-31"

# ISO8601 format
assert Undate(1984).format("ISO8601") == "1984"
assert Undate(1984, 4).format("ISO8601") == "1984-04"
assert Undate(1984, 4, 15).format("ISO8601") == "1984-04-15"
assert Undate(month=12, day=31).format("ISO8601") == "--12-31"

# unsupported format
with pytest.raises(ValueError, match="Unsupported format"):
Undate(1984).format("foobar")
with pytest.raises(ValueError, match="Unsupported format"):
Undate(1984).format("%Y-%m")


class TestUndateInterval:
def test_str(self):
Expand All @@ -392,6 +432,20 @@ def test_str(self):
== "2022-11-01/2023-11-07"
)

def test_format(self):
interval = UndateInterval(Undate(2000), Undate(2001))
assert interval.format("EDTF") == "2000/2001"
assert interval.format("ISO8601") == "2000/2001"

# Open-ended intervals
open_start = UndateInterval(latest=Undate(2000))
assert open_start.format("EDTF") == "../2000"
assert open_start.format("ISO8601") == "/2000"

open_end = UndateInterval(earliest=Undate(2000))
assert open_end.format("EDTF") == "2000/.."
assert open_end.format("ISO8601") == "2000/"

def test_repr(self):
assert (
repr(UndateInterval(Undate(2022), Undate(2023)))
Expand Down

0 comments on commit a8802d6

Please sign in to comment.