# Explicit Implementation
[](https://badge.fury.io/py/explicit-implementation)
[](https://pypi.org/project/explicit-implementation/)
[](https://opensource.org/licenses/MIT)
A Python library that provides explicit interface implementations with compile-time safety and clear separation between interface contracts and their implementations.
## Features
- **Explicit Interface Declarations**: Define clear interface contracts using abstract methods
- **Flexible Implementation**: Allow partial implementations by default, enforce completeness with `concrete=True`
- **Compile-time Safety**: Catch implementation errors at class definition time, not runtime
- **Multiple Interface Support**: Implement multiple interfaces in a single class
- **Interface Access Control**: Access implementations through specific interface views
- **Type Safety**: Full typing support with generics for better IDE experience
- **Diamond Inheritance**: Proper handling of complex inheritance patterns
## Installation
```bash
pip install explicit-implementation
```
## Quick Start
```python
from explicit_implementation import Interface, abstractmethod, implements
# Define an interface
class IDrawable(Interface):
@abstractmethod
def draw(self) -> str:
...
class IPrintable(Interface):
@abstractmethod
def print_info(self) -> str:
...
# Implement the interfaces explicitly
class Document(IDrawable, IPrintable):
def __init__(self, content: str):
self.content = content
@implements(IDrawable.draw)
def render_document(self) -> str:
return f"Drawing: {self.content}"
@implements(IPrintable.print_info)
def document_info(self) -> str:
return f"Document: {self.content}"
# Use the implementation
doc = Document("Hello World")
# Access through specific interfaces
drawable = doc.as_interface(IDrawable)
printable = doc.as_interface(IPrintable)
print(drawable.draw()) # "Drawing: Hello World"
print(printable.print_info()) # "Document: Hello World"
```
## Key Concepts
### Interface Declaration
Interfaces are defined by inheriting from `Interface` and using `@abstractmethod`:
```python
class IRepository(Interface):
@abstractmethod
def save(self, data: dict) -> bool:
...
@abstractmethod
def load(self, id: str) -> dict:
...
```
### Explicit Implementation
Use the `@implements` decorator to explicitly map interface methods to implementation methods:
```python
class DatabaseRepository(IRepository):
@implements(IRepository.save)
def save_to_database(self, data: dict) -> bool:
# Implementation here
return True
@implements(IRepository.load)
def load_from_database(self, id: str) -> dict:
# Implementation here
return {"id": id}
```
### Interface Access
Access implementations through specific interface views:
```python
repo = DatabaseRepository()
# Access through the IRepository interface
repository_interface = repo.as_interface(IRepository)
repository_interface.save({"name": "example"})
repository_interface.load("123")
```
### Concrete Classes
By default, partial implementations are allowed at class definition time. To enforce complete implementation:
```python
# This is allowed - partial implementation class definition
class PartialRepository(IRepository):
@implements(IRepository.save)
def save_to_database(self, data: dict) -> bool:
return True
# Missing IRepository.load implementation - class definition succeeds
# However, you still can't instantiate classes with unimplemented abstract methods
# partial = PartialRepository() # Raises TypeError at instantiation
# This will raise TypeError at class definition time
class ConcreteRepository(IRepository, concrete=True):
@implements(IRepository.save)
def save_to_database(self, data: dict) -> bool:
return True
# Missing IRepository.load implementation - TypeError at class definition!
```
## Advanced Usage
### Multiple Interface Implementation
```python
class IValidator(Interface):
@abstractmethod
def validate(self, data: str) -> bool:
...
class IFormatter(Interface):
@abstractmethod
def format(self, data: str) -> str:
...
class DataProcessor(IValidator, IFormatter):
@implements(IValidator.validate)
def check_data(self, data: str) -> bool:
return len(data) > 0
@implements(IFormatter.format)
def format_data(self, data: str) -> str:
return data.upper()
```
### Interface Inheritance
```python
class IBasic(Interface):
@abstractmethod
def basic_method(self) -> str:
...
class IExtended(IBasic):
@abstractmethod
def extended_method(self) -> int:
...
class Implementation(IExtended):
@implements(IBasic.basic_method)
def basic_impl(self) -> str:
return "basic"
@implements(IExtended.extended_method)
def extended_impl(self) -> int:
return 42
```
### Diamond Inheritance Patterns
In diamond inheritance, each interface path requires explicit implementation:
```python
class IBase(Interface):
@abstractmethod
def base_method(self) -> str:
...
class ILeft(IBase):
@abstractmethod
def left_method(self) -> int:
...
class IRight(IBase):
@abstractmethod
def right_method(self) -> bool:
...
class Diamond(ILeft, IRight):
# Can only implement base_method once for IBase
@implements(IBase.base_method)
def base_impl(self) -> str:
return "base"
@implements(ILeft.left_method)
def left_impl(self) -> int:
return 42
@implements(IRight.right_method)
def right_impl(self) -> bool:
return True
# Access base_method only through IBase interface
diamond = Diamond()
base_interface = diamond.as_interface(IBase)
print(base_interface.base_method()) # "base"
```
## Error Handling
The library provides clear error messages for common mistakes:
### Missing Implementation
By default, partial implementations are allowed:
```python
class Incomplete(IDrawable):
pass # Missing @implements for IDrawable.draw
# This is allowed by default - no error raised
```
To enforce complete implementation, use `concrete=True`:
```python
class Concrete(IDrawable, concrete=True):
pass # Missing @implements for IDrawable.draw
# Raises: TypeError at class definition time
```
### Invalid Implementation Target
```python
class Invalid(IDrawable):
@implements(IPrintable.print_info) # Wrong interface method
def some_method(self) -> str:
return "invalid"
# Raises: TypeError - method not in base interfaces
```
### Accessing Unimplemented Interface
```python
class Partial(IDrawable):
@implements(IDrawable.draw)
def draw_impl(self) -> str:
return "drawn"
partial = Partial()
# This will raise TypeError:
printable = partial.as_interface(IPrintable)
```
## Type Safety
The library provides full typing support:
```python
from typing import Protocol
def use_drawable(drawable: IDrawable) -> str:
return drawable.draw()
def process_document(doc: Document) -> tuple[str, str]:
drawable = doc.as_interface(IDrawable) # Type: IDrawable
printable = doc.as_interface(IPrintable) # Type: IPrintable
return drawable.draw(), printable.print_info()
```
## Comparison with ABC
| Feature | ABC | Explicit Implementation |
|---------|-----|------------------------|
| Method Names | Must match interface | Can be different |
| Interface Access | Direct method calls | Through `.as_interface()` |
| Multiple Interfaces | Name conflicts possible | Clean separation |
| Implementation Clarity | Implicit | Explicit with `@implements` |
| Error Detection | Runtime | Compile-time |
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Changelog
### 0.1.0
- Initial release
- Basic interface and implementation functionality
- Support for multiple interface implementation
- Diamond inheritance pattern support
- Full typing support
- Comprehensive test coverage
Raw data
{
"_id": null,
"home_page": null,
"name": "explicit-implementation",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "abc, explicit, implementation, interface, typing",
"author": null,
"author_email": "Binyamin Y Cohen <biny@xpo.dev>",
"download_url": "https://files.pythonhosted.org/packages/0f/b7/463e9f3fb89af47eb135e9ed19b111f61b0095b58077a7d19d0ec327bfb6/explicit_implementation-0.1.0.tar.gz",
"platform": null,
"description": "# Explicit Implementation\n\n[](https://badge.fury.io/py/explicit-implementation)\n[](https://pypi.org/project/explicit-implementation/)\n[](https://opensource.org/licenses/MIT)\n\nA Python library that provides explicit interface implementations with compile-time safety and clear separation between interface contracts and their implementations.\n\n## Features\n\n- **Explicit Interface Declarations**: Define clear interface contracts using abstract methods\n- **Flexible Implementation**: Allow partial implementations by default, enforce completeness with `concrete=True`\n- **Compile-time Safety**: Catch implementation errors at class definition time, not runtime\n- **Multiple Interface Support**: Implement multiple interfaces in a single class\n- **Interface Access Control**: Access implementations through specific interface views\n- **Type Safety**: Full typing support with generics for better IDE experience\n- **Diamond Inheritance**: Proper handling of complex inheritance patterns\n\n## Installation\n\n```bash\npip install explicit-implementation\n```\n\n## Quick Start\n\n```python\nfrom explicit_implementation import Interface, abstractmethod, implements\n\n# Define an interface\nclass IDrawable(Interface):\n @abstractmethod\n def draw(self) -> str:\n ...\n\nclass IPrintable(Interface):\n @abstractmethod\n def print_info(self) -> str:\n ...\n\n# Implement the interfaces explicitly\nclass Document(IDrawable, IPrintable):\n def __init__(self, content: str):\n self.content = content\n \n @implements(IDrawable.draw)\n def render_document(self) -> str:\n return f\"Drawing: {self.content}\"\n \n @implements(IPrintable.print_info)\n def document_info(self) -> str:\n return f\"Document: {self.content}\"\n\n# Use the implementation\ndoc = Document(\"Hello World\")\n\n# Access through specific interfaces\ndrawable = doc.as_interface(IDrawable)\nprintable = doc.as_interface(IPrintable)\n\nprint(drawable.draw()) # \"Drawing: Hello World\"\nprint(printable.print_info()) # \"Document: Hello World\"\n```\n\n## Key Concepts\n\n### Interface Declaration\n\nInterfaces are defined by inheriting from `Interface` and using `@abstractmethod`:\n\n```python\nclass IRepository(Interface):\n @abstractmethod\n def save(self, data: dict) -> bool:\n ...\n \n @abstractmethod\n def load(self, id: str) -> dict:\n ...\n```\n\n### Explicit Implementation\n\nUse the `@implements` decorator to explicitly map interface methods to implementation methods:\n\n```python\nclass DatabaseRepository(IRepository):\n @implements(IRepository.save)\n def save_to_database(self, data: dict) -> bool:\n # Implementation here\n return True\n \n @implements(IRepository.load) \n def load_from_database(self, id: str) -> dict:\n # Implementation here\n return {\"id\": id}\n```\n\n### Interface Access\n\nAccess implementations through specific interface views:\n\n```python\nrepo = DatabaseRepository()\n\n# Access through the IRepository interface\nrepository_interface = repo.as_interface(IRepository)\nrepository_interface.save({\"name\": \"example\"})\nrepository_interface.load(\"123\")\n```\n\n### Concrete Classes\n\nBy default, partial implementations are allowed at class definition time. To enforce complete implementation:\n\n```python\n# This is allowed - partial implementation class definition\nclass PartialRepository(IRepository):\n @implements(IRepository.save)\n def save_to_database(self, data: dict) -> bool:\n return True\n # Missing IRepository.load implementation - class definition succeeds\n\n# However, you still can't instantiate classes with unimplemented abstract methods\n# partial = PartialRepository() # Raises TypeError at instantiation\n\n# This will raise TypeError at class definition time\nclass ConcreteRepository(IRepository, concrete=True):\n @implements(IRepository.save)\n def save_to_database(self, data: dict) -> bool:\n return True\n # Missing IRepository.load implementation - TypeError at class definition!\n```\n\n## Advanced Usage\n\n### Multiple Interface Implementation\n\n```python\nclass IValidator(Interface):\n @abstractmethod\n def validate(self, data: str) -> bool:\n ...\n\nclass IFormatter(Interface):\n @abstractmethod\n def format(self, data: str) -> str:\n ...\n\nclass DataProcessor(IValidator, IFormatter):\n @implements(IValidator.validate)\n def check_data(self, data: str) -> bool:\n return len(data) > 0\n \n @implements(IFormatter.format)\n def format_data(self, data: str) -> str:\n return data.upper()\n```\n\n### Interface Inheritance\n\n```python\nclass IBasic(Interface):\n @abstractmethod\n def basic_method(self) -> str:\n ...\n\nclass IExtended(IBasic):\n @abstractmethod\n def extended_method(self) -> int:\n ...\n\nclass Implementation(IExtended):\n @implements(IBasic.basic_method)\n def basic_impl(self) -> str:\n return \"basic\"\n \n @implements(IExtended.extended_method)\n def extended_impl(self) -> int:\n return 42\n```\n\n### Diamond Inheritance Patterns\n\nIn diamond inheritance, each interface path requires explicit implementation:\n\n```python\nclass IBase(Interface):\n @abstractmethod\n def base_method(self) -> str:\n ...\n\nclass ILeft(IBase):\n @abstractmethod\n def left_method(self) -> int:\n ...\n\nclass IRight(IBase):\n @abstractmethod\n def right_method(self) -> bool:\n ...\n\nclass Diamond(ILeft, IRight):\n # Can only implement base_method once for IBase\n @implements(IBase.base_method)\n def base_impl(self) -> str:\n return \"base\"\n \n @implements(ILeft.left_method)\n def left_impl(self) -> int:\n return 42\n \n @implements(IRight.right_method)\n def right_impl(self) -> bool:\n return True\n\n# Access base_method only through IBase interface\ndiamond = Diamond()\nbase_interface = diamond.as_interface(IBase)\nprint(base_interface.base_method()) # \"base\"\n```\n\n## Error Handling\n\nThe library provides clear error messages for common mistakes:\n\n### Missing Implementation\n\nBy default, partial implementations are allowed:\n\n```python\nclass Incomplete(IDrawable):\n pass # Missing @implements for IDrawable.draw\n # This is allowed by default - no error raised\n```\n\nTo enforce complete implementation, use `concrete=True`:\n\n```python\nclass Concrete(IDrawable, concrete=True):\n pass # Missing @implements for IDrawable.draw\n # Raises: TypeError at class definition time\n```\n\n### Invalid Implementation Target\n\n```python\nclass Invalid(IDrawable):\n @implements(IPrintable.print_info) # Wrong interface method\n def some_method(self) -> str:\n return \"invalid\"\n # Raises: TypeError - method not in base interfaces\n```\n\n### Accessing Unimplemented Interface\n\n```python\nclass Partial(IDrawable):\n @implements(IDrawable.draw)\n def draw_impl(self) -> str:\n return \"drawn\"\n\npartial = Partial()\n# This will raise TypeError:\nprintable = partial.as_interface(IPrintable)\n```\n\n## Type Safety\n\nThe library provides full typing support:\n\n```python\nfrom typing import Protocol\n\ndef use_drawable(drawable: IDrawable) -> str:\n return drawable.draw()\n\ndef process_document(doc: Document) -> tuple[str, str]:\n drawable = doc.as_interface(IDrawable) # Type: IDrawable\n printable = doc.as_interface(IPrintable) # Type: IPrintable\n \n return drawable.draw(), printable.print_info()\n```\n\n## Comparison with ABC\n\n| Feature | ABC | Explicit Implementation |\n|---------|-----|------------------------|\n| Method Names | Must match interface | Can be different |\n| Interface Access | Direct method calls | Through `.as_interface()` |\n| Multiple Interfaces | Name conflicts possible | Clean separation |\n| Implementation Clarity | Implicit | Explicit with `@implements` |\n| Error Detection | Runtime | Compile-time |\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Changelog\n\n### 0.1.0\n- Initial release\n- Basic interface and implementation functionality\n- Support for multiple interface implementation\n- Diamond inheritance pattern support\n- Full typing support\n- Comprehensive test coverage\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A Python library for explicit interface implementations with compile-time safety",
"version": "0.1.0",
"project_urls": {
"Homepage": "https://github.com/xpodev/explicit-implementation",
"Issues": "https://github.com/xpodev/explicit-implementation/issues",
"Repository": "https://github.com/xpodev/explicit-implementation"
},
"split_keywords": [
"abc",
" explicit",
" implementation",
" interface",
" typing"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "e5675cb425b7ce1d00548b876b1a6f07923ff5557236abdb323a5e2dacfdf80b",
"md5": "f36d120c48168d7710ca7efb33563223",
"sha256": "bdce0ce5083c1b42574e0ed55e94f8c572304dbcd7c8da606395806474217024"
},
"downloads": -1,
"filename": "explicit_implementation-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "f36d120c48168d7710ca7efb33563223",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 6949,
"upload_time": "2025-09-15T18:20:39",
"upload_time_iso_8601": "2025-09-15T18:20:39.261433Z",
"url": "https://files.pythonhosted.org/packages/e5/67/5cb425b7ce1d00548b876b1a6f07923ff5557236abdb323a5e2dacfdf80b/explicit_implementation-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "0fb7463e9f3fb89af47eb135e9ed19b111f61b0095b58077a7d19d0ec327bfb6",
"md5": "6703b63617c0a43fc1298a79c937197c",
"sha256": "91aa83c8c1fc715912de87ce6ec6f950717270520f975832db04fed19b2b01d1"
},
"downloads": -1,
"filename": "explicit_implementation-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "6703b63617c0a43fc1298a79c937197c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 35101,
"upload_time": "2025-09-15T18:20:40",
"upload_time_iso_8601": "2025-09-15T18:20:40.758349Z",
"url": "https://files.pythonhosted.org/packages/0f/b7/463e9f3fb89af47eb135e9ed19b111f61b0095b58077a7d19d0ec327bfb6/explicit_implementation-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-15 18:20:40",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "xpodev",
"github_project": "explicit-implementation",
"github_not_found": true,
"lcname": "explicit-implementation"
}