python pattern_终于Python的 Pattern Match要来了!!

import array

import collections.abc

import dataclasses

import sys

from typing import Dict, Optional

import pytest # type: ignore

from patma import *

def checks(pat: Pattern, x: object) -> Optional[Dict[str, object]]:

"""Compare pat.match(x) the code generated by pat.translate().If they match, return whatever pat.match() returned."""

match = pat.match(x)

ns = {

"X": x,

"Sequence": collections.abc.Sequence,

"Mapping": collections.abc.Mapping,

"_Nope": object(), # Used for "attribute doesn't exist"

__name__: sys.modules[__name__],

}

res = eval(pat.translate("X"), ns)

if "__builtins__" in ns:

del ns["__builtins__"] # We don't need this for the comparison

if not res:

assert match is None

return match

assert match is not None

for key, value in match.items():

assert key in ns

assert ns[key] == value

assert type(ns[key]) == type(value)

return match

@dataclasses.dataclass

class MyClass:

x: int

y: str

# NOTE: in 3.10 dataclasses will have this by default

__match_args__ = ["x", "y"]

def test_value_pattern() -> None:

# case 42:

pat = ValuePattern(42)

assert checks(pat, 42) == {}

assert checks(pat, 0) is None

assert checks(pat, 42.0) == {}

assert checks(pat, "42") is None

def test_float_value_pattern() -> None:

# case 42.0:

pat = ValuePattern(42.0)

assert checks(pat, 42.0) == {}

assert checks(pat, 42) == {}

assert checks(pat, 0.0) is None

assert checks(pat, 0) is None

def test_or_pattern() -> None:

# case 1|2|3:

pat = OrPattern([ValuePattern(i) for i in [1, 2, 3]])

assert checks(pat, 1) == {}

assert checks(pat, 2) == {}

assert checks(pat, 3) == {}

assert checks(pat, 3.0) == {}

assert checks(pat, 0) is None

assert checks(pat, 4) is None

assert checks(pat, "1") is None

def test_fancy_or_pattern() -> None:

# case [1, 2] | [3, 4]:

pat = OrPattern(

[

SequencePattern([ValuePattern(1), ValuePattern(2)]),

SequencePattern([ValuePattern(3), ValuePattern(4)]),

]

)

assert checks(pat, [1, 2]) == {}

assert checks(pat, [3, 4]) == {}

assert checks(pat, 42) is None

assert checks(pat, [2, 3]) is None

assert checks(pat, [1, 2, 3]) is None

assert checks(pat, [1, 2.0]) == {}

def test_capture_pattern() -> None:

# case x:

pat = CapturePattern("x")

assert checks(pat, 42) == {"x": 42}

assert checks(pat, (1, 2)) == {"x": (1, 2)}

assert checks(pat, None) == {"x": None}

def test_wildcard_pattern() -> None:

# case _:

pat = WildcardPattern()

assert checks(pat, 42) == {}

assert checks(pat, None) == {}

assert checks(pat, (1, 2)) == {}

def test_sequence_pattern() -> None:

# case (x, y, z):

pat = SequencePattern([CapturePattern(s) for s in "xyz"])

assert checks(pat, (1, 2, 3)) == {"x": 1, "y": 2, "z": 3}

assert checks(pat, (1, 2)) is None

assert checks(pat, (1, 2, 3, 4)) is None

assert checks(pat, 123) is None

# Check that character/byte strings don't match sequences

assert pat.match("abc") is None # TODO: translate should disallow strings

assert pat.match(b"abc") is None # TODO: translate ditto

assert pat.match(array.array("b", b"abc")) is None # TODO: translate ditto

## assert checks(pat, memoryview(b'abc')) is None

## assert checks(pat, bytearray(b'abc')) is None

def test_mapping_pattern() -> None:

# case {"x": x, "y": "z": z}:

pat = MappingPattern(

{

"x": CapturePattern("x"),

"y": ValuePattern("y"),

"z": CapturePattern("z"),

}

)

assert checks(pat, {"x": "x", "y": "y", "z": "z"}) == {"x": "x", "z": "z"}

assert checks(pat, {"x": "x", "y": "y", "z": "z", "a": "a"}) == {"x": "x", "z": "z"}

assert checks(pat, {"x": "x", "y": "yy", "z": "z", "a": "a"}) is None

assert checks(pat, {"x": "x", "y": "y"}) is None

def test_class_pattern() -> None:

# case MyClass(xx: int, y='hello'):

vxx = CapturePattern("xx")

hello = ValuePattern("hello")

pat = ClassPattern(MyClass, [vxx], {"y": hello})

assert checks(pat, MyClass(42, "hello")) == {"xx": 42}

def test_walrus_pattern() -> None:

# case x := (p, q):

pat = WalrusPattern("x", SequencePattern([CapturePattern(s) for s in "pq"]))

assert checks(pat, (1, 2)) == {"p": 1, "q": 2, "x": (1, 2)}

assert checks(pat, [1, 2]) == {"p": 1, "q": 2, "x": [1, 2]}

assert checks(pat, 12) is None

assert checks(pat, (1, 2, 3)) is None

def test_bindings() -> None:

p: Pattern = ValuePattern(42)

assert p.bindings() == p.bindings(False) == set()

p = OrPattern(

[ValuePattern(1), ValuePattern(2), ValuePattern(3)]

)

assert p.bindings() == p.bindings(False) == set()

p = WildcardPattern()

assert p.bindings() == p.bindings(False) == set()

p = CapturePattern("abc")

assert p.bindings() == p.bindings(False) == {"abc"}

p = OrPattern([CapturePattern("a"), CapturePattern("a")])

assert p.bindings() == p.bindings(False) == {"a"}

p = OrPattern([CapturePattern("a"), ValuePattern("a")])

assert p.bindings(False) == {"a"}

with pytest.raises(TypeError):

p.bindings()

p = SequencePattern([CapturePattern("a"), CapturePattern("b")])

assert p.bindings() == p.bindings(False) == {"a", "b"}

p = SequencePattern([CapturePattern("a"), CapturePattern("a")])

assert p.bindings(False) == {"a"}

with pytest.raises(TypeError):

p.bindings()

p = MappingPattern({"k": CapturePattern("a"), "l": CapturePattern("b")})

assert p.bindings() == p.bindings(False) == {"a", "b"}

p = MappingPattern({"k": CapturePattern("a"), "l": CapturePattern("a")})

assert p.bindings(False) == {"a"}

with pytest.raises(TypeError):

p.bindings()

p = ClassPattern(MyClass, [CapturePattern("x")], {"y": CapturePattern("y")})

assert p.bindings() == p.bindings(False) == {"x", "y"}

p = ClassPattern(MyClass, [CapturePattern("x"), CapturePattern("x")], {})

assert p.bindings(False) == {"x"}

with pytest.raises(TypeError):

p.bindings()

p = ClassPattern(

MyClass, [], {"x": CapturePattern("x"), "y": CapturePattern("x")}

)

assert p.bindings(False) == {"x"}

with pytest.raises(TypeError):

p.bindings()

p = ClassPattern(MyClass, [CapturePattern("x")], {"y": CapturePattern("x")})

assert p.bindings(False) == {"x"}

with pytest.raises(TypeError):

p.bindings()

p = WalrusPattern("a", CapturePattern("b"))

assert p.bindings() == p.bindings(False) == {"a", "b"}

p = WalrusPattern("a", CapturePattern("a"))

assert p.bindings(False) == {"a"}

with pytest.raises(TypeError):

p.bindings()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值