Compatibility#

Cross-version compatibility utilities for Python 3.9+ support. This module provides backports and compatibility shims for features introduced in newer Python versions.

Overview#

The compatibility module ensures your code works across different Python versions by:

  • Providing Self type hint for Python < 3.11

  • Implementing StrEnum for Python < 3.11

  • Automatically using native implementations when available

Quick Examples#

Self Type Hint#

Use Self for better type hints in methods that return the instance itself:

from core_mixins import Self

class Builder:
    def __init__(self) -> None:
        self.value = 0

    def add(self, amount: int) -> Self:
        """Returns self for method chaining."""
        self.value += amount
        return self

    def multiply(self, factor: int) -> Self:
        """Returns self for method chaining."""
        self.value *= factor
        return self

# Type checker knows the return type
result = Builder().add(5).multiply(2)  # type: Builder

Why use Self?

Before Python 3.11, you had to use string literals or type variables:

# Old way (Python < 3.11)
from typing import TypeVar

T = TypeVar('T', bound='Builder')

class Builder:
    def add(self: T, amount: int) -> T:  # Complex!
        return self

# New way (Python 3.11+, works in 3.9+ with core-mixins)
from core_mixins import Self

class Builder:
    def add(self, amount: int) -> Self:  # Simple!
        return self

StrEnum Usage#

Create string-based enumerations that work consistently across Python versions:

from core_mixins import StrEnum

class Status(StrEnum):
    """Order status enumeration."""
    PENDING = "pending"
    PROCESSING = "processing"
    COMPLETED = "completed"
    CANCELLED = "cancelled"

# Use as strings
status = Status.PENDING
print(status)  # "pending"
print(f"Status: {status}")  # "Status: pending"

# String comparison works
if status == "pending":
    print("Order is pending")

# Enum features
print(Status.PENDING.name)   # "PENDING"
print(Status.PENDING.value)  # "pending"
print(list(Status))  # [Status.PENDING, Status.PROCESSING, ...]

HTTP Status Example#

from core_mixins import StrEnum

class HTTPStatus(StrEnum):
    """HTTP status codes."""
    OK = "200"
    CREATED = "201"
    BAD_REQUEST = "400"
    UNAUTHORIZED = "401"
    NOT_FOUND = "404"
    SERVER_ERROR = "500"

def handle_response(status: HTTPStatus) -> str:
    """Handle HTTP response based on status."""
    if status == HTTPStatus.OK:
        return "Success"
    elif status in (HTTPStatus.BAD_REQUEST, HTTPStatus.UNAUTHORIZED):
        return "Client error"
    elif status == HTTPStatus.SERVER_ERROR:
        return "Server error"
    return "Unknown status"

# Usage
response_status = HTTPStatus.OK
print(handle_response(response_status))  # "Success"

Python Version Support#

Feature

Native In

Backported By

Self

Python 3.11+

typing_extensions

StrEnum

Python 3.11+

Custom implementation

The module automatically uses native implementations when running on Python 3.11+, ensuring optimal performance and compatibility.

API Reference#

Compatibility utilities for Python version differences.

class core_mixins.compatibility.StrEnum(new_class_name, /, names, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]#

Bases: str, ReprEnum

Enum where members are also (and must be) strings

Best Practices#

Import from core_mixins#

Always import compatibility features from core_mixins:

# ✓ Correct
from core_mixins import Self, StrEnum

# ✗ Avoid direct imports (may not exist in older Python)
from typing import Self  # Fails in Python < 3.11

Use Self for Fluent Interfaces#

Self is perfect for builder patterns and fluent APIs:

from core_mixins import Self

class QueryBuilder:
    def where(self, condition: str) -> Self:
        return self

    def order_by(self, field: str) -> Self:
        return self

    def limit(self, count: int) -> Self:
        return self

# Type-safe method chaining
query = QueryBuilder().where("active = true").order_by("name").limit(10)

Use StrEnum for Constants#

StrEnum is ideal for configuration values and constants:

from core_mixins import StrEnum

class Environment(StrEnum):
    DEVELOPMENT = "dev"
    STAGING = "staging"
    PRODUCTION = "prod"

class LogLevel(StrEnum):
    DEBUG = "DEBUG"
    INFO = "INFO"
    WARNING = "WARNING"
    ERROR = "ERROR"