# match-expression
A Python implementation of TypeScript's [ts-pattern](https://github.com/gvergnaud/ts-pattern), bringing powerful, type-safe pattern matching to Python with an expressive, chainable API.
## Features
- **Chainable API**: Intuitive `match(value).case(pattern, then).exhaustive()` syntax
- **Type-safe**: Full type inference support with pyright/mypy
- **Exhaustiveness checking**: Ensures all cases are handled at compile time
- **Zero dependencies**: Lightweight and fast
- **Pythonic**: Leverages Python 3.12+ type system features
## Installation
```bash
pip install match_expression
```
## Quick Start
```python
from typing import Literal
from py_pattern import match
# Literal type matching
def process_status(status: Literal["pending", "success", "error"]) -> int:
return (
match(status)
.case("pending", 0)
.case("success", 1)
.case("error", -1)
.exhaustive()
)
# Type matching with classes
class Dog:
def bark(self) -> str:
return "Woof!"
class Cat:
def meow(self) -> str:
return "Meow!"
def handle_animal(animal: Dog | Cat) -> str:
return (
match(animal)
.case(Dog, lambda d: d.bark())
.case(Cat, lambda c: c.meow())
.exhaustive()
)
```
## Examples
### Literal Type Matching
```python
from typing import Literal
from py_pattern import match
type Platform = Literal["web", "mobile", "desktop"]
def get_app_name(platform: Platform) -> str:
return (
match(platform)
.case("web", "Web Application")
.case("mobile", "Mobile App")
.case("desktop", "Desktop Software")
.exhaustive()
)
# Type checker knows all cases are covered!
```
### Class Type Matching
```python
from py_pattern import match
class Success:
def __init__(self, value: str):
self.value = value
class Error:
def __init__(self, message: str):
self.message = message
def handle_result(result: Success | Error) -> str:
return (
match(result)
.case(Success, lambda s: f"Success: {s.value}")
.case(Error, lambda e: f"Error: {e.message}")
.exhaustive()
)
```
### Using `otherwise` for Default Cases
```python
from py_pattern import match
def classify_number(n: int) -> str:
return (
match(n)
.case(0, "zero")
.case(1, "one")
.case(2, "two")
.otherwise("many")
)
```
### Mixed Return Types
The library correctly infers union return types:
```python
from py_pattern import match
def process(value: int | str) -> int | str:
return (
match(value)
.case(int, lambda i: i * 2) # Returns int
.case(str, lambda s: s.upper()) # Returns str
.exhaustive()
)
# Type is inferred as: int | str
```
## API Reference
### `match(value: V) -> Match[V]`
Starts a pattern matching chain.
### `.case(pattern: P, then: R) -> Case[V, P, R]`
Matches against a pattern. If the pattern matches, executes `then`.
- `pattern`: A value to match against (for literals) or a type (for isinstance checks)
- `then`: The value to return or a function to execute with the matched value
### `.exhaustive() -> R`
Ensures all cases are handled. Raises `ExhaustiveError` if not all cases are covered.
### `.otherwise(default: R) -> R`
Provides a default value for unmatched cases.
## Type Checking
The library is designed to work with type checkers like pyright and mypy:
```bash
# Install pyright
pip install pyright
# Type check your code
pyright your_file.py
```
## Contributing
Contributions are welcome! Here's how to get started:
1. Clone the repository
```bash
git clone https://github.com/qodot/match-expression.git
cd match-expression
```
2. Install development dependencies
```bash
uv sync --dev
```
3. Run tests
```bash
uv run pytest
```
4. Type check
```bash
uv run pyright src/ tests/
```
## Requirements
- Python 3.12 or higher
- No external dependencies
## License
MIT License - see LICENSE file for details
Raw data
{
"_id": null,
"home_page": null,
"name": "match-expression",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.12",
"maintainer_email": null,
"keywords": "exhaustive, functional, match, pattern, pattern-matching, ts-pattern, type-safe, typescript",
"author": null,
"author_email": "Qodot <qodot@example.com>",
"download_url": "https://files.pythonhosted.org/packages/e5/a7/cb495fa4e576640629d8e2a2e798f4594985df8029fe4c3e3fa6d251e858/match_expression-0.1.2.tar.gz",
"platform": null,
"description": "# match-expression\n\nA Python implementation of TypeScript's [ts-pattern](https://github.com/gvergnaud/ts-pattern), bringing powerful, type-safe pattern matching to Python with an expressive, chainable API.\n\n## Features\n\n- **Chainable API**: Intuitive `match(value).case(pattern, then).exhaustive()` syntax\n- **Type-safe**: Full type inference support with pyright/mypy\n- **Exhaustiveness checking**: Ensures all cases are handled at compile time\n- **Zero dependencies**: Lightweight and fast\n- **Pythonic**: Leverages Python 3.12+ type system features\n\n## Installation\n\n```bash\npip install match_expression\n```\n\n## Quick Start\n\n```python\nfrom typing import Literal\nfrom py_pattern import match\n\n# Literal type matching\ndef process_status(status: Literal[\"pending\", \"success\", \"error\"]) -> int:\n return (\n match(status)\n .case(\"pending\", 0)\n .case(\"success\", 1)\n .case(\"error\", -1)\n .exhaustive()\n )\n\n# Type matching with classes\nclass Dog:\n def bark(self) -> str:\n return \"Woof!\"\n\nclass Cat:\n def meow(self) -> str:\n return \"Meow!\"\n\ndef handle_animal(animal: Dog | Cat) -> str:\n return (\n match(animal)\n .case(Dog, lambda d: d.bark())\n .case(Cat, lambda c: c.meow())\n .exhaustive()\n )\n```\n\n## Examples\n\n### Literal Type Matching\n\n```python\nfrom typing import Literal\nfrom py_pattern import match\n\ntype Platform = Literal[\"web\", \"mobile\", \"desktop\"]\n\ndef get_app_name(platform: Platform) -> str:\n return (\n match(platform)\n .case(\"web\", \"Web Application\")\n .case(\"mobile\", \"Mobile App\")\n .case(\"desktop\", \"Desktop Software\")\n .exhaustive()\n )\n\n# Type checker knows all cases are covered!\n```\n\n### Class Type Matching\n\n```python\nfrom py_pattern import match\n\nclass Success:\n def __init__(self, value: str):\n self.value = value\n\nclass Error:\n def __init__(self, message: str):\n self.message = message\n\ndef handle_result(result: Success | Error) -> str:\n return (\n match(result)\n .case(Success, lambda s: f\"Success: {s.value}\")\n .case(Error, lambda e: f\"Error: {e.message}\")\n .exhaustive()\n )\n```\n\n### Using `otherwise` for Default Cases\n\n```python\nfrom py_pattern import match\n\ndef classify_number(n: int) -> str:\n return (\n match(n)\n .case(0, \"zero\")\n .case(1, \"one\")\n .case(2, \"two\")\n .otherwise(\"many\")\n )\n```\n\n### Mixed Return Types\n\nThe library correctly infers union return types:\n\n```python\nfrom py_pattern import match\n\ndef process(value: int | str) -> int | str:\n return (\n match(value)\n .case(int, lambda i: i * 2) # Returns int\n .case(str, lambda s: s.upper()) # Returns str\n .exhaustive()\n )\n # Type is inferred as: int | str\n```\n\n## API Reference\n\n### `match(value: V) -> Match[V]`\nStarts a pattern matching chain.\n\n### `.case(pattern: P, then: R) -> Case[V, P, R]`\nMatches against a pattern. If the pattern matches, executes `then`.\n\n- `pattern`: A value to match against (for literals) or a type (for isinstance checks)\n- `then`: The value to return or a function to execute with the matched value\n\n### `.exhaustive() -> R`\nEnsures all cases are handled. Raises `ExhaustiveError` if not all cases are covered.\n\n### `.otherwise(default: R) -> R`\nProvides a default value for unmatched cases.\n\n## Type Checking\n\nThe library is designed to work with type checkers like pyright and mypy:\n\n```bash\n# Install pyright\npip install pyright\n\n# Type check your code\npyright your_file.py\n```\n\n## Contributing\n\nContributions are welcome! Here's how to get started:\n\n1. Clone the repository\n```bash\ngit clone https://github.com/qodot/match-expression.git\ncd match-expression\n```\n\n2. Install development dependencies\n```bash\nuv sync --dev\n```\n\n3. Run tests\n```bash\nuv run pytest\n```\n\n4. Type check\n```bash\nuv run pyright src/ tests/\n```\n\n## Requirements\n\n- Python 3.12 or higher\n- No external dependencies\n\n## License\n\nMIT License - see LICENSE file for details",
"bugtrack_url": null,
"license": "MIT",
"summary": "A Python implementation of TypeScript's ts-pattern, type-safe pattern matching with an expressive API",
"version": "0.1.2",
"project_urls": {
"Bug Tracker": "https://github.com/qodot/match-expression/issues",
"Homepage": "https://github.com/qodot/match-expression",
"Repository": "https://github.com/qodot/match-expression"
},
"split_keywords": [
"exhaustive",
" functional",
" match",
" pattern",
" pattern-matching",
" ts-pattern",
" type-safe",
" typescript"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "3457838b51851dd08977295dad2b9ab68872fe0c7f99a90393263e30acb1987c",
"md5": "afbfa567bc2bc77ee75f4b938d78eb18",
"sha256": "62f3847495ae2a6c6c07c2ed4643c3683796c250bd1ed4a0043e1bacaa7ed794"
},
"downloads": -1,
"filename": "match_expression-0.1.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "afbfa567bc2bc77ee75f4b938d78eb18",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.12",
"size": 4751,
"upload_time": "2025-08-17T15:36:22",
"upload_time_iso_8601": "2025-08-17T15:36:22.673688Z",
"url": "https://files.pythonhosted.org/packages/34/57/838b51851dd08977295dad2b9ab68872fe0c7f99a90393263e30acb1987c/match_expression-0.1.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "e5a7cb495fa4e576640629d8e2a2e798f4594985df8029fe4c3e3fa6d251e858",
"md5": "34627ec514bc4ad21b20f9a283284315",
"sha256": "e1e5fe34ac3f52bb41f2338b6c4c39e4a88416ef1c5762c06c906042a5939003"
},
"downloads": -1,
"filename": "match_expression-0.1.2.tar.gz",
"has_sig": false,
"md5_digest": "34627ec514bc4ad21b20f9a283284315",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.12",
"size": 5121,
"upload_time": "2025-08-17T15:36:23",
"upload_time_iso_8601": "2025-08-17T15:36:23.941195Z",
"url": "https://files.pythonhosted.org/packages/e5/a7/cb495fa4e576640629d8e2a2e798f4594985df8029fe4c3e3fa6d251e858/match_expression-0.1.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-17 15:36:23",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "qodot",
"github_project": "match-expression",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "match-expression"
}