Python library using parent method instead of overriden method - python

I have extended the Parent class with the Override class. I have have overridden the method() method to fix a bug that occurs in the Parent class. I fixed the said bug and this fix has been tested in the Override class.
I use the Override class through an External class. By testing the External class to see if the previous bug is fixed, I discovered that it is not and that the traceback does not go through the Override class.
class Parent():
def method(self, param):
# Bugged
do_stuff()
class Override(Parent):
def method(self, param):
# Fixed (tested)
param = fix_param(param)
super(Parent, self).method(param)
class External():
def processing():
# Same bug as in `Parent`
param = get_param()
obj = Override()
obj.method(param)
It seems to me that the External class uses the Parent.method() method instead of the Override.method() method. Any clue on how to fix it or on where this problem comes from?
I'm a beginner and have not been confronted inheritance a lot so, please, forgive my ignorance and my lack of experience.
EDIT
Test that fails in External :
import os
import collections
import envtpl
from acquisition.configargparse_confparser import StepConfigFileParser
from configparser_extended import ExtendedConfigParser
from unittest import TestCase
from acquisition.utils import set_custom_environment
class ConfigFileParserTestCase(TestCase):
def test_parse_extended(self):
# x = StepConfigFileParser("test_plugin_name", "test")
plugin_name = "test_plugin_name"
step_name = "test"
set_custom_environment(plugin_name, step_name)
config = os.environ.get('MFCONFIG', 'GENERIC')
filename = os.path.dirname(os.path.realpath(__file__)) + "/test.ini"
with open(filename, 'r') as stream:
config_parser = ExtendedConfigParser(
config=config, inheritance='im', interpolation=None)
content = stream.read()
config_parser.read_string(content) # Fails here
section = "step_%s" % step_name
res = collections.OrderedDict()
for key in config_parser.options(section):
if not key.startswith('arg_'):
continue
res[key.replace('arg_', '', 1)] = envtpl.render_string(
config_parser.get(section, key))
self.assertEqual(res, {"venom": "snake", "revolver": "ocelot"})
Overridden method :
read_string() in https://github.com/thefab/configparser_extended/blob/master/configparser_extended/ecp.py line 573
Parent method :
read_string() from configparser
(https://docs.python.org/3/library/configparser.html#configparser.ConfigParser.read_string)
test.ini
[step_test]
arg_venom=snake
arg_revolver=ocelot
liquid=snake
Error :
ERROR: test_parse_extended (tests.test_confparser.ConfigFileParserTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/florian/metwork/mfdata/src/acquisition/tests/test_confparser.py", line 39, in test_parse_extended
config_parser.read_string(content)
File "/opt/metwork-mfext/opt/python2/lib/python2.7/site-packages/backports/configparser/__init__.py", line 728, in read_string
sfile = io.StringIO(string)
TypeError: initial_value must be unicode or None, not str

Your code is not a complete working example, but it should do as you suggest.
Here is an example you can run to prove the point:
class Parent():
def method(self):
print('parent')
class Child(Parent):
def method(self):
print('child')
class Other():
def call_method(self):
c = Child()
c.method()
o = Other()
o.call_method()
That prints 'child', proving the Child class has overridden method(self).

Related

Assign Constructor argument with static method pointer in python?

Getting undefined error with the below program
class SignalHandler(object): # pylint: disable=too-few-public-methods
"""
Handles various user generated signals
"""
def __init__(self,
sigint_signalhandler=SignalHandler.signal_handler,
sigquit_signalhandler=SignalHandler.signal_handler,
sighup_signalhandler=SignalHandler.signal_handler):
signal.signal(signal.SIGINT, sigint_signalhandler)
signal.signal(signal.SIGQUIT, sigquit_signalhandler)
signal.signal(signal.SIGHUP, sighup_signalhandler)
#staticmethod
def signal_handler(signalnum):
print ('Ignoring signal : ', signalnum)
This is what the error looks like
import signalhandler
File "/usr/local/sandvine/scripts/upgrade-assistance/signalhandler.py", line 10, in <module>
class SignalHandler(object): # pylint: disable=too-few-public-methods
File "/usr/local/sandvine/scripts/upgrade-assistance/signalhandler.py", line 22, in SignalHandler
sigint_signalhandler=SignalHandler.signal_handler,
NameError: name 'SignalHandler' is not defined
So eventually i want to pass some custom methods, if not i will use signal_handler method provided by SignalHandler class.
Define signal_handler above the class as a plain method, not inside it as a static method. You can't refer to a class before it's been defined, which is what your __init__ is trying to do.
Alternatively, use self.signal_handler in the init body instead of SignalHandler.signal_handler:
class Foo(object):
def __init__(self, bar_printer=None):
self.bar_printer = bar_printer if bar_printer else self._default_bar_printer
#staticmethod
def _default_bar_printer():
print("bar")
f = Foo()
f.bar_printer() # Prints "bar"
def better_bar_printer():
print("The best bar!")
f2 = Foo(better_bar_printer)
f2.bar_printer() # Prints "The best bar!"

nesting of properties vs setters and getters in python

class OurAtt():
def __init__(self):
self.Log = False
def setLog(self):
self.Log = True
def clearLog(self):
self.Log = False
class OurClass(object):
def __init__(self):
self.__OurAtt = OurAtt()
#property
def OurAtt(self):
return self.__OurAtt
#OurAtt.setter
def OurAtt(self, val):
raise Exception("can't modify the attribute" )
x = OurClass()
x.OurAtt.setLog()
print x.OurAtt.Log # print True
x.OurAtt.Log = False
print x.OurAtt.Log # sets to False Aim set this through function call x.OurAtt.setLog() I want to restrict the access, something like private variable.
Final aim is Log should be the attribute of OurAttr and should be protected by getter and setters or properties. Its like nesting of properties. and hierarchy should be maintained like object.OurAttr.Log
I researched and got the following link.
Python: multiple properties, one setter/getter
But It is not hitting my aim.
I am actually new to getter, setter and properties. Thanks in advance
I believe you are over-complicating the issue. If you want to prevent access to the attributes of OurAtt, the #property decorator should be used withing OurAtt. Instances of the OurAtt class will implement this protected-access behavior always, including when they are members of OurClass. You don't need to do anything with the #property decorator in OurClass unless you want to prevent modifying members of that class.
This, I think, does what you are trying to accomplish. It runs under 2.7 - if you are using an earlier version your mileage may vary.
class OurAttr(object):
def __init__(self):
self._log = False
#property
def log(self):
return self._log
#log.setter
def log(self, value):
raise AttributeError("Cannot set 'log' attribute directly.")
#log.deleter
def log(self):
raise AttributeError("Cannot delete 'log' attribute directly.")
def setLog(self):
self._log = True
print "Log is", self._log
def clearLog(self):
self._log = False
print "Log is", self._log
class OurClass(object):
def __init__(self):
self.OurAttr = OurAttr()
oc = OurClass()
oc.OurAttr.setLog()
oc.OurAttr.clearLog()
oc.OurAttr.log = False # Raises exception
Output is:
$ python2.7 test.py
Log is True
Log is False
Traceback (most recent call last):
File "test.py", line 33, in <module>
oc.OurAttr.log = False
File "test.py", line 11, in log
raise AttributeError("Cannot set 'log' attribute directly.")
AttributeError: Cannot set 'log' attribute directly.

exec to add a function into a class

So I've looked at similar questions, and I've found some solutions to this, but I can't quite figure out how to do this.
What I'm trying to do is add a method to a class from a string. I can do this with the setattr() method, but that won't let me use self as an attribute in the extra method. Here's an example: (and I apologize for the variable names, I always use yolo when I'm mocking up an idea)
class what:
def __init__(self):
s = 'def yolo(self):\n\tself.extra = "Hello"\n\tprint self.extra'
exec(s)
setattr(self,"yolo",yolo)
what().yolo()
returns this:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: yolo() takes exactly 1 argument (0 given)
and if s = 'def yolo():\n\tself.extra = "Hello"\n\tprint self.extra'
then I get this result:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 2, in yolo
NameError: global name 'self' is not defined
This essentially means that I cannot dynamically create methods for classes, which I know is bad practice and unpythonic, because the methods would be unable to access the variables that the rest of the class has access to.
I appreciate any help.
You have to bind your function to the class instance to turn it into a method. It can be done by wrapping it in types.MethodType:
import types
class what:
def __init__(self):
s = 'def yolo(self):\n\tself.extra = "Hello"\n\tprint self.extra'
exec(s)
self.yolo = types.MethodType(yolo, self)
what().yolo()
On a side note, why do you even need exec in this case? You can just as well write
import types
class what:
def __init__(self):
def yolo(self):
self.extra = "Hello"
print self.extra
self.yolo = types.MethodType(yolo, self)
what().yolo()
Edit: for the sake of completeness, one might prefer a solution through the descriptor protocol:
class what:
def __init__(self):
def yolo(self):
self.extra = "Hello"
print self.extra
self.yolo = yolo.__get__(self)
what().yolo()
Another way, seems more elegant to me:
class what:
pass
ld = {}
exec("""
def yolo(self):
self.extra = "Hello"
print(self.extra)
""", None, ld)
# print('locals got: {}'.format(ld))
for name, value in ld.items():
setattr(what, name, value)
what().yolo()

Python :TypeError: 'str' object is not callable

I am using a function to instansiate the python classes .
Hers is the class structure
from DB.models import ApiKey,ServiceProvider
class SMSMrg( object ):
_instance = None
class Singleton:
def __init__(self):
self.username = None
self.password = None
self.allsp = []
self.classnames = {}
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(SMSMrg, cls).__new__(
cls, *args, **kwargs)
return cls._instance
def loadsettings(self):
get_all_sp = ServiceProvider.objects.filter(status = False)
for (options,obj) in enumerate(get_all_sp):
cla = str(obj.class_Name)
self.classnames[cla] = cla
print self.classnames
for (options,obj) in enumerate(get_all_sp):
cla = str(obj.class_Name)
class_object = self.classnames[cla](obj.userName,obj.password,obj.sendingurl)
# self.allsp = get_all_sp
def send(self):
print "+++++++++++++++++++== Global send "
if __name__ == "__main__":
b = SMSMrg()
b.loadsettings()
I have stored the classnames in database and I have defined each class structures on different files .
Like cla will contain a class name .
But when i am calling above function i am getting the type error .
Traceback (most recent call last):
File "allsms.py", line 30, in <module>
b.loadsettings()
File "allsms.py", line 21, in loadsettings
class_object = cla(obj.userName,obj.password,obj.sendingurl)
TypeError: 'str' object is not callable
Please tell me how can instansiate all the classes which names are present in my db .
On the line cla = str(SERVIVEPROVIDER) you convert SERVIVEPROVIDER to string. And on the next line you are trying to call it, thus you get an error...
# Means `cla` is pointing to a string
cla = str(SERVIVEPROVIDER)
# there is no function called `cla` now it contains a string
cla(obj.userName,obj.password,obj.sendingurl)
As you said cla contains the name of the class, which means that you can't use it as a callable.
You can build a dict and take the class object from there:
from somemodule import SomeClass
class TheClass(object):
def __init__(self, username, password, url):
#do stuff
class AnOtherClass(object):
def __init__(self, username, password, url):
# do stuff
CLASS_NAMES_TO_CLASSES = {
# Note: TheClass is *not* a string, is the class!!!
'FirstName': TheClass,
'SecondName': AnOtherClass,
'SomeClass': SomeClass,
}
class SMSMrg(object):
#do stuff
def loadsettings(self):
get_all_sp = ServiceProvider.objects.filter(status = True)
for obj in get_all_sp:
SERVIVEPROVIDER = obj.class_Name
cla = str(SERVIVEPROVIDER)
class_object = CLASS_NAMES_TO_CLASSES[cla](obj.userName,obj.password,obj.sendingurl)
This method requires you to be able to build such a dict, so either you know ahead which classes could end up in the db or you can't use this method.
Note that CLASS_NAMES_TO_CLASSES is not a dictionary that maps strings to strings. It maps strings to class objects. If you import the class SomeClass from a module then you have to put it inside the dictionary.
An other method could be to use eval to evaluate the class name, but you should avoid this if the db contains data from users(which is not safe).
An other option that might turn out useful is to avoid saving the class names and instead use pickle to save the instances directly.
Please tell me how can instansiate all the classes which names are
present in my db .
Try this:
class A(object): pass
class B(object): pass
class_names = {'first': A, 'second': B}
obj = class_names['first']()
type(obj)
<class 'yourmodule.A'>
Or, if your classes are stored somewhere else, say in a module called mymodule:
import mymodule
obj = getattr(mymodule, 'A')()

new class instance not being initialized

I'm writing a package, and doing my testing like a good little programmer, but here's what happens:
class TestOne(unittest.TestCase):
def setUp(self):
self.finder = Finder()
def test_default_search_parts(self):
self.assertEqual(self.finder.search_parts, [])
class TestTwo(unittest.TestCase):
def setUp(self):
self.finder = Finder()
def test_add_letter(self):
self.finder.add('a')
self.assertNotEqual(self.finder.search_parts, [])
in this case, test_default_search_parts fails with AssertionError: ['a'] != [], and test_add_letter passes. I don't know what's going on here. It gets really weird when I rewrite test_default_search_parts:
def test_default_search_parts(self):
f = Finder()
self.assertEqual(f.search_parts, [])
the same failure occurs. What am I doing wrong here with initializing my instances?
Oh, and I'm using nose to run them, if that matters.
As #samplebias mentioned, shared state, in this case with class-level attributes, can cause problems. Here is a possible situation you have:
import unittest
# bad implementation of Finder, class-level attribute
class Finder(object):
search_parts = []
def add(self, letter):
self.search_parts.append(letter)
# using 'Zne' here makes sure this test is run second
class TestZne(unittest.TestCase):
def setUp(self):
print 'I am run next'
self.finder = Finder()
def test_default_search_parts(self):
self.assertEqual(self.finder.search_parts, [])
class TestTwo(unittest.TestCase):
def setUp(self):
print 'I am run first'
self.finder = Finder()
def test_add_letter(self):
self.finder.add('a')
self.assertNotEqual(self.finder.search_parts, [])
unittest.main()
Outputs
Traceback (most recent call last):
File "test.py", line 18, in test_default_search_parts
self.assertEqual(self.finder.search_parts, [])
AssertionError: Lists differ: ['a'] != []
The problem being that all Finder instances share this class-level attribute search_parts, and add_letter is being run before the default search test.
To resolve, use something like:
class Finder(object):
def __init__(self):
self.search_parts = []
This will ensure it is an instance attribute only.

Categories