Format: text/x-python
⬇ Download File (6.3 KB)
   1  import math
   2  import sys
   3  from datetime import date, datetime, timedelta, timezone
   4  from decimal import Decimal
   5  from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Set, Tuple
   6  
   7  if sys.version_info < (3, 9):
   8      from typing_extensions import Annotated
   9  else:
  10      from typing import Annotated
  11  
  12  import annotated_types as at
  13  
  14  
  15  class Case(NamedTuple):
  16      """
  17      A test case for `annotated_types`.
  18      """
  19  
  20      annotation: Any
  21      valid_cases: Iterable[Any]
  22      invalid_cases: Iterable[Any]
  23  
  24  
  25  def cases() -> Iterable[Case]:
  26      # Gt, Ge, Lt, Le
  27      yield Case(Annotated[int, at.Gt(4)], (5, 6, 1000), (4, 0, -1))
  28      yield Case(Annotated[float, at.Gt(0.5)], (0.6, 0.7, 0.8, 0.9), (0.5, 0.0, -0.1))
  29      yield Case(
  30          Annotated[datetime, at.Gt(datetime(2000, 1, 1))],
  31          [datetime(2000, 1, 2), datetime(2000, 1, 3)],
  32          [datetime(2000, 1, 1), datetime(1999, 12, 31)],
  33      )
  34      yield Case(
  35          Annotated[datetime, at.Gt(date(2000, 1, 1))],
  36          [date(2000, 1, 2), date(2000, 1, 3)],
  37          [date(2000, 1, 1), date(1999, 12, 31)],
  38      )
  39      yield Case(
  40          Annotated[datetime, at.Gt(Decimal('1.123'))],
  41          [Decimal('1.1231'), Decimal('123')],
  42          [Decimal('1.123'), Decimal('0')],
  43      )
  44  
  45      yield Case(Annotated[int, at.Ge(4)], (4, 5, 6, 1000, 4), (0, -1))
  46      yield Case(Annotated[float, at.Ge(0.5)], (0.5, 0.6, 0.7, 0.8, 0.9), (0.4, 0.0, -0.1))
  47      yield Case(
  48          Annotated[datetime, at.Ge(datetime(2000, 1, 1))],
  49          [datetime(2000, 1, 2), datetime(2000, 1, 3)],
  50          [datetime(1998, 1, 1), datetime(1999, 12, 31)],
  51      )
  52  
  53      yield Case(Annotated[int, at.Lt(4)], (0, -1), (4, 5, 6, 1000, 4))
  54      yield Case(Annotated[float, at.Lt(0.5)], (0.4, 0.0, -0.1), (0.5, 0.6, 0.7, 0.8, 0.9))
  55      yield Case(
  56          Annotated[datetime, at.Lt(datetime(2000, 1, 1))],
  57          [datetime(1999, 12, 31), datetime(1999, 12, 31)],
  58          [datetime(2000, 1, 2), datetime(2000, 1, 3)],
  59      )
  60  
  61      yield Case(Annotated[int, at.Le(4)], (4, 0, -1), (5, 6, 1000))
  62      yield Case(Annotated[float, at.Le(0.5)], (0.5, 0.0, -0.1), (0.6, 0.7, 0.8, 0.9))
  63      yield Case(
  64          Annotated[datetime, at.Le(datetime(2000, 1, 1))],
  65          [datetime(2000, 1, 1), datetime(1999, 12, 31)],
  66          [datetime(2000, 1, 2), datetime(2000, 1, 3)],
  67      )
  68  
  69      # Interval
  70      yield Case(Annotated[int, at.Interval(gt=4)], (5, 6, 1000), (4, 0, -1))
  71      yield Case(Annotated[int, at.Interval(gt=4, lt=10)], (5, 6), (4, 10, 1000, 0, -1))
  72      yield Case(Annotated[float, at.Interval(ge=0.5, le=1)], (0.5, 0.9, 1), (0.49, 1.1))
  73      yield Case(
  74          Annotated[datetime, at.Interval(gt=datetime(2000, 1, 1), le=datetime(2000, 1, 3))],
  75          [datetime(2000, 1, 2), datetime(2000, 1, 3)],
  76          [datetime(2000, 1, 1), datetime(2000, 1, 4)],
  77      )
  78  
  79      yield Case(Annotated[int, at.MultipleOf(multiple_of=3)], (0, 3, 9), (1, 2, 4))
  80      yield Case(Annotated[float, at.MultipleOf(multiple_of=0.5)], (0, 0.5, 1, 1.5), (0.4, 1.1))
  81  
  82      # lengths
  83  
  84      yield Case(Annotated[str, at.MinLen(3)], ('123', '1234', 'x' * 10), ('', '1', '12'))
  85      yield Case(Annotated[str, at.Len(3)], ('123', '1234', 'x' * 10), ('', '1', '12'))
  86      yield Case(Annotated[List[int], at.MinLen(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2]))
  87      yield Case(Annotated[List[int], at.Len(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2]))
  88  
  89      yield Case(Annotated[str, at.MaxLen(4)], ('', '1234'), ('12345', 'x' * 10))
  90      yield Case(Annotated[str, at.Len(0, 4)], ('', '1234'), ('12345', 'x' * 10))
  91      yield Case(Annotated[List[str], at.MaxLen(4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10))
  92      yield Case(Annotated[List[str], at.Len(0, 4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10))
  93  
  94      yield Case(Annotated[str, at.Len(3, 5)], ('123', '12345'), ('', '1', '12', '123456', 'x' * 10))
  95      yield Case(Annotated[str, at.Len(3, 3)], ('123',), ('12', '1234'))
  96  
  97      yield Case(Annotated[Dict[int, int], at.Len(2, 3)], [{1: 1, 2: 2}], [{}, {1: 1}, {1: 1, 2: 2, 3: 3, 4: 4}])
  98      yield Case(Annotated[Set[int], at.Len(2, 3)], ({1, 2}, {1, 2, 3}), (set(), {1}, {1, 2, 3, 4}))
  99      yield Case(Annotated[Tuple[int, ...], at.Len(2, 3)], ((1, 2), (1, 2, 3)), ((), (1,), (1, 2, 3, 4)))
 100  
 101      # Timezone
 102  
 103      yield Case(
 104          Annotated[datetime, at.Timezone(None)], [datetime(2000, 1, 1)], [datetime(2000, 1, 1, tzinfo=timezone.utc)]
 105      )
 106      yield Case(
 107          Annotated[datetime, at.Timezone(...)], [datetime(2000, 1, 1, tzinfo=timezone.utc)], [datetime(2000, 1, 1)]
 108      )
 109      yield Case(
 110          Annotated[datetime, at.Timezone(timezone.utc)],
 111          [datetime(2000, 1, 1, tzinfo=timezone.utc)],
 112          [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))],
 113      )
 114      yield Case(
 115          Annotated[datetime, at.Timezone('Europe/London')],
 116          [datetime(2000, 1, 1, tzinfo=timezone(timedelta(0), name='Europe/London'))],
 117          [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))],
 118      )
 119  
 120      # Quantity
 121  
 122      yield Case(Annotated[float, at.Unit(unit='m')], (5, 4.2), ('5m', '4.2m'))
 123  
 124      # predicate types
 125  
 126      yield Case(at.LowerCase[str], ['abc', 'foobar'], ['', 'A', 'Boom'])
 127      yield Case(at.UpperCase[str], ['ABC', 'DEFO'], ['', 'a', 'abc', 'AbC'])
 128      yield Case(at.IsDigit[str], ['123'], ['', 'ab', 'a1b2'])
 129      yield Case(at.IsAscii[str], ['123', 'foo bar'], ['£100', '😊', 'whatever 👀'])
 130  
 131      yield Case(Annotated[int, at.Predicate(lambda x: x % 2 == 0)], [0, 2, 4], [1, 3, 5])
 132  
 133      yield Case(at.IsFinite[float], [1.23], [math.nan, math.inf, -math.inf])
 134      yield Case(at.IsNotFinite[float], [math.nan, math.inf], [1.23])
 135      yield Case(at.IsNan[float], [math.nan], [1.23, math.inf])
 136      yield Case(at.IsNotNan[float], [1.23, math.inf], [math.nan])
 137      yield Case(at.IsInfinite[float], [math.inf], [math.nan, 1.23])
 138      yield Case(at.IsNotInfinite[float], [math.nan, 1.23], [math.inf])
 139  
 140      # check stacked predicates
 141      yield Case(at.IsInfinite[Annotated[float, at.Predicate(lambda x: x > 0)]], [math.inf], [-math.inf, 1.23, math.nan])
 142  
 143      # doc
 144      yield Case(Annotated[int, at.doc("A number")], [1, 2], [])
 145  
 146      # custom GroupedMetadata
 147      class MyCustomGroupedMetadata(at.GroupedMetadata):
 148          def __iter__(self) -> Iterator[at.Predicate]:
 149              yield at.Predicate(lambda x: float(x).is_integer())
 150  
 151      yield Case(Annotated[float, MyCustomGroupedMetadata()], [0, 2.0], [0.01, 1.5])
 152