Skip to content

Commit

Permalink
Better formatting in range_check.py example, and added to test_exampl…
Browse files Browse the repository at this point in the history
…es.py
  • Loading branch information
ptmcg committed May 7, 2023
1 parent fa12321 commit 1808ddd
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 23 deletions.
93 changes: 70 additions & 23 deletions examples/range_check.py
Expand Up @@ -9,56 +9,103 @@
#

import pyparsing as pp
from datetime import datetime
from datetime import date
from typing import Any


def ranged_value(expr, minval=None, maxval=None):
def ranged_value(
expr: pp.ParserElement,
min_val: Any = None,
max_val: Any = None,
label: str = ""
) -> pp.ParserElement:

# have to specify at least one range boundary
if minval is None and maxval is None:
raise ValueError("minval or maxval must be specified")
if (min_val, max_val) == (None, None):
raise ValueError("min_val or max_val must be specified")

expr_label = label or "value"

# set range testing function and error message depending on
# whether either or both min and max values are given
in_range_condition = {
(False, True): lambda s, l, t: t[0] <= maxval,
(True, False): lambda s, l, t: minval <= t[0],
(True, True): lambda s, l, t: minval <= t[0] <= maxval,
}[minval is not None, maxval is not None]
(False, True): lambda s, l, t: t[0] <= max_val,
(True, False): lambda s, l, t: min_val <= t[0],
(True, True): lambda s, l, t: min_val <= t[0] <= max_val,
}[min_val is not None, max_val is not None]

out_of_range_message = {
(False, True): f"value is greater than {maxval}",
(True, False): f"value is less than {minval}",
(True, True): f"value is not in the range ({minval} to {maxval})",
}[minval is not None, maxval is not None]
(False, True): f"{expr_label} is greater than {max_val}",
(True, False): f"{expr_label} is less than {min_val}",
(True, True): f"{expr_label} is not in the range ({min_val} to {max_val})",
}[min_val is not None, max_val is not None]

ret = expr().add_condition(in_range_condition, message=out_of_range_message)

if label:
ret.set_name(label)

return expr().add_condition(in_range_condition, message=out_of_range_message)
return ret


# define the expressions for a date of the form YYYY/MM/DD or YYYY/MM (assumes YYYY/MM/01)
integer = pp.Word(pp.nums).set_name("integer")
integer.set_parse_action(lambda t: int(t[0]))

month = ranged_value(integer, 1, 12)
day = ranged_value(integer, 1, 31)
year = ranged_value(integer, 2000, None)
month = ranged_value(integer, 1, 12, "month")
day = ranged_value(integer, 1, 31, "day")
year = ranged_value(integer, 2000, None, "year")

SLASH = pp.Suppress("/")
dateExpr = year("year") + SLASH + month("month") + pp.Opt(SLASH + day("day"))
dateExpr.set_name("date")

# convert date fields to datetime (also validates dates as truly valid dates)
dateExpr.set_parse_action(lambda t: datetime(t.year, t.month, t.day or 1).date())
dateExpr.set_parse_action(lambda t: date(t.year, t.month, t.day or 1))

# add range checking on dates
mindate = datetime(2002, 1, 1).date()
maxdate = datetime.now().date()
dateExpr = ranged_value(dateExpr, mindate, maxdate)
min_date = date(2002, 1, 1)
max_date = date.today()
date_expr = ranged_value(dateExpr, min_date, max_date, "date")

date_expr.create_diagram("range_check.html")

dateExpr.run_tests(
# tests of valid dates
success_valid_tests, _ = date_expr.run_tests(
"""
# valid date
2011/5/8
2001/1/1
# leap day
2004/2/29
# default day of month to 1
2004/2
1999/12/31"""
"""
)

# tests of invalid dates
success_invalid_tests, _ = date_expr.run_tests(
"""
# all values are in range, but date is too early
2001/1/1
# not a leap day
2005/2/29
# year number is < 2000
1999/12/31
# bad year field
XXXX/1/1
# bad month field
2010/XX/1
# bad day field
2010/11/XX
""",
failure_tests=True
)

assert (success_valid_tests and success_invalid_tests)
3 changes: 3 additions & 0 deletions tests/test_examples.py
Expand Up @@ -45,3 +45,6 @@ def test_excelExpr(self):

def test_lucene_grammar(self):
self._run("lucene_grammar")

def test_range_check(self):
self._run("range_check")

0 comments on commit 1808ddd

Please sign in to comment.