Metadata-Version: 2.5
Name: abcreg
Version: 0.2.0
Summary: Checked inheritance for Abstract Base Classes
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# ABCReg

ABCReg adds `AnnotatedABC`, `AnnotatedABCMeta`, and `AnnotatedProtocolMeta`, which provide additional interface checking at registration time to ensure that registered virtual and ordinary subclasses are valid.

Use ABCReg if you are designing a plugin API or any other interface that might be implemented by an end user.

## Defining the Interface

Use `AnnotatedABC` just like an ordinary `ABC`. Make sure to mark your API methods as abstract and provide type hints:

```Python
from abc import abstractmethod
from abcreg import AnnotatedABC

class Queryable(AnnotatedABC):
    @abstractmethod
    def query(self, **kwargs: object) -> str: ...
```

We recommend you use virtual inheritance:

```Python
@Queryable.register
class VirtualQueryProvider:
    def query(self, **kwargs: object) -> str:
        return "query result"

assert issubclass(VirtualQueryProvider, Queryable)
assert isinstance(VirtualQueryProvider(), Queryable)
```

But, regular inheritance will also work:

```Python
class QueryProvider(Queryable):
    def query(self, **kwargs: object) -> str:
        return "query result"

assert issubclass(QueryProvider, Queryable)
```

## Protocols (structural subtyping)

For structural subtyping with mypy, define a `Protocol` that uses `AnnotatedProtocolMeta`:

```Python
from typing import Protocol, runtime_checkable
from abcreg import AnnotatedProtocolMeta

@runtime_checkable
class LogHook(Protocol, metaclass=AnnotatedProtocolMeta):
    def handlemsg(self, msg: str) -> bool: ...

@LogHook.register
class LogWriter:
    def handlemsg(self, msg: str) -> bool:
        return True
```

Mypy accepts structural matches without registration. `@LogHook.register` still validates annotations at runtime and registers a virtual subclass.

## Requirements and Usage

Requires Python `3.10+`. With UV, require with `uv add abcreg`.

## Development

Pre-build checks:
```
uv sync --all-groups
uv run ruff check --fix
uv run ruff format --preview
uv run mypy --strict abcreg main.py tests/
```
