I'm currently refactoring features and I ended up with this abstractions
I have this classes
class AbstractClassA(SomeOtherAbstractClass):
#abstractmethod
def some_abstract_method(self):
pass
def my_method(self)):
service.some_method
class AbstractClassB(AbstractClassA):
#abstractmethod
def another_abstract_method(self):
pass
def some_abstract_method(self):
some_implementation
def my_method(self):
super().my_method()
do_any_other_stuff
And I need to test if the AbstractClassB.my_method calls super().my_method().
I've tried to test this by creating some ImplementationClass that inherits from AbstractClassB and then mocking the AbstractClassA.my_method and checking if it was called but it didn't work...
class AbstractClassBImplementation(AbstractClassB):
def some_abstract_method(self):
calls_service()
class TestAbstractClassB(TestCase):
#patch('module.submodule.AbstractClassA.my_method')
def test_class_b_calls_class_a_my_method(self, my_method_mock):
instance = AbstractClassBImplementation()
instance.my_method()
self.assertTrue(my_method_mock.called)
Someone know how to test this?
Related
I know python likes to play it nice and loose with types, but sometimes you want a plugin type interface, and want to discover before production that someone has missed something. I found abcmeta - so did the following:
class Abstract_Base(metaclass=abc.ABCMeta):
#abc.abstractmethod
def a():
pass
#abc.abstractmethod
def b():
pass
class Inheritor_One(Abstract_Base):
def a():
pass
but when I do python -m flake8.... it has no problem with that. Is there any way of writing it such that someone not overriding an abstract method will go bang at linting time?
Pylint raises abstract-method for your example:
W0223: Method 'b' is abstract in class 'Abstract_Base' but is not overridden (abstract-method)
If you actually want Inheritor_One to be an abstract class you can disable the warning locally in this class and still have the warning when you use the abstract class later on:
import abc
class Abstract_Base(metaclass=abc.ABCMeta):
#abc.abstractmethod
def a(self):
pass
#abc.abstractmethod
def b(self):
pass
class Inheritor_One(Abstract_Base):
# pylint: disable=abstract-method
def a(self):
pass
The background
In python, if you were defining an Abstract Base Class which requires that its methods be overwritten, you'd do:
from abc import ABC, abstractmethod
class MyAbstractClass(ABC):
#abstractmethod
def my_method(self):
pass
The following code would then fail because it doesn't implement my_method.
class MyConcreteClass(MyAbstractClass):
pass
But what if I want to define the method requirements of a mixin class?
class MyMixin:
def my_mixin_method(self):
self.a_required_method()
The following code is then valid:
class MyBase:
def a_required_method(self):
pass
class MyFull(MyMixin, MyBase):
pass
The following code is also valid...
class MyDubious(MyMixin):
pass
But exposes an error at runtime:
MyFull().my_mixin_method() # Works
MyDubious().my_mixin_method() # Runtime error
The Question
Is there something like AbstractBaseClass which can be added to Mixin classes, to ensure that a derived class can't be instantiated unless it inherits correctly?
I'm thinking a nice API would look like:
from asc import ASC, requiredmethod
class MyRobustMixin(ASC):
#requiredmethod
def a_required_method(self):
pass
def my_mixin_method(self):
self.a_required_method()
Python does not provide some built-in inheritance mechanism to call implementations of base virtual or abstract methods in the derived class from the base methods
I am wondering what is the closest thing in python that would provide the following structure:
class Base(?):
def some_abstract_interface(self, **params):
raise Unimplemented()
def some_base_impl(self):
self.some_abstract_interface(self, a=4, b=3, c=2)
class Derived(Base):
#neat_override_decorator_here?
def some_abstract_interface(self, **params):
print("actual logic here {0}".format(params))
d = Derived()
d.some_base_impl()
>>>output: actual logic here a=4, b=3, c=2
You can already do that without any neat decorator:
class Base:
def some_abstract_interface(self):
raise NotImplemented
def some_base_impl(self):
self.some_abstract_interface()
class Derived(Base):
def some_abstract_interface(self):
print('actual logic here')
Derived().some_base_impl()
This outputs:
actual logic here
If you want to enforce that Base is an abstract class and cannot be used to instantiate an object directly, and that some_abstract_interface is meant to be an abstract method and always has to be overridden by an implementation of the method from a child class, you can make the base class inherit from the ABC class of the abc module and decorate abstract methods with abc.abstractmethod like this:
import abc
class Base(abc.ABC):
#abc.abstractmethod
def some_abstract_interface(self):
raise NotImplemented
def some_base_impl(self):
self.some_abstract_interface()
class Derived(Base):
def some_abstract_interface(self):
print('actual logic here')
Derived().some_base_impl()
You simply make the call yourself. That's not going to be any heavier, syntactically, then the decorator you posit.
class Derived(Base):
def some_abstract_interface(self, **params):
self.some_base_impl()
print('actual logic her {0}.format(params))
In fact, you don't even need to separate some_base_impl and some_abstract_interace; an abstract method can have an implementation but still require overriding.
from abc import ABC, abstractmethod
class Base(ABC):
#abstractmethod
def some_abstract_interface(self, **params):
pass # Put base implementation here
class Derived(Base):
def some_abstract_interface(self, **params):
super().some_abstract_interface(**params)
print("actual logic here {0}".format(params))
I have an Interface class which defines the requirements to an active "in-use" class:
class Portfolio(ABC):
#abstractmethod
def update_portfolio(self):
raise NotImplementedError
#abstractmethod
def update_from_fill(self):
raise NotImplementedError
#abstractmethod
def check_signal(self, signal_event):
raise NotImplementedError
The methods update_portfolio and update_from_fill are both methods which will be the same in 99% of the required cases. Only the check_signal method will vary. Therefore, to avoid having to write the same code again and again, I have defined a base class with default methods for update_portfolio and update_from_fill:
class BaseBacktestPortfolio(Portfolio):
def __init__(self, ...):
...
def update_portfolio(self, ...):
...
def update_from_fill(self, ...):
...
Then, finally, I have a class inheriting from the BacktestPortfolio class which specifies the correct implementation of the check_signal method:
class USBacktestPortfolio(BaseBacktestPortfolio):
def check_signal(self, ...):
...
Now, the problem is that my editor complains about the BacktestPortfolio classing not having all the required abstract methods. I could ignore this, of course, but the perfect scenario would be if I could make sure that it is not possible to instantiate an object form the BacktestPortfolio class.
Is this possible? And/or is there a more correct way to implement a structure like this?
I could ignore this, of course, but the perfect scenario would be if I could make sure that it is not possible to instantiate an object from the BacktestPortfolio class.
That is the case in your example already:
>>> BaseBacktestPortfolio.mro()
[__main__.BaseBacktestPortfolio, __main__.Portfolio, abc.ABC, object]
>>> BaseBacktestPortfolio()
TypeError: Can't instantiate abstract class BaseBacktestPortfolio with abstract methods check_signal
Since ABC and ABCMeta are just regular types, their features are inherited. This includes their guards against instantiating incomplete classes. Your BaseBacktestPortfolio already is an abstract class.
The warning from your IDE/linter/... exists specifically to warn you that instantiating BaseBacktestPortfolio is not possible.
You can make the BaseBacktestPortfolio also as Abstract class.
from abc import ABC, abstractmethod
class Portfolio(ABC):
#abstractmethod
def update_portfolio(self):
pass
#abstractmethod
def update_from_fill(self):
pass
#abstractmethod
def check_signal(self, signal_event):
pass
class BaseBacktestPortfolio(Portfolio, ABC):
def update_portfolio(self):
print("updated portfolio")
def update_from_fill(self):
print("update from fill")
#abstractmethod
def check_signal(self):
pass
class USBacktestPortfolio(BaseBacktestPortfolio):
def check_signal(self):
print("checked signal")
Also notice that you don't need raise NotImplementedError inside abstract method. You can just pass. Its more Pythonic :)
I have a python abstract base class as follows:
class Node(object):
"""
All concrete node classes should inherit from this
"""
__metaclass__ = ABCMeta
def __init__(self, name):
self.name = name
self.inputs = dict()
def add_input(self, key, value=None, d=None):
self.inputs[key] = (d, value)
def bind_input(self):
print "Binding inputs"
#abstractmethod
def run(self):
pass
Now, various derived classes will inherit from this node class and override the run method. It is always the case that bind_input() must be the first thing that should be called in the run method. Currently, for all derived classes the developer has to make sure to first call self.bind_input(). This is not a huge problem per se but out of curiosity is it possible to ensure this somehow from the base class itself that bind_input is called before executing the child object's run?
The usual object-oriented approach is this:
def run(self):
self.bind_input()
return self.do_run()
#abstractmethod
def do_run(self):
pass # override this method
Have your subclasses override the inner method, instead of the outer one.