TypeScript's ts-pattern for Python - powerful, type-safe pattern matching with an expressive API
Project description
match-expression
A Python implementation of TypeScript's 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.10+ type system features
Installation
pip install match-expression
Quick Start
from typing import Literal
from match_expression 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
from typing import Literal
from match_expression 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
from match_expression 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
from match_expression 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:
from match_expression 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
How It Works
Type System Design
The library uses Python's powerful type system with TypeVars to ensure type safety:
V: The type of the matched valueP: The narrowed type after pattern matchingR: The return type of the first branchUR: Union of return types from multiple branches
This design enables:
- Type narrowing: In each
whenbranch, the value is narrowed to the specific matched type - Return type union: Different branches can return different types, and the final type is their union
- Exhaustiveness checking: The type system ensures all possible cases are handled
Example Type Flow
match(value: Dog | Cat | Bird) # V = Dog | Cat | Bird
.case(Dog, lambda d: 123) # P = Dog, R = int
.case(Cat, lambda c: "hello") # P = Cat, UR = str
.case(Bird, lambda b: True) # P = Bird, UR = bool
.exhaustive() # Returns: int | str | bool
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:
# Install pyright
pip install pyright
# Type check your code
pyright your_file.py
Contributing
Contributions are welcome! Here's how to get started:
- Clone the repository
git clone https://github.com/qodot/py-pattern.git
cd py-pattern
- Install development dependencies
uv sync --dev
- Run tests
uv run pytest
- Type check
uv run pyright src/ tests/
Comparison with Alternatives
| Feature | match-expression | Python match/case | Traditional if/elif |
|---|---|---|---|
| Expression-based | ✅ | ❌ | ❌ |
| Type inference | ✅ | Partial | ❌ |
| Exhaustiveness check | ✅ | ❌ | ❌ |
| Chainable API | ✅ | ❌ | ❌ |
| Runtime overhead | Minimal | None | None |
Requirements
- Python 3.10 or higher
- No external dependencies
License
MIT License - see LICENSE file for details
Acknowledgments
This library is inspired by the excellent ts-pattern library for TypeScript. We aim to bring the same level of type safety and expressiveness to Python.
Resources
- TypeScript ts-pattern - The original inspiration
- PEP 622 - Structural Pattern Matching in Python
- Python Type Hints - Python typing module documentation
Made with ❤️ for the Python community
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file match_expression-0.1.0.tar.gz.
File metadata
- Download URL: match_expression-0.1.0.tar.gz
- Upload date:
- Size: 7.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b87823b90294e94ab385e6e72887d6181850a9978f4a4d9aa7c563c6fc87f92
|
|
| MD5 |
2892e87f803f63064629c0b9d1161a23
|
|
| BLAKE2b-256 |
45422146de581c521d5ef4675b693ff57e2a4355e6d44fe3960854849f12c606
|
File details
Details for the file match_expression-0.1.0-py3-none-any.whl.
File metadata
- Download URL: match_expression-0.1.0-py3-none-any.whl
- Upload date:
- Size: 5.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
530e04eb988517fb7ca02e3400d6df736ad5f58feb5cb072b0225c695def4f35
|
|
| MD5 |
012b54496e9946acb5e1d0c06c6f7b10
|
|
| BLAKE2b-256 |
90c92d15f15599b86d49d42fa72f69cc876b03eb1e6b9e85705a8c2f2f185494
|