rangeCheck.py 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. # rangeCheck.py
  2. #
  3. # A sample program showing how parse actions can convert parsed
  4. # strings into a data type or object, and to validate the parsed value.
  5. #
  6. # Updated to use new addCondition method and expr() copy.
  7. #
  8. # Copyright 2011,2015 Paul T. McGuire
  9. #
  10. from pyparsing import Word, nums, Suppress, Optional
  11. from datetime import datetime
  12. def ranged_value(expr, minval=None, maxval=None):
  13. # have to specify at least one range boundary
  14. if minval is None and maxval is None:
  15. raise ValueError("minval or maxval must be specified")
  16. # set range testing function and error message depending on
  17. # whether either or both min and max values are given
  18. inRangeCondition = {
  19. (True, False) : lambda s,l,t : t[0] <= maxval,
  20. (False, True) : lambda s,l,t : minval <= t[0],
  21. (False, False) : lambda s,l,t : minval <= t[0] <= maxval,
  22. }[minval is None, maxval is None]
  23. outOfRangeMessage = {
  24. (True, False) : "value is greater than %s" % maxval,
  25. (False, True) : "value is less than %s" % minval,
  26. (False, False) : "value is not in the range ({0} to {1})".format(minval,maxval),
  27. }[minval is None, maxval is None]
  28. return expr().addCondition(inRangeCondition, message=outOfRangeMessage)
  29. # define the expressions for a date of the form YYYY/MM/DD or YYYY/MM (assumes YYYY/MM/01)
  30. integer = Word(nums).setName("integer")
  31. integer.setParseAction(lambda t:int(t[0]))
  32. month = ranged_value(integer, 1, 12)
  33. day = ranged_value(integer, 1, 31)
  34. year = ranged_value(integer, 2000, None)
  35. SLASH = Suppress('/')
  36. dateExpr = year("year") + SLASH + month("month") + Optional(SLASH + day("day"))
  37. dateExpr.setName("date")
  38. # convert date fields to datetime (also validates dates as truly valid dates)
  39. dateExpr.setParseAction(lambda t: datetime(t.year, t.month, t.day or 1).date())
  40. # add range checking on dates
  41. mindate = datetime(2002,1,1).date()
  42. maxdate = datetime.now().date()
  43. dateExpr = ranged_value(dateExpr, mindate, maxdate)
  44. dateExpr.runTests("""
  45. 2011/5/8
  46. 2001/1/1
  47. 2004/2/29
  48. 2004/2
  49. 1999/12/31""")