Current collected state Current
Observed since 20 Oct, 17:43 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Abstract class and interface definitions
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 Create an ``implementer`` that implements multiple ``Abstraction`` s. --------------------------------------------------------------------- An implementer can implement multiple abstractions. Let's create a second abstraction. .. code-block:: pycon >>> class ABar(metaclass=abstracts.Abstraction): ... ... @abc.abstractmethod ... def do_bar(self): ... raise NotImplementedError And now we can create an implementer that implememts both the ``AFoo`` and ``ABar`` ``Abstraction`` s. .. code-block:: pycon >>> @abstracts.implementer((AFoo, ABar)) ... class FooBar: ... ... def do_foo(self): ... return "DID FOO" ... ... def do_bar(self): ... return "DID BAR" >>> FooBar() <__main__.FooBar object at ...> Defining abstract properties ---------------------------- Properties can be defined in an abstract class, and just like with normal methods, they must be implemented by any implementers. .. code-block:: pycon >>> class AMover(metaclass=abstracts.Abstraction): ... ... @property ... @abc.abstractmethod ... def speed(self): ... return 5 ... ... @property ... @abc.abstractmethod ... def direction(self): ... return "forwards" Calling ``super()`` on an ``abstractmethod`` -------------------------------------------- Just like with pythons "Abstract Base Classes" you can call ``super()`` in an ``abstractmethod``, to invoke an abstract implementation. .. code-block:: pycon >>> @abstracts.implementer(AMover) ... class Mover: ... ... @property ... def direction(self): ... return "backwards" ... ... @property ... def speed(self): ... return super().speed This custom implementation of ``AMover`` **must** implement both ``speed`` and ``direction``, even if its implementation invokes the abstract implementation. In this case it uses the default/abstract implementation of ``speed`` while providing its own implementation of ``direction``. .. code-block:: pycon >>> mover = Mover() >>> mover <__main__.Mover object at ...> >>> mover.speed 5 >>> mover.direction 'backwards' Defining an ``abstracts.Interface`` class ----------------------------------------- An ``Interface`` is much like an ``Abstraction``, but with a few differences. An ``Interface`` can only define methods with the ``@interfacemethod`` decorator. It cannot define normal methods or methods with the ``@abstractmethod``, only methods with ``@interfacemethod``. An ``@interfacemethod`` if invoked will always raise an ``NotImplementedError``, and therefore cannot be used as an abstract implementation. Lets add an ``Interface`` class that we can use. In the way that it may be helpful to distinguish an ``Abstraction`` from other types of classes, it may be also useful to distinguish an ``Interface`` by using an ``I`` prefix when naming them. .. code-block:: pycon >>> class IGeared(metaclass=abstracts.Interface): ... ... @property ... @abstracts.interfacemethod ... def number_of_gears(self): ... # Raising an error is ~superfluous as the decorator will raise ... # anyway if the method is invoked. ... raise NotImplementedError Implementing an ``Interface`` ----------------------------- Just like with an ``Abstraction``, an ``Interface`` can be implemented using the ``@implementer`` decorator. An implementer, can implement a combination of ``Abstractions`` and ``Interfaces``. .. code-block:: pycon >>> @abstracts.implementer((AMover, IGeared)) ... class Bicycle: ... ... @property ... def direction(self): ... return super().direction ... ... @property ... def speed(self): ... return super().speed ... ... @property ... def number_of_gears(self): ... return 7 >>> Bicycle().number_of_gears 7 An implementer does **not** inherit from its ``Interfaces`` ----------------------------------------------------------- An ``implementer`` class is a subclass of its ``Interfaces``. .. code-block:: pycon >>> issubclass(Bicycle, AMover) True >>> issubclass(Bicycle, IGeared) True Likewise an instance of an implementer is an instance of its ``Interfaces`` .. code-block:: pycon >>> isinstance(Bicycle(), AMover) True >>> isinstance(Bicycle(), IGeared) True Unlike with ``Abstractions`` it does **not** however, inherit from its ``Interfaces``. .. code-block:: pycon >>> AMover in inspect.getmro(Bicycle) True >>> IGeared in inspect.getmro(Bicycle) False ``@interfacemethods`` can never be invoked ------------------------------------------ The key thing to remember is that you cannot call ``super()`` on any ``@interfacemethod``, or directly invoke it. If it was defined as part of an ``Interface`` you will receive an ``AttributeError``, as the implementation does not inherit directly from the interface. .. code-block:: pycon >>> @abstracts.implementer((AMover, IGeared)) ... class BrokenBicycle: ... ... @property ... def direction(self): ... return super().direction ... ... @property ... def speed(self): ... return super().speed ... ... @property ... def number_of_gears(self): ... return super().number_of_gears >>> BrokenBicycle().number_of_gears Traceback (most recent call last): ... AttributeError: 'super' object has no attribute 'number_of_gears' .. warning:: Misuse of this class can have `unintended consequences <https://www.dailymotion.com/video/x2howud>`_ If you invoke ``super()`` on an ``@interfacemethod`` defined as part of an ``Abstraction`` it will raise ``NotImplementedError``. As an ``Interface`` can only hold this type of method, you can never invoke any of its methods. Doing so directly will raising a ``NotImplementedError``. .. code-block:: pycon >>> IGeared.number_of_gears.__get__(Bicycle()) Traceback (most recent call last): ... NotImplementedError Combining ``@abstractmethod`` and ``@interfacemethod`` in an ``Abstraction`` ---------------------------------------------------------------------------- As ``Interfaces`` are "pure", they cannot use ``@abstractmethod`` or contain any implementation. An ``Abstraction`` on the other hand can combine both. Lets create a pure ``Interface`` that represents a "shed". .. code-block:: pycon >>> class IShed(metaclass=abstracts.Interface): ... ... @property ... @abstracts.interfacemethod ... def size(self): ... raise NotImplementedError We can use this interface to create an ``ABikeShed`` ``Abstraction`` .. code-block:: pycon >>> class ABikeShed(IShed, metaclass=abstracts.Abstraction): ... ... @property ... @abstracts.interfacemethod ... def max_bike_size(self): ... raise NotImplementedError ... ... @abc.abstractmethod ... def get_capacity(self): ... return int(self.size / self.max_bike_size) We can now create an implementation. It will need to define both the ``size`` and the ``max_bike_size``, as these are ``interfacemethods``. It can, however, make use of the abstract implementation of ``get_capacity``, even if it must be defined. .. code-block:: pycon >>> @abstracts.implementer(ABikeShed) ... class BikeShed: ... ... @property ... def max_bike_size(self): ... return 7 ... ... @property ... def size(self): ... return 161 ... ... def get_capacity(self): ... return super().get_capacity() >>> bikeshed = BikeShed() >>> bikeshed.get_capacity() 23
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.2.0 | 9 May 2026 | 6 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 17:43 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:794338c4d72f0b353f6ea9e8d9611776ddbdf6674e1ea9311d77fc82864b8bf9