Metadata-Version: 2.1
Name: abstracts
Version: 0.0.4
Summary: Abstract class and interface definitions
Home-page: https://github.com/phlax/pytooling/abstracts
Author: Ryan Northey
Author-email: ryan@synca.io
Maintainer: Ryan Northey
Maintainer-email: ryan@synca.io
License: Apache Software License 2.0
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Pytest
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Testing
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Operating System :: OS Independent
Classifier: License :: OSI Approved :: Apache Software License
Requires-Python: >=3.5
Provides-Extra: lint
Requires-Dist: flake8 ; extra == 'lint'
Provides-Extra: publish
Requires-Dist: wheel ; extra == 'publish'
Provides-Extra: test
Requires-Dist: pytest ; extra == 'test'
Requires-Dist: pytest-asyncio ; extra == 'test'
Requires-Dist: pytest-coverage ; extra == 'test'
Requires-Dist: pytest-patches ; extra == 'test'
Provides-Extra: types
Requires-Dist: mypy ; extra == 'types'


abstracts
=========

Abstract class and interface definitions.

Create an ``abstract.Abstraction``
----------------------------------

An ``Abstraction`` is a ``metaclass`` for defining abstract classes.

Let's define an abstract ``AFoo`` class and give it an abstract ``do_foo``
method.

Like any python class, an ``Abstraction`` can have any name, but it may
be helpful to distinguish abstract classes from others by prefixing their
name with ``A``.

.. code-block:: pycon

   >>> import abc
   >>> import abstracts

   >>> class AFoo(metaclass=abstracts.Abstraction):
   ...
   ...     @abc.abstractmethod
   ...     def do_foo(self):
   ...         raise NotImplementedError

Abstract classes **cannot** be instantiated directly.

.. code-block:: pycon

   >>> AFoo()
   Traceback (most recent call last):
   ...
   TypeError: Can't instantiate abstract class AFoo with abstract method... do_foo


Create an ``implementer`` for an ``abstract.Abstraction``
---------------------------------------------------------

In order to make use of ``AFoo``, we need to create an implementer for it.

.. code-block:: pycon

   >>> @abstracts.implementer(AFoo)
   ... class Foo:
   ...     pass

The implementer **must** implement all of the abstract methods,
defined by its abstract classes.

.. code-block:: pycon

   >>> Foo()
   Traceback (most recent call last):
   ...
   TypeError: Can't instantiate abstract class Foo with abstract method... do_foo

   >>> @abstracts.implementer(AFoo)
   ... class Foo2:
   ...
   ...     def do_foo(self):
   ...         return "DID FOO"

   >>> Foo2()
   <__main__.Foo2 object at ...>


An implementer inherits from its ``Abstractions``
-------------------------------------------------

An ``implementer`` class is a subclass of its ``Abstraction``.

.. code-block:: pycon

   >>> issubclass(Foo2, AFoo)
   True

Likewise an instance of an implementer is an instance of its ``Abstraction``

.. code-block:: pycon

   >>> isinstance(Foo2(), AFoo)
   True

The ``Abstraction`` class can be seen in the class ``bases``, and the
methods of the ``Abstraction`` can be invoked by the implementer.

.. code-block:: pycon

   >>> import inspect
   >>> AFoo in inspect.getmro(Foo2)
   True


