So I have a class that extends two classes deep, here is it's definition and __init__():
class ProspectEventSocketProtocol(ChannelEventSocketProtocol):
def __init__(self, *args, **kwargs):
super(ProspectEventSocketProtocol, self).__init__(*args, **kwargs)
self.channel_info = None
self.rep_uuid = None
self.manual_dial = None
self.datetime_setup = timezone.now()
self.datetime_answered = None
self.defer_until_answered = defer.Deferred()
self.defer_until_originated = defer.Deferred()
self.defer_until_finished = defer.Deferred()
The definition and __init__() for the ChannelEventSocketProtocol is here:
class ChannelEventSocketProtocol(Freeswitch):
def __init__(self, *args, **kwargs):
self.channel_driver = None
self.uuid = kwargs.pop('uuid', str(uuid4()))
self._call_driver = kwargs.pop('call_driver', None)
super(ChannelEventSocketProtocol, self).__init__(*args, **kwargs)
And the definition and __init__() for the Freeswitch class is here:
class Freeswitch(client.EventSocketProtocol, TwistedLoggingMixin):
def __init__(self, *args, **kwargs):
self.jobs = {}
self.defer_until_authenticated = defer.Deferred() # This is the problem
client.EventSocketProtocol.__init__(self, *args, **kwargs)
TwistedLoggingMixin.__init__(self)
Even though I know that this is running and the defer_until_authenticated is being set as well as it's callback and errback, when I call this:
live_call = yield self._create_client_dial_live_call(client_dial.cid, client_dial.campaign)
pchannel = yield self.realm.get_or_create_channel_driver(live_call.uuid, 'prospect')
# ...
client_dial.prospect_channel = pchannel
yield pchannel.freeswitch_protocol.defer_until_authenticated # This is the problem here!
I get the error:
type object 'ProspectEventSocketProtocol' has no attribute 'defer_until_authenticated'
I have no idea why I can't get the attribute again. I know it is being set, but I have no idea where it goes... or what happens to it. I've searched the error and I have no idea what is happening in this spot.
Just for reference, here are the _create_client_dial_live_call() and get_or_create_channel_driver() functions:
def _create_client_dial_live_call():
# ...
p, created = Prospect.objects.get_or_create_client_dial_prospect(campaign, cid_num)
# ...
live_call = LiveCall(prospect=p, campaign=campaign.slug)
live_call.channel_vars_dict = chan_vars
live_call.save()
# ...
def get_or_create_channel_driver()
# The code is kind of confusing with even more context,
# it basically either gets the existing ProspectChannel
# object or creates a new one and then returns it.
Something somewhere is forgetting to instantiate a class.
The error is not telling you that an instance of the class ProspectEventSocketProtocol has no attribute defer_until_authenticated. It's telling you that the class ProspectEventSocketProtocol itself has no such attribute.
In other words, you are quite probably writing something like
pchannel.freeswitch_protocol = ProspectEventSocketProtocol
when you want
pchannel.freeswitch_protocol = ProspectEventSocketProtocol(...)
instead.
Here's a quick demo script that reproduces the error message you are seeing:
#!/usr/bin/env python3
class Test(object):
def __init__(self):
self.arg = "1234"
correct = Test()
print(correct.arg)
wrong = Test
print(wrong.arg)
When I run it, I get the following output:
1234
Traceback (most recent call last):
File "./type_object_error.py", line 12, in <module>
print(wrong.arg)
AttributeError: type object 'Test' has no attribute 'arg'
Related
I want to unit test this class method update
class EmployeeUpdateSerializer(serializers.ModelSerializer):
def update(self, instance, data):
shift_types = data.pop('shift_types', None)
instance = super().update(instance, data)
self.update_shift_type(instance, shift_types)
return instance
I am doing this
class TestEmployeeUpdateSerializer(TestCase):
def setUp(self):
self.company, self.user, self.header = create_user_session()
self.serializer = EmployeeUpdateSerializer()
def test_update(self):
employee = self.user
with patch.object(self.serializer, 'update') as update:
with patch.object(self.serializer, 'update_shift_type') as update_shift_type:
res = self.serializer.update(employee, dict())
update.assert_called_once_with(employee, dict())
update_shift_type.assert_called_once_with(employee, None)
self.assertEqual(res, employee)
But this gives me an error
Traceback (most recent call last):
File "/Users/shahzadfarukh/my-croft/backend/account/tests/test_employee_serializers.py", line 222, in test_update
update_shift_type.assert_called_once_with(employee, None)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/mock.py", line 830, in assert_called_once_with
raise AssertionError(msg)
AssertionError: Expected 'update_shift_type' to be called once. Called 0 times.
Please help me! is something I am doing wrong?
You have mocked update, so its original code won't get called. If you want to test what update calls, you have to call the original version, and mock only functions/methods called within the update. Assuming the base class is imported like import serializers, you could do something like this (untested)
class TestEmployeeUpdateSerializer(TestCase):
def setUp(self):
self.company, self.user, self.header = create_user_session()
self.serializer = EmployeeUpdateSerializer()
#patch('serializers.ModelSerializer.update')
#patch('serializers.ModelSerializer.update_shift_type')
def test_update(self, mocked_update_shift_type, mocked_update):
employee = self.user
res = self.serializer.update(employee, dict())
mocked_update.assert_called_once_with(employee, dict())
mocked_update_shift_type.assert_called_once_with(employee, None)
self.assertEqual(res, employee)
Hello I have the following situation:
A specialized class that inherits from two parent class
The need to define the most specialized class at run time, based on some information that I get only when I start reading data from a database.
I defined the following code to handle the create all the classes in the chain:
class BusinessDocument():
#staticmethod
def get_class(doc_type):
switch = {
'MasterData': MasterData,
'Transactional': Transactional
}
func = switch.get(doc_type, lambda: "Invalid Noun Type")
return func()
def __init__(self, doc_id, location, doc_type):
self.doc_id = doc_id
self.location = location
self.doc_type = doc_type
pass
#property
def get_location(self):
return self.location
#property
def get_doc_id(self):
return self.doc_id
class MasterData(BusinessDocument):
def __init__(self, doc_id, location):
BusinessDocument.__init__(self, doc_id, location, 'MasterData')
class Transactional(BusinessDocument):
def __init__(self, doc_id, location):
BusinessDocument.__init__(self, doc_id, location, 'Transactional')
class NounClass():
#staticmethod
def get_class(doc_name, doc_type):
return type(doc_name, (BusinessDocument.get_class(doc_type),
BusinessDocument, ),dict.fromkeys(['doc_id', 'location']))
Then at run time when I get the doc_name and I try to create a new class. At this point I may not have the required arguments doc_id and location but I need to class type.
invoice_cls = NounClass.get_class('Invoice', 'Transactional')
I get the following error:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-10-cb774746875a> in <module>
----> 1 invoice_cls = NounClass.get_class('Invoice', 'Transactional')
<ipython-input-9-aa5e0b316ed1> in get_class(doc_name, doc_type)
35 #staticmethod
36 def get_class(doc_name, doc_type):
---> 37 return type(doc_name, (BusinessDocument.get_class(doc_type),
38 BusinessDocument, ),dict.fromkeys(['doc_id', 'location']))
<ipython-input-9-aa5e0b316ed1> in get_class(doc_type)
7 }
8 func = switch.get(doc_type, lambda: "Invalid Noun Type")
----> 9 return func()
10
11 def __init__(self, doc_id, location, doc_type):
TypeError: __init__() missing 2 required positional arguments: 'doc_id' and 'location'
I understand that the reason for it is because the __init__() will be called during the class instantiation, but I thought that type would be only creating a new type and not instantiate one right away. So my question is if is there a way to defer the instantiation of the instance at this time.
Thank you in advance for any help and tips on this.
--MD.
The initalization occurs on line 9:
return func()
I assume you want to return a class object, so remove those parantheses.
Also func is misleding, I've changed it to cls:
def get_class(doc_type):
switch = {
'MasterData': MasterData,
'Transactional': Transactional
}
cls = switch.get(doc_type, lambda: "Invalid Noun Type")
return cls
I am using Python 3.5 and i try to print the number of function-calls with python-decorator. So here is my example:
import inspect
def logWrapper(func):
def wrapper_func(self, *args, **kwargs):
wrapper_func.calls += 1
self.logger.info('Func: {}' .format(func.__name__) )
return func(self, *args, **kwargs)
wrapper_func.calls=0
return wrapper_func
class A:
__init__(self):
print('created')
#logWrapper
def myfunction1(self, var1):
print('var1: {}' .format(var1))
#logWrapper
def myfunction2(self, var2):
print('var2: {}' .format(var2))
if __name__ == "__main__":
Pal1=A()
Pal1.myfunction1('1')
Pal1.myfunction1('2')
Pal1.myfunction1('3')
Pal1.myfunction2('A')
function_list=inspect.getmembers(Pal1, predicate=inspect.ismethod)
for func in function_list:
method_to_call = getattr(A, func[0])
print( 'Function: {}; Calls: {}' .format(func[0], method_to_call.calls))
When i call Pal1.myfunction1.calls and Pal1.myfunction2.calls i got my correct results 3 and 1. But now i like to iterate throw every function of class A. When i try Pal1.func[0].calls i got the error-message *** AttributeError: 'A' object has no attribute 'func', i also tried A.method_to_call.calls and got the same results.
What i am doing wrong?
The problem is that you are calling instance methods as class methods.
For example, you cannot call
A.myfunction1('3')
However you can call,
inst = A()
inst.myfunction1('3')
When this is translated into the getattr syntax, your code becomes
method_to_call = getattr(Pal1, func[0])
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.
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')()