How can I refactor classes in Python? - python

I have test code written in Python, using classes.
The test environment has two types of hosts - app hosts, where applications run, and storage hosts, where storage components run.
I have two classes, each representing the type of host:
class AppHost_Class(object):
def __init_(self, ip_address):
# etc.
# This method handles interfacing with the application
def application_service(self):
# This method handles the virtual storage component
def virtual_storage(self):
# This method handles caching
def cache_handling(self):
class Storage_Server_Class(object):
def __init_(self, ip_address):
# This method handles interfacing with the storage process
def storage_handling(self):
# This method handles interfacing with the disk handling processes
def disk_handling(self):
The problem is that the topology can change.
Topology #1 is this:
- Application Host runs
* Application processes
* Virtual storage processes
* Cache processes
Storage Host runs
Storage processes
Disk handling processes
My current test code handles Topology #1
However, we also want to support another Topology (Topology #2)
Application Host runs
Application processes
Storage Host runs
Virtual storage processes
Cache processes
Storage processes
Disk handling processes
How can I refactor the classes so that for Topology 1, the classes and its methods are the same, but for Topology 2, the Storage_Server_Class gets some of the methods from the AppHost_Class?
I was thinking of making a child class like this:
class Both_Class(AppHost_Class, Storage_Server_Class):
But I don't want to do this because I don't want the applcation_service method to be available to Both_Class.
Is there a way to just map a few methods in AppHost_Class into the Storage_Server_Class?

Here is an example of a class B that shares exactly one method defined in class A:
class A:
def a1(self):
pass
def a2(self):
pass
class B:
def __init__(self, instance_of_a):
self.a2 = instance_of_a.a2
a = A()
B(a)

It sounds to me like you want three base classes. One for App stuff, one for VirtualStorage (and cache) stuff and one for Storage (and disk) stuff. Then you can make child classes for your two topologies that mix the desired methods together.
For topology 1, you have a class that inherits from both the App and the VirtualStorage base classes (and you use the Storage base class unmodified). For topology 2, you create a class that inherits from the VirtualStorage and the Storage base classes and use the App base class unmodified.
Example code:
class App:
def do_app_stuff(self):
pass
class VirtualStorage:
def do_virtual_storage_stuff(self):
pass
class Storage:
def do_storage_stuff(self):
pass
# topology 1
class Top1App(App, VirtualStorage):
pass
Top1Storage = Storage
# topology 2
Top2App = App
class Top2Storage(VirtualStorage, Storage):
pass
You might not need the aliased names for the base classes you're using directly in the different topologies, I just threw those in to make it look extra nice.

Split the methods up into three classes then combine as needed.
#class NetworkObject(object): # Python 2.7
class NetworkObject:
def __init__(self, ip_address):
self.ip_address = ip_address
class AppHost(NetworkObject):
def application_service(self):
print('app service', self.ip_address)
class Storage_Server(NetworkObject):
def storage_handling(self):
print('storage handler', self.ip_address)
def disk_handling(self):
print('disk handler', self.ip_address)
class Foo(object):
def virtual_storage(self):
print('virtual storage', self.ip_address)
def cache_handling(self):
print('cache handling', self.ip_address)
topology_1, topology_2 = True, False
# Topology 1
if topology_1:
class AppHost_Class(AppHost, Foo):
pass
class Storage_Server_Class(Storage_Server):
pass
# Topology 2
if topology_2:
class AppHost_Class(AppHost):
pass
class Storage_Server_Class(Storage_Server, Foo):
pass
Another option would be to define the two classes with the methods they will always include,
#class NetworkObject(object): # Python 2.7
class NetworkObject:
def __init__(self, ip_address):
self.ip_address = ip_address
class A(NetworkObject):
def application_service(self):
print('app service', self.ip_address)
class B(NetworkObject):
def storage_handling(self):
print('storage handler', self.ip_address)
def disk_handling(self):
print('disk handler', self.ip_address)
... define methods you would like to mix and match
def virtual_storage(self):
print('virtual storage', self.ip_address)
def cache_handling(self):
print('cache handling', self.ip_address)
... and conditionally add the methods to the classes
topology = 1
if topology == 1:
A.virtual_storage = virtual_storage
A.cache_handling = cache_handling
if topology == 2:
B.virtual_storage = virtual_storage
B.cache_handling = cache_handling
You may want to define the extra methods in the parent/base class but have them raise an exception unless a topology has been applied
#class NetworkObject(object): # Python 2.7
class NetworkObject:
def __init__(self, ip_address):
self.ip_address = ip_address
def virtual_storage(self):
raise NotImplementedError
def cache_handling(self):
raise NotImplementedError

Related

Python: Force each instance of a class to have a certain property set to the same value

I have a number of objects that share a particular property. Let's call this property "Application". At the beginning of my program, I do not know the value of Application. At startup, I will run a routine that reveals the value of Application. After this point, the value of Application will never change. It is convenient for my objects to know the value of Application. So my desired architecture is:
Create a Parent Class that holds the Application property. Since there are many different objects that want to point to Application, I figured making them Children of another object would be convenient so all Child objects inherently point to Application.
Have a functionality such that I set Application one time and then every time I create an instance of a Child, they point to Application without the need to explicitly tell them to.
Below is an example that appears to work as I want. The ParentClass creates a class method called set_application so that the calling program must call it at some point before invoking an instance of ParentClass. Then the ChildClass will inherit the value of Application.
I am new to Python, so I'm curious if there are better ways to do this than what I have designed.
class ParentClass:
#classmethod
def set_application(cls, value):
cls.Application = value
def __init__(self):
attr = list(__class__.__dict__.keys())
if 'Application' in attr:
self.Application = __class__.Application
else:
raise ValueError('Application must be set by using set_application method')
class ChildClass(ParentClass):
def __init__(self, height):
self.height = height
super().__init__()
def print(self):
return vars(self)
Running this code:
Child = ChildClass(3)
gives:
ValueError: Application must be set by using set_application method
But running this:
ParentClass.set_application('ABC')
Child = ChildClass(3)
Child.print()
gives:
{'height': 3, 'Application': 'ABC'}
You can just do this:
class Foo:
application = ""
def __init__(self):
pass
if __name__ == "__main__":
Foo.application = "whatever"
foo = Foo()
print(foo.application) # whatever
And if you want the inheriting classes to know application, too, you get that for free:
class Foo:
application = ""
def __init__(self):
pass
class SubFoo(Foo):
def __init__(self):
pass
if __name__ == "__main__":
Foo.application = "whatever"
foo = Foo()
print(foo.application) # whatever
subfoo = SubFoo()
print(subfoo.application) # whatever
Another way I can think of would be to use a factory object:
class FooFactory:
def __init__(self, application):
self.application = application
def new_instance(self):
return Foo(application=self.application)
class Foo:
def __init__(self, application):
self.application = application
if __name__ == "__main__":
application = "whatever"
# instantiate the factory
factory = FooFactory(application)
# then use that factory to create new instances of Foo
foo_0 = factory.new_instance()
foo_1 = factory.new_instance()

#abstractmethod given by a second class to inherit from (multiple inheritance with abstract methods)

I would like to define an abstract method which from my base class through a second inheritance.
Since I can imagine that my question or even this sentence is confusing here is an example from what I am trying to do:
Imagine the following BaseClass containing 2 abstract methods: process & validation
class BaseClass(ABC):
"""
Base class for all services
"""
def __init__(self) -> None:
pass
#abstractmethod
def validate_input(self, payload: dict) -> None:
"""
validates the payload
"""
pass
#abstractmethod
def process(self, payload: dict) -> dict:
"""
processes the payload
"""
pass
As you can tell there are 2 methods in the BaseClass that need to be defined by the processes. I now want to define the process method in the Process1 class which will inherit from the BaseClass. However I also need to define the validate_input method, which can be the same for different processes. Therefore I thought of solving this using Multiple Inheritance.
In my case I would like to create a second BaseValidation1 Class that contains a certain valdidation method, for example to check if there is key in the payload.
class Validation1(ABC):
"""
Validates if the payload is valid given a certained method e.g. if payload contains a certain key
"""
def validate_input(self, payload_dict: typing.Dict[str, typing.Any]) -> None:
"""
check if dict contains a certain key
"""
if not payload_dict:
raise ValidationException("payload is empty")
if not payload_dict.get("key"):
raise ValidationException("payload does not contain key")
So now I would like to inherit from both to define my Process1.
class Process1(BaseClass,Validation1):
"""
Base class for processing the payload
"""
def process(self, payload: typing.Dict) -> typing.Dict:
"""
Process the payload
"""
processed_payload = payload
return processed_payload
I am however super unsure if my method is even the best way to solve this problem. Furthermore Pylint already show the following warning:
E0110: Abstract class 'Process1' with abstract methods instantiated (abstract-class-instantiated)
Appreciate any solution.
Your example works, if you reverse the order of your base classes:
class Process1(Validation1, BaseClass):
...
The reason has to do with python's method resolution order: The way you defined the parent classes of Process1 causes the python interpreter to "find" BaseClass.validate() when you invoke Process1.validate(), which is abstract.
I would further remove the ABC parent from Validation1, as I consider that class a Mixin. Here is a fullly working minimal example:
from abc import ABC, abstractmethod
class BaseClass(ABC):
def __init__(self):
pass
#abstractmethod
def validate(self):
pass
#abstractmethod
def process(self):
pass
class ValidationMixin:
def validate(self):
pass
class Processor(ValidationMixin, BaseClass):
def process(self):
pass

Inheriting setUp method Python Unittest

I have a question regarding unittest with Python! Let's say that I have a docker container set up that handles a specific api endpoint (let's say users, ex: my_site/users/etc/etc/etc). There are quite a few different layers that are broken up and handled for this container. Classes that handle the actual call and response, logic layer, data layer. I am wanting to write tests around the specific calls (just checking for status codes).
There are a lot of different classes that act as Handlers for the given endpoints. There are a few things that I would have to set up differently per one, however, each one inherits from Application and uses some methods from it. I am wanting to do a setUp class for my unittest so I don't have to re-establish this each time. Any advice will help. So far I've mainly seen that inheritance is a bad idea with testing, however, I am only wanting to use this for setUp. Here's an example:
class SetUpClass(unittest.TestCase):
def setUp(self):
self._some_data = data_set.FirstOne()
self._another_data_set = data_set.SecondOne()
def get_app(self):
config = Config()
return Application(config,
first_one=self._some_data,
second_one=self._another_data_set)
class TestFirstHandler(SetUpClass, unittest.TestCase):
def setUp(self):
new_var = something
def tearDown(self):
pass
def test_this_handler(self):
# This specific handler needs the application to function
# but I don't want to define it in this test class
res = self.fetch('some_url/users')
self.assertEqual(res.code, 200)
class TestSecondHandler(SetUpClass, unittest.TestCase):
def setUp(self):
different_var_thats_specific_to_this_handler = something_else
def tearDown(self):
pass
def test_this_handler(self):
# This specific handler needs the application to function
# but I don't want to define it in this test class
res = self.fetch('some_url/users/account/?something_custom={}'.format('WOW'))
self.assertEqual(res.code, 200)
Thanks again!!
As mentioned in the comments, you just need to learn how to use super(). You also don't need to repeat TestCase in the list of base classes.
Here's the simple version for Python 3:
class TestFirstHandler(SetUpClass):
def setUp(self):
super().setUp()
new_var = something
def tearDown(self): # Easier to not declare this if it's empty.
super().tearDown()
def test_this_handler(self):
# This specific handler needs the application to function
# but I don't want to define it in this test class
res = self.fetch('some_url/users')
self.assertEqual(res.code, 200)

Can I ensure that python base class method is always called

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.

How to execute BaseClass method before it gets overridden by DerivedClass method in Python

I am almost sure that there is a proper term for what I want to do but since I'm not familiar with it, I will try to describe the whole idea explicitly. So what I have is a collection of classes that all inherit from one base class. All the classes consist almost entirely of different methods that are relevant within each class only. However, there are several methods that share similar name, general functionality and also some logic but their implementation is still mostly different. So what I want to know is whether it's possible to create a method in a base class that will execute some logic that is similar to all the methods but still continue the execution in the class specific method. Hopefully that makes sense but I will try to give a basic example of what I want.
So consider a base class that looks something like that:
class App(object):
def __init__(self, testName):
self.localLog = logging.getLogger(testName)
def access(self):
LOGIC_SHARED
And an example of a derived class:
class App1(App):
def __init__(self, testName):
. . .
super(App1, self).__init__(testName)
def access(self):
LOGIC_SPECIFIC
So what I'd like to achieve is that the LOGIC_SHARED part in base class access method to be executed when calling the access method of any App class before executing the LOGIC_SPECIFIC part which is(as it says) specific for each access method of all derived classes.
If that makes any difference, the LOGIC_SHARED mostly consists of logging and maintenance tasks.
Hope that is clear enough and the idea makes sense.
NOTE 1:
There are class specific parameters which are being used in the LOGIC_SHARED section.
NOTE 2:
It is important to implement that behavior using only Python built-in functions and modules.
NOTE 3:
The LOGIC_SHARED part looks something like that:
try:
self.localLog.info("Checking the actual link for %s", self.application)
self.link = self.checkLink(self.application)
self.localLog.info("Actual link found!: %s", self.link)
except:
self.localLog.info("No links found. Going to use the default link: %s", self.link)
So, there are plenty of specific class instance attributes that I use and I'm not sure how to use these attributes from the base class.
Sure, just put the specific logic in its own "private" function, which can overridden by the derived classes, and leave access in the Base.
class Base(object):
def access(self):
# Shared logic 1
self._specific_logic()
# Shared logic 2
def _specific_logic(self):
# Nothing special to do in the base class
pass
# Or you could even raise an exception
raise Exception('Called access on Base class instance')
class DerivedA(Base):
# overrides Base implementation
def _specific_logic(self):
# DerivedA specific logic
class DerivedB(Base):
# overrides Base implementation
def _specific_logic(self):
# DerivedB specific logic
def test():
x = Base()
x.access() # Shared logic 1
# Shared logic 2
a = DerivedA()
a.access() # Shared logic 1
# Derived A specific logic
# Shared logic 2
b = DerivedB()
b.access() # Shared logic 1
# Derived B specific logic
# Shared logic 2
The easiest method to do what you want is to simply call the parent's class access method inside the child's access method.
class App(object):
def __init__(self, testName):
self.localLog = logging.getLogger(testName)
def access(self):
LOGIC_SHARED
class App1(App):
def __init__(self, testName):
super(App1, self).__init__(testName)
def access(self):
App.access(self)
# or use super
super(App1, self).access()
However, your shared functionality is mostly logging and maintenance. Unless there is a pressing reason to put this inside the parent class, you may want to consider is to refactor the shared functionality into a decorator function. This is particularly useful if you want to reuse similar logging and maintenance functionality for a range of methods inside your class.
You can read more about function decorators here: http://www.artima.com/weblogs/viewpost.jsp?thread=240808, or here on Stack Overflow: How to make a chain of function decorators?.
def decorated(method):
def decorated_method(self, *args, **kwargs):
LOGIC_SHARED
method(self, *args, **kwargs)
return decorated_method
Remember than in python, functions are first class objects. That means that you can take a function and pass it as a parameter to another function. A decorator function make use of this. The decorator function takes another function as a parameter (here called method) and then creates a new function (here called decorated_method) that takes the place of the original function.
Your App1 class then would look like this:
class App1(App):
#logged
def access(self):
LOGIC_SPECIFIC
This really is shorthand for this:
class App1(App):
def access(self):
LOGIC_SPECIFIC
decorated_access = logged(App.access)
App.access = decorated_access
I would find this more elegant than adding methods to the superclass to capture shared functionality.
If I understand well this commment (How to execute BaseClass method before it gets overridden by DerivedClass method in Python) you want that additional arguments passed to the parent class used in derived class
based on Jonathon Reinhart's answer
it's how you could do
class Base(object):
def access(self,
param1 ,param2, #first common parameters
*args, #second positional parameters
**kwargs #third keyword arguments
):
# Shared logic 1
self._specific_logic(param1, param2, *args, **kwargs)
# Shared logic 2
def _specific_logic(self, param1, param2, *args, **kwargs):
# Nothing special to do in the base class
pass
# Or you could even raise an exception
raise Exception('Called access on Base class instance')
class DerivedA(Base):
# overrides Base implementation
def _specific_logic(self, param1, param2, param3):
# DerivedA specific logic
class DerivedB(Base):
# overrides Base implementation
def _specific_logic(self, param1, param2, param4):
# DerivedB specific logic
def test():
x = Base()
a = DerivedA()
a.access("param1", "param2", "param3") # Shared logic 1
# Derived A specific logic
# Shared logic 2
b = DerivedB()
b.access("param1", "param2", param4="param4") # Shared logic 1
# Derived B specific logic
# Shared logic 2
I personally prefer Jonathon Reinhart's answer, but seeing as you seem to want more options, here's two more. I would probably never use the metaclass one, as cool as it is, but I might consider the second one with decorators.
With Metaclasses
This method uses a metaclass for the base class that will force the base class's access method to be called first, without having a separate private function, and without having to explicitly call super or anything like that. End result: no extra work/code goes into inheriting classes.
Plus, it works like maaaagiiiiic </spongebob>
Below is the code that will do this. Here http://dbgr.cc/W you can step through the code live and see how it works :
#!/usr/bin/env python
class ForceBaseClassFirst(type):
def __new__(cls, name, bases, attrs):
"""
"""
print("Creating class '%s'" % name)
def wrap_function(fn_name, base_fn, other_fn):
def new_fn(*args, **kwargs):
print("calling base '%s' function" % fn_name)
base_fn(*args, **kwargs)
print("calling other '%s' function" % fn_name)
other_fn(*args, **kwargs)
new_fn.__name__ = "wrapped_%s" % fn_name
return new_fn
if name != "BaseClass":
print("setting attrs['access'] to wrapped function")
attrs["access"] = wrap_function(
"access",
getattr(bases[0], "access", lambda: None),
attrs.setdefault("access", lambda: None)
)
return type.__new__(cls, name, bases, attrs)
class BaseClass(object):
__metaclass__ = ForceBaseClassFirst
def access(self):
print("in BaseClass access function")
class OtherClass(BaseClass):
def access(self):
print("in OtherClass access function")
print("OtherClass attributes:")
for k,v in OtherClass.__dict__.iteritems():
print("%15s: %r" % (k, v))
o = OtherClass()
print("Calling access on OtherClass instance")
print("-------------------------------------")
o.access()
This uses a metaclass to replace OtherClass's access function with a function that wraps a call to BaseClass's access function and a call to OtherClass's access function. See the best explanation of metaclasses here https://stackoverflow.com/a/6581949.
Stepping through the code should really help you understand the order of things.
With Decorators
This functionality could also easily be put into a decorator, as shown below. Again, a steppable/debuggable/runnable version of the code below can be found here http://dbgr.cc/0
#!/usr/bin/env python
def superfy(some_func):
def wrapped(self, *args, **kwargs):
# NOTE might need to be changed when dealing with
# multiple inheritance
base_fn = getattr(self.__class__.__bases__[0], some_func.__name__, lambda *args, **kwargs: None)
# bind the parent class' function and call it
base_fn.__get__(self, self.__class__)(*args, **kwargs)
# call the child class' function
some_func(self, *args, **kwargs)
wrapped.__name__ = "superfy(%s)" % some_func.__name__
return wrapped
class BaseClass(object):
def access(self):
print("in BaseClass access function")
class OtherClass(BaseClass):
#superfy
def access(self):
print("in OtherClass access function")
print("OtherClass attributes")
print("----------------------")
for k,v in OtherClass.__dict__.iteritems():
print("%15s: %r" % (k, v))
print("")
o = OtherClass()
print("Calling access on OtherClass instance")
print("-------------------------------------")
o.access()
The decorator above retrieves the BaseClass' function of the same name, and calls that first before calling the OtherClass' function.
May this simple approach can help.
class App:
def __init__(self, testName):
self.localLog = logging.getLogger(testName)
self.application = None
self.link = None
def access(self):
print('There is something BaseClass must do')
print('The application is ', self.application)
print('The link is ', self.link)
class App1(App):
def __init__(self, testName):
# ...
super(App1, self).__init__(testName)
def access(self):
self.application = 'Application created by App1'
self.link = 'Link created by App1'
super(App1, self).access()
print('There is something App1 must do')
class App2(App):
def __init__(self, testName):
# ...
super(App2, self).__init__(testName)
def access(self):
self.application = 'Application created by App2'
self.link = 'Link created by App2'
super(App2, self).access()
print('There is something App2 must do')
and the test result:
>>>
>>> app = App('Baseclass')
>>> app.access()
There is something BaseClass must do
The application is None
The link is None
>>> app1 = App1('App1 test')
>>> app1.access()
There is something BaseClass must do
The application is Application created by App1
The link is Link created by App1
There is something App1 must do
>>> app2 = App2('App2 text')
>>> app2.access()
There is something BaseClass must do
The application is Application created by App2
The link is Link created by App2
There is something App2 must do
>>>
Adding a combine function we can combine two functions and execute them one after other as bellow
def combine(*fun):
def new(*s):
for i in fun:
i(*s)
return new
class base():
def x(self,i):
print 'i',i
class derived(base):
def x(self,i):
print 'i*i',i*i
x=combine(base.x,x)
new_obj=derived():
new_obj.x(3)
Output Bellow
i 3
i*i 9
it need not be single level hierarchy it can have any number of levels or nested

Categories

Resources