def test_match_dict(): pet = {"type": "dog", "details": {"age": 3}} assert ~(caseof(pet) | m({"details": { "age": _ }}) >> (lambda age: age)) == 3 assert ~(caseof(pet) | m({_: { "age": _ }}) >> (lambda a, b: (a, b))) == ("details", 3)
def test_match_XObject(): assert ~(caseof((1, 2, 3)) | m(X[2] == 3) >> True) with pytest.raises(MatchError): ~(caseof((1, 2, 3)) | m(X[2]) >> True) assert ~(caseof("abc") | m(X.upper() == "ABC") >> True | _ >> False) assert ~(caseof((1, 2, 3)) | m(X[2] == 3) >> X[2] + 4) == 7 assert ~(caseof(9) | m(X**2 - X + 2 == 74) >> True | _ >> False)
def test_chain_caseof(): assert ~(caseof([1, 2, 3]) | m(_, _, 3) >> ~(caseof(X) | m(_, 2) >> X)) == 1 pet = {"type": "dog", "details": {"age": 3}} assert ~(caseof(pet) | m({_: { "age": _ }}) >> ~(caseof(X) | m(int, int) >> (lambda x, y: x + y) | m(str, int) >> (lambda x, y: y))) == 3
def test_match_XObject_with_getitem_style(): assert ~(caseof((1, 2, 3)) | m[X[2] == 3] >> True) with pytest.raises(MatchError): ~(caseof((1, 2, 3)) | m[X[2]] >> True) assert ~(caseof("abc") | m[X.upper() == "ABC"] >> True | _ >> False) assert ~(caseof((1, 2, 3)) | m[X[2] == 3] >> X[2] + 4) == 7 assert ~(caseof(9) | m[X**2 - X + 2 == 74] >> True | _ >> False)
def test_bitwise_operators_example(): assert ~(caseof(1) | (m[2] | m[1]) >> 1 | _ >> "nothing") == 1 assert ~(caseof(11) | (m[lambda x: x > 1] & m[lambda x: x < 10]) >> "1 < x < 10" | (m[lambda x: x > 1] & m[lambda x: x < 15]) >> "1 < x < 15" ) == "1 < x < 15" assert ~(caseof(6) | ~m[lambda x: x > 5] >> "x <=5" | ~m[lambda x: x > 10] >> "x <= 10") == "x <= 10"
def test_xfunction_pattern(): @xfunction def greater_than_4(x): return x > 4 assert ~(caseof(1) | m(greater_than_4(X + 5)) >> "greater than 4" | _ >> "equal or lesser than 4") == "greater than 4" assert ~(caseof(1) | m(greater_than_4(X)) >> "greater than 4" | _ >> "equal or lesser than 4") == "equal or lesser than 4"
def test_match_dict_with_getitem_style(): pet = {"type": "dog", "details": {"age": 3}} assert ~(caseof(pet) | m[{ "details": { "age": _ } }] >> (lambda age: age)) == 3 assert ~(caseof(pet) | m[{ _: { "age": _ } }] >> (lambda a, b: (a, b))) == ("details", 3)
def what_is(x): return ~(caseof(x) | m(Dog(_, 0)) >> "good boy" | m(Dog(_, _)) >> "doggy!" | m(Cat(_, 0)) >> "tommy?" | m(Cat(_, _)) >> "a cat" )
def what_is(pet): return ~(caseof(pet) | m(re.compile(r"(\w+)-(\w+)-cat$")) >> (lambda name, my: "cat " + name) | m(re.compile(r"(\w+)-(\w+)-dog$")) >> (lambda name, my: "dog " + name) | _ >> "something else")
def test_multi_dataclasses(): try: from dataclasses import dataclass except ImportError: return @dataclass class Point: x: int y: int @dataclass class Point2: x: int y: int @dataclass class Line: p1: Point p2: Point @dataclass class Rect: l1: Line l2: Line assert ~(caseof(Rect(Point(1, 2), Point(3, 4))) | m(Rect(Point(_, str), Point(_, 4))) >> "first" | m(Rect(Point(_, int), Point2(_, 4))) >> "second" | m(Rect(Point(_, int), Point(_, 4))) >> (lambda x, y, z: (x, y, z)) ) == (1, 2, 3)
def f(x): return ~(caseof(x) | m(Point(1, 2)) >> X | m(Point(_, 2)) >> X + 1 | m(Point(1, _)) >> X ** 2 | m(Point(_, _)) >> X * 2 )
def f(x): return ~(caseof(x) | m(Point(1, 2)) >> "1" | m(Point(_, 2)) >> str | m(Point(1, _)) >> str | m(Point(_, _)) >> (lambda a, b: str(a + b)) )
def test_match_raise_lambda_error(): with pytest.raises(MatchError) as error: ~( caseof([1, 2, 3]) | m([1, _, 3]) >> (lambda: "xxxxx {}".format()) # noqa ) assert "lambda" in str(error.value) assert "xxxxx" in str(error.value)
def to_datetime( dt: Union[timestamp, day_tuple, dt_tuple, str, ]) -> Optional[datetime]: return ~(caseof(dt) | m(timestamp) >> (lambda x: datetime.fromtimestamp(x)) | m(Union[day_tuple, dt_tuple]) >> (lambda *x: datetime(*x)) | m(datetime_p(["%Y-%m-%d", "%Y-%m-%d %H:%M:%S"])) >> (lambda x: x) | _ >> None)
def avg_cuteness_pampy(): cutenesses = [] for pet in pets: ~(caseof(pet) | m({_: { "cuteness": _ }}) >> (lambda key, x: cutenesses.append(x)) | m({_: { "cuty": _ }}) >> (lambda key, x: cutenesses.append(x))) return sum(cutenesses) / len(cutenesses)
def test_match_enum(): class Color(Enum): RED = 1 GREEN = 2 BLUE = 3 assert ~(caseof(Color.RED) | m(Color.BLUE) >> "blue" | m(Color.RED) >> "red" | _ >> "else") == "red" assert ~(caseof(Color.RED) | m(Color.BLUE) >> "blue" | m(Color.GREEN) >> "green" | _ >> "else") == "else" assert ~(caseof(1) | m(Color.BLUE) >> "blue" | m(Color.RED) >> "red" | _ >> "else") == "else"
def test_dataclasses_with_chain_caseof(): try: from dataclasses import dataclass except ImportError: return @dataclass class Class1: a: int b: int @dataclass class Class2: data: Class1 obj = Class2(Class1(a=1, b=2)) assert ~(caseof(obj) | m(Class2(_)) >> ~(caseof(X) | m(Class1(_, _)) >> (lambda a, b: (a, b)))) == (1, 2) # noqa
def test_advanced_lambda(): def either(pattern1, pattern2): """Matches values satisfying pattern1 OR pattern2""" def repack(*args): return True, list(args) def f(var): return ~(caseof(var) | m(pattern1) >> repack | m(pattern2) >> repack | _ >> (False, [])) return f assert ~(caseof("str") | m(either(int, str)) >> "success") == "success" def datetime_p(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0): """Matches a datetime with these values""" def f(var: datetime): if not isinstance(var, datetime): return False, [] args = [] for pattern, actual in [(year, var.year), (month, var.month), (day, var.day), (hour, var.hour), (minute, var.minute), (second, var.second)]: if pattern is _: args.append(actual) elif pattern != actual: return False, [] return True, args return f def test(var): return ~(caseof(var) | m(datetime_p(2018, 12, 23)) >> "full match" | m(datetime_p(2018, _, _)) >> (lambda month, day: f'{month}/{day} in 2018') | m(datetime_p(_, _, _, _, _, _)) >> "any datetime" | _ >> "not a datetime") assert test(datetime(2018, 12, 23)) == "full match" assert test(datetime(2018, 1, 2)) == "1/2 in 2018" assert test(datetime(2017, 1, 2, 3, 4, 5)) == "any datetime" assert test(11) == "not a datetime"
def test(var): return ~(caseof(var) | m(datetime_p(2018, 12, 23)) >> "full match" | m(datetime_p(2018, _, _)) >> (lambda month, day: f'{month}/{day} in 2018') | m(datetime_p(_, _, _, _, _, _)) >> "any datetime" | _ >> "not a datetime") assert test(datetime(2018, 12, 23)) == "full match" assert test(datetime(2018, 1, 2)) == "1/2 in 2018" assert test(datetime(2017, 1, 2, 3, 4, 5)) == "any datetime" assert test(11) == "not a datetime"
def test_wild_dicts(): data = [ { "type": "dog", "dog-name": "fuffy", "info": { "age": 2 } }, { "type": "pet", "dog-name": "puffy", "info": { "age": 1 } }, { "type": "cat", "cat-name": "buffy", "cat-info": { "age": 3 } }, ] ages = [ ~(caseof(row) | m({_: { "age": int }}) >> (lambda field, age: age)) for row in data ] average_age = sum(ages) / len(ages) assert average_age == (2 + 1 + 3) / 3 names = [ ~(caseof(row) | m({ "type": _, _: str }) >> (lambda type, name_field, name: name)) for row in data ] assert names == ["fuffy", "puffy", "buffy"]
def parser(exp): return ~( caseof(exp) | m(3) >> "the integer 3" | m(float) >> "any float number" | m(int) >> "any integer" | m("ciao") >> "the string ciao" | m(dict) >> "any dictionary" | m(str) >> "any string" | m((int, int)) >> "a tuple made of two ints" | m([1]) >> "the list [1]" | m([1, 2, 3]) >> "the list [1, 2, 3]" | m([1, _, 3]) >> "the list [1, _, 3]" | m((str, str)) >> (lambda a, b: "%s %s" % (a, b)) | m([1, 2, _]) >> (lambda x: "the list [1, 2, _]") | m([1, 2, 4]) >> "the list [1, 2, 4]" # this can never be matched | m([1, [2, _], _]) >> (lambda a, b: "[1, [2, %s], %s]" % (a, b)))
def test_with_xobject_action(): pet = {"type": "dog", "details": {"age": 3}} assert ~(caseof(pet) | m({"details": {"age": _}}) >> X) == 3 assert ~(caseof(pet) | m({_: {"age": _}}) >> X[0].upper()) == "DETAILS"
def test_xfunction_action(): @xfunction def add(a, b): return a + b assert ~(caseof([1, "b", 2]) | m(_, "b", _) >> add(X[0], X[1] + 1)) == 4
def test_lambda_cond(): cond = lambda x: x < 10 assert ~(caseof(3) | m(cond) >> "action" | _ >> "else") == "action" assert ~(caseof(11) | m(cond) >> "action1" | _ >> "else") == "else"
def f(x): return ~(caseof(x) | m(lambda x: x % 2 == 0) >> (lambda x: "even %d" % x) | m(lambda x: x % 2 != 0) >> (lambda x: "odd %d" % x))
def f(var): return ~(caseof(var) | m(pattern1) >> repack | m(pattern2) >> repack | _ >> (False, []))
def fib(n): return ~(caseof(n) | m(1) >> 1 | m(2) >> 1 | _ >> (lambda x: fib(x - 1) + fib(x - 2)))
def test_slide1(): _input = [1, 2, 3] pattern = [1, _, 3] action = lambda x: "it's {}".format(x) assert ~(caseof(_input) | m(pattern) >> action) == "it's 2"
def myzip(a, b): return ~(caseof((a, b)) | m(([], [])) >> [] | m(([_, TAIL], [_, TAIL])) >> (lambda ha, ta, hb, tb: [(ha, hb)] + myzip(ta, tb)))
def lisp(exp): return ~(caseof(exp) | m(int) >> (lambda x: x) | m(callable) >> (lambda x: x) | m(callable, REST) >> (lambda f, rest: f(*map(lisp, rest))) | m(tuple) >> (lambda t: list(map(lisp, t))))