Skip to main content

Typed protocols with runtime validation and structural typing

Project description

TypedProtocol

Python 3.12+ License: MIT

Typed protocols with runtime validation and structural typing for Python

TypedProtocol provides a way to define and validate protocols (interfaces) in Python with runtime type checking. It extends Python's standard typing.Protocol by enforcing type annotations at class definition time and performing structural subtyping checks.

Features

  • Type Enforcement: All protocol members require type annotations
  • Runtime Validation: Structural subtyping checks at runtime with issubclass()
  • Generic Support: Support for generic protocols with TypeVar unification
  • Protocol Inheritance: Inheritance between protocols
  • Type Checking: Method signatures, return types, and parameter validation
  • Minimal Overhead: Type checking only happens during issubclass() calls

Installation

pip install typedprotocol

Quick Start

from typedprotocol import TypedProtocol

# Define a protocol
class Drawable(TypedProtocol):
    x: int
    y: int

    def draw(self) -> None: ...
    def move(self, dx: int, dy: int) -> None: ...

# Implement the protocol
class Circle:
    x: int
    y: int
    radius: float  # Extra fields are allowed

    def __init__(self, x: int, y: int, radius: float):
        self.x = x
        self.y = y
        self.radius = radius

    def draw(self) -> None:
        print(f"Drawing circle at ({self.x}, {self.y})")

    def move(self, dx: int, dy: int) -> None:
        self.x += dx
        self.y += dy

# Check protocol compliance
assert issubclass(Circle, Drawable)

Generic Protocols

from typedprotocol import TypedProtocol
from typing import TypeVar

T = TypeVar('T')

class Container(TypedProtocol[T]):
    def add(self, item: T) -> None: ...
    def get(self) -> T: ...

class StringContainer:
    def __init__(self):
        self.items = []

    def add(self, item: str) -> None:
        self.items.append(item)

    def get(self) -> str:
        return self.items[0] if self.items else ""

# Test protocol compliance and implementation
assert issubclass(StringContainer, Container)

Protocol Inheritance

from typedprotocol import TypedProtocol

class Drawable(TypedProtocol):
    x: int
    y: int
    def draw(self) -> None: ...
    def move(self, dx: int, dy: int) -> None: ...

class Serializable(TypedProtocol):
    def to_dict(self) -> dict: ...

class PersistentDrawable(Drawable, Serializable):
    """Protocol combining drawing and serialization"""
    pass

class SmartCircle:
    x: int
    y: int
    radius: float

    def __init__(self, x: int, y: int, radius: float):
        self.x = x
        self.y = y
        self.radius = radius

    def draw(self) -> None:
        print(f"Drawing at ({self.x}, {self.y})")

    def move(self, dx: int, dy: int) -> None:
        self.x += dx
        self.y += dy

    def to_dict(self) -> dict:
        return {"x": self.x, "y": self.y, "radius": self.radius}

assert issubclass(SmartCircle, PersistentDrawable)

Async Method Support

from typedprotocol import TypedProtocol

class AsyncProcessor(TypedProtocol):
    async def process(self, data: bytes) -> str: ...

class MyProcessor:
    async def process(self, data: bytes) -> str:
        return data.decode()

assert issubclass(MyProcessor, AsyncProcessor)

Key Differences from typing.Protocol

Feature typing.Protocol TypedProtocol
Type annotation enforcement Optional Required
Runtime type checking Basic Enhanced
Generic protocol support Limited With unification
Instantiation prevention No Yes
Method signature validation Basic Parameter/return types
Protocol inheritance restrictions None Protocol-only inheritance

Required Annotations

from typedprotocol import TypedProtocol

# This will raise TypeError at class definition time
class BadProtocol(TypedProtocol):
    unannotated_field = "invalid"  # Missing type annotation

Type Checking

from typedprotocol import TypedProtocol

class DataProcessor(TypedProtocol):
    def process(self, data: bytes) -> str: ...

class BadImplementation:
    def process(self, data: str) -> str:  # Wrong parameter type
        return data

# This should return False due to wrong parameter type
assert not issubclass(BadImplementation, DataProcessor)

Requirements

  • Python 3.12+
  • No external dependencies

License

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog

0.1.0 (2024-12-19)

  • Initial release
  • Core TypedProtocol implementation
  • Generic protocol support

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

typedprotocol-0.1.0.tar.gz (44.6 kB view details)

Uploaded Source

Built Distribution

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

typedprotocol-0.1.0-py3-none-any.whl (9.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: typedprotocol-0.1.0.tar.gz
  • Upload date:
  • Size: 44.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for typedprotocol-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0a59e4b8469701adee48da3018733b2b8957e1d0ac8fd49a3655b5ff1aecee60
MD5 489f1f956086a59a88825ca79e23c528
BLAKE2b-256 4f922b12032171b1ebbbed64c37abde339e69c13d2b43c0b96e4c480e407b126

See more details on using hashes here.

Provenance

The following attestation bundles were made for typedprotocol-0.1.0.tar.gz:

Publisher: publish.yml on okanakbulut/typedprotocol

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

  • Download URL: typedprotocol-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for typedprotocol-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 671f8565a69db6007d03d84b6cd507b20fe259e82bcf275eefaef1b4d3c71d9b
MD5 861250498a8888dde41f3841c4373297
BLAKE2b-256 db5ab7b78fbe0408af02444e9438a138fee6db8b3e7d12ef1223b8e866ce34cb

See more details on using hashes here.

Provenance

The following attestation bundles were made for typedprotocol-0.1.0-py3-none-any.whl:

Publisher: publish.yml on okanakbulut/typedprotocol

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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