Skip to main content

Safe boilerplate-free static regular expressions with MyPy support

Project description

re-static

Safe boilerplate-free static regular expressions with MyPy support

re-static provides a powerful way to work with regular expressions in Python that gives you:

  • Type safety: Named capture groups become typed attributes on result objects
  • IDE support: Full autocomplete and type checking for regex groups
  • Runtime safety: Compile-time validation of regex patterns
  • Zero runtime overhead: Patterns are compiled once at class definition time

Installation

pip install re-static

Requires Python 3.11+ and MyPy for full type checking support.

Quick Start

from re_static import StaticRegex

class EmailRegex(StaticRegex):
    REGEX = r"(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})"

# Now you get type-safe access to capture groups!
match = EmailRegex.search("Contact us at hello@example.com")
if match:
    print(f"Username: {match.username}")  # Type: str
    print(f"Domain: {match.domain}")      # Type: str

Features

All Standard Regex Methods

re-static supports all the standard regex matching methods:

class DigitsRegex(StaticRegex):
    REGEX = r"(?P<digits>\d+)"

# Match from start of string
result = DigitsRegex.match("123abc")

# Search anywhere in string
result = DigitsRegex.search("abc123def")

# Match entire string
result = DigitsRegex.fullmatch("123")

# Find all matches as a list
results = DigitsRegex.findall("123 456 789")

# Find all matches as an iterator
for result in DigitsRegex.finditer("123 456 789"):
    print(result.digits)

Type-Safe Optional Groups

Optional capture groups are correctly typed as str | None:

class OptionalRegex(StaticRegex):
    REGEX = r"(?P<required>\w+)(?P<optional>\d+)?"

match = OptionalRegex.match("hello123")
print(match.required)  # Type: str (always present)
print(match.optional)  # Type: str | None (might be None)

match = OptionalRegex.match("hello")
print(match.required)  # "hello"
print(match.optional)  # None

Position and Bounds Support

All methods support the standard pos and endpos parameters:

result = EmailRegex.search("prefix hello@example.com suffix", pos=7, endpos=25)

Regex Flags

You can specify regex flags using the REGEX_FLAGS class attribute:

import re

class CaseInsensitiveRegex(StaticRegex):
    REGEX = r"(?P<word>[a-z]+)"
    REGEX_FLAGS = re.IGNORECASE

match = CaseInsensitiveRegex.match("HELLO")  # Works!
print(match.word)  # "HELLO"

MyPy Integration

To get full type checking support, configure MyPy to use the re-static plugin by adding this to your pyproject.toml:

[tool.mypy]
plugins = ["re_static.mypy_plugin.plugin"]

With the plugin enabled, MyPy will:

  • Validate that your regex patterns are syntactically correct
  • Automatically infer types for named capture groups
  • Provide intelligent autocomplete in your IDE
  • Catch attempts to access non-existent groups at compile time
  • Enforce that regex group attributes are only accessed on instances, not classes

Advanced Usage

Complex Patterns

class LogLineRegex(StaticRegex):
    REGEX = r"(?P<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(?P<level>\w+)\] (?P<message>.*?)(?P<error_code> \(code: \d+\))?"

log_line = "2023-12-01 10:30:15 [ERROR] Database connection failed (code: 500)"
match = LogLineRegex.match(log_line)
if match:
    print(f"Time: {match.timestamp}")
    print(f"Level: {match.level}")
    print(f"Message: {match.message}")
    print(f"Error code: {match.error_code}")  # Optional group

Error Handling

If a regex pattern has syntax errors, they'll be caught at class definition time:

# This will raise a compile-time error:
class BadRegex(StaticRegex):
    REGEX = r"(?P<bad>[unclosed"  # SyntaxError!

Performance

  • Regex patterns are compiled once when the class is defined, not on each use
  • Basically zero runtime overhead compared to using re.compile() directly
  • Type checking happens at build time with MyPy, not at runtime

Development

This project uses modern Python development practices:

  • uv for dependency management
  • pytest for testing
  • mypy for type checking
  • ruff for linting and formatting

See development.md for detailed development instructions.

License

MIT License - see LICENSE for details.

Contributing

Contributions welcome! Please see our development guide and submit pull requests on GitHub.

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

re_static-0.1.0.tar.gz (58.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

re_static-0.1.0-py3-none-any.whl (8.4 kB view details)

Uploaded Python 3

File details

Details for the file re_static-0.1.0.tar.gz.

File metadata

  • Download URL: re_static-0.1.0.tar.gz
  • Upload date:
  • Size: 58.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.8.13

File hashes

Hashes for re_static-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f27874398bd3df0198b5d87ca8e6dd965d85906e01d413b84c1ed3e27494f3f9
MD5 5fdbc28f1535c1e9edb6e22a47c467be
BLAKE2b-256 505e32fcfdd3f1a8899cdff815f97328ce9444adfd3f642207677de59cd0f87a

See more details on using hashes here.

File details

Details for the file re_static-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: re_static-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.8.13

File hashes

Hashes for re_static-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 967b3ff1d81c21fffea2ae5d85b952db4f3aadab673f85333be3f560be6289cc
MD5 24deafc6b8ff434121144f2d5aeeb1da
BLAKE2b-256 2ef4d48cb8320d8dbe9fc70bd029050af4552498568b8740e99c0d2bbf4392b2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page