{"id":16937542,"url":"https://github.com/megaing/pattern-matching","last_synced_at":"2025-04-11T19:13:42.792Z","repository":{"id":57451156,"uuid":"307090680","full_name":"MegaIng/pattern-matching","owner":"MegaIng","description":"Black magic pattern matching","archived":false,"fork":false,"pushed_at":"2020-11-09T19:55:12.000Z","size":73,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-11T19:13:37.023Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MegaIng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-10-25T12:09:22.000Z","updated_at":"2024-09-21T10:16:02.000Z","dependencies_parsed_at":"2022-09-26T17:31:29.301Z","dependency_job_id":null,"html_url":"https://github.com/MegaIng/pattern-matching","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MegaIng%2Fpattern-matching","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MegaIng%2Fpattern-matching/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MegaIng%2Fpattern-matching/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MegaIng%2Fpattern-matching/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MegaIng","download_url":"https://codeload.github.com/MegaIng/pattern-matching/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248465344,"owners_count":21108244,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T20:59:44.448Z","updated_at":"2025-04-11T19:13:42.771Z","avatar_url":"https://github.com/MegaIng.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pattern matching PEP 634\n\nThis is a python package implementing pattern-matching similar to what [PEP-634](https://www.python.org/dev/peps/pep-0634/) proposes.\n\n## Installation\n\nUse the package manager [pip](https://pip.pypa.io/en/stable/) to install pattern-matching-pep634.\n\n```bash\npip install pattern-matching-pep634\n```\n\n## Usage\n\nThere are 4 different implementations of pattern matching in here.\n\nThe safest one is this:\n```python\nfrom pattern_matching import Matcher\n\nmatch = Matcher(Click, KeyPress, Quit)\n\nwith match(event.get()) as m:\n    if m.case('Click(position=(x, y))'):\n        handle_click_at(m.x, m.y)\n    elif m.case('KeyPress(key_name=\"Q\") | Quit()'):\n        m.game.quit()\n    elif m.case('KeyPress(key_name=\"up arrow\")'):\n        m.game.go_north()\n    elif m.case('KeyPress()'):\n        pass # Ignore other keystrokes\n    elif m.case('other_event'):\n        raise ValueError(f\"Unrecognized event: {m.other_event}\")\n```\n\n(This is based on an example in [PEP-636](https://www.python.org/dev/peps/pep-0636/))\n\nNote how you have to specify which names you will be using, and how you always have to use `m.` to access the capture values.\nThis is the so called `no_magic` implementation. This implementation will work even in Python3.7 and other implementations than CPython that support the same features as 3.7\n\n#### auto_lookup\n\nIf you don't want to specify which classes you will be using, but don't want to have the pattern matching messing with the locals, you can use `auto_lookup`\n\n```python\nfrom pattern_matching.auto_lookup import match\n\n\nwith match(event.get()) as m:\n    if m.case('Click(position=(x, y))'):\n        handle_click_at(m.x, m.y)\n    elif m.case('KeyPress(key_name=\"Q\") | Quit()'):\n        m.game.quit()\n    elif m.case('KeyPress(key_name=\"up arrow\")'):\n        m.game.go_north()\n    elif m.case('KeyPress()'):\n        pass # Ignore other keystrokes\n    elif m.case('other_event'):\n        raise ValueError(f\"Unrecognized event: {m.other_event}\")\n```\n\nYou still have to use `m.`, but at least you don't have to duplicate the class names and carry around a `Matcher` instance.\n\nNote that this might have weird edge cases and fail for some reason sometimes. (Most notably conflict between what you think is visible in a function vs. what really is)\n\n#### injecting\n\nThis is for those who don't want to type `m.` everywhere.\n```python\nfrom pattern_matching.injecting import match, case\n\n\nwith match(event.get()):\n    if case('Click(position=(x, y))'):\n        handle_click_at(x, y)\n    elif case('KeyPress(key_name=\"Q\") | Quit()'):\n        game.quit()\n    elif case('KeyPress(key_name=\"up arrow\")'):\n        game.go_north()\n    elif case('KeyPress()'):\n        pass # Ignore other keystrokes\n    elif case('other_event'):\n        raise ValueError(f\"Unrecognized event: {other_event}\")\n```\n\nThis will 'infect' the name space and put the captured names into it. It also does `auto_lookup`.\n\nThis is will only work on Python3.9. It might also randomly break with debuggers/coverage/tracing tools.\n\nNote that this heavily suffers from the problem of what locals are defined and what aren't, e.g. the problem of where names are looked up.\n\n\n#### full_magic\n\nThis is the one that is as close as possible to the syntax proposed in PEP-634\n\n```python\nfrom pattern_matching.full_magic import match\n\n\nwith match(event.get()):\n    if Click(position=(x, y)):\n        handle_click_at(x, y)\n    elif KeyPress(key_name=\"Q\") | Quit():\n        game.quit()\n    elif KeyPress(key_name=\"up arrow\"):\n        game.go_north()\n    elif KeyPress():\n        pass # Ignore other keystrokes\n    elif other_event:\n        raise ValueError(f\"Unrecognized event: {other_event}\")\n```\n\n(only differences to PEP-634 is `with match` instead of match, `if`/`elif` instead of `case` and `:=` instead of `as`)\n\nThis does source-code analysis to figure out what cases to take and which names do bind. This is also Python3.9 only, and might break with any minor release of python. But that is unlikely.\n\nNote: Sometimes, the small amount of optimization that python does can still break this:\n\n```python\nfrom pattern_matching.full_magic import match\n\n\nwith match(n):\n    if 1 | 2:\n        print(\"Smaller than three\")\n    elif 3:\n        print(\"Equal to three\")\n    elif _:\n        print(\"Bigger than three\")\n```\n\nPython's peephole optimizer will (normally) correctly figure out that only the first branch can be taken and throw away the rest of the code.\nThis means that `match` can not correctly jump to the other lines. To circumvent the optimizer, `c@` ('case') can be added to prevent the optimization\n\n```python\nfrom pattern_matching.full_magic import match\n\n\nwith match(n):\n    if c@ 1 | 2:\n        print(\"Smaller than three\")\n    elif c@ 3:\n        print(\"Equal to three\")\n    elif c@ _:\n        print(\"Bigger than three\")\n```\n This doesn't have to be done always, but it is a good first attempt if you get weird error messages.\n\n\n### Guards\n\nGuards are not directly implemented, but are supported via a simple `and` that can be added to a case:\n\n```python\nfrom pattern_matching.injecting import match, case\n\nwith match(p):\n    if case('(x, y)') and x == y:\n        print(\"X=Y, at\", x)\n    else:\n        print(\"Not on a diagonal\")\n```\n\nThis works similar for all options\n\n## License\n[MIT](https://choosealicense.com/licenses/mit/)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmegaing%2Fpattern-matching","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmegaing%2Fpattern-matching","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmegaing%2Fpattern-matching/lists"}