raise exception in __init__ if parameter not found - python

I have a construction like:
def __init__(self, my_param):
if my_param:
self.my_param = my_param
else:
raise MYException()
and I am using this value somewhere like value=self.my_param
but when I dont pass the my_param it doesnot raise exception but says class object does not have my_param
How can I raise it properly?

Actually When you don't pass an argument to your function, raising an TypeError exception is exactly what python does by itself, which I think There is no need to override this exception :) :
TypeError: __init__() takes exactly 2 arguments (1 given)
But you can also use *args to pass a tuple of arguments to your constructor in order to check the validity of args which will pass an empty tuple if you don't pass anything:
class a(object):
def __init__(self, *args):
if args:
self.param = args[0]
else:
raise Exception("Please pass a parameter to instance")
Also as a practical and not pythonic approach you can use a decorator to wrap your constructor:
def my_exp(func):
def wrapper(*args, **kwds):
if args:
return func(*args)
else:
raise Exception("Pleas pass an argument to instance")
return wrapper()
class a(object):
#my_exp
def __init__(self, my_param):
self.param = my_param
Demo :
instance = a()
Traceback (most recent call last):
File "/home/kasra/Desktop/ex2.py", line 11, in <module>
class a(object):
File "/home/kasra/Desktop/ex2.py", line 12, in a
#my_exp
File "/home/kasra/Desktop/ex2.py", line 9, in my_exp
return wrapper()
File "/home/kasra/Desktop/ex2.py", line 8, in wrapper
raise Exception("Pleas pass an argument to instance")
Exception: Pleas pass an argument to instance
You can also use another tools like functools.wraps or etc. in order to create more flexible decorators. But still I recommend to let python does the job for you!

This should work,
def __init__(self, my_param=None):
if my_param:
self.my_param = my_param
else:
raise MYException()

Related

Issues passing self to class decorator in python

I am new to decorators but ideally I wan to use them to simply define a bunch of class functions within class OptionClass, each representing some particular option with a name and description and if it's required. I don't want to modify the operation of the class function at all if that makes sense, I only want to use the decorator to define name, description, and if it's required.
Problem 1: I construct an OptionClass() and I want to call it's option_1. When I do this I receive a TypeError as the call decorator is not receiving an instance of OptionClass. Why is this? When I call option_1 passing the instance of OptionClass() it works. How do I call option_1 without needing to always pass the instance as self.
The error when received is:
Traceback (most recent call last):
File "D:/OneDrive_P/OneDrive/projects/python/examples/dec_ex.py", line 110, in <module>
print(a.option_1("test")) # TypeError: option1() missing 1 required positional argument: 'test_text'
File "D:/OneDrive_P/OneDrive/projects/python/examples/dec_ex.py", line 80, in __call__
return self.function_ptr(*args, **kwargs)
TypeError: option_1() missing 1 required positional argument: 'test_text'
Problem 2: How would I run or call methods on the decorator to set_name, set_description, set_required?
Problem 3: Although this is a sample I intend to code an option class using async functions and decorate them. Do I need to make the decorator call be async def __call__() or is it fine since it's just returning the function?
class option_decorator(object):
def __init__(self, function_pt):
self.function_ptr = function_pt
self.__required = True
self.__name = ""
self.__description = ""
def set_name(self, text):
self.__name = text
def set_description(self, text):
self.__description = text
def set_required(self,flag:bool):
self.__required = flag
def __bool__(self):
"""returns if required"""
return self.__required
def __call__(self, *args, **kwargs):
return self.function_ptr(*args, **kwargs)
def __str__(self):
"""prints a description and name of the option """
return "{} - {}".format(self.__name, self.__description)
class OptionClass(object):
"""defines a bunch of options"""
#option_decorator
def option_1(self,test_text):
return("option {}".format(test_text))
#option_decorator
def option_2(self):
print("option 2")
def get_all_required(self):
"""would return a list of option functions within the class that have their decorator required flag set to true"""
pass
def get_all_available(self):
"""would return all options regardless of required flag set"""
pass
def print_all_functions(self):
"""would call str(option_1) and print {} - {} for example"""
pass
a = OptionClass()
print(a.option_1("test")) # TypeError: option1() missing 1 required positional argument: 'test_text'
print(a.option_1(a,"test")) #Prints: option test
Problem 1
You implemented the method wrapper as a custom callable instead of as a normal function object. This means that you must implement the __get__() descriptor that transforms a function into a method yourself. (If you had used a function this would already be present.)
from types import MethodType
class Dec:
def __init__(self, f):
self.f = f
def __call__(self, *a, **kw):
return self.f(*a, **kw)
def __get__(self, obj, objtype=None):
return self if obj is None else MethodType(self, obj)
class Foo:
#Dec
def opt1(self, text):
return 'foo' + text
>>> Foo().opt1('two')
'footwo'
See the Descriptor HowTo Guide
Problem 2
The callable option_decorator instance replaces the function in the OptionClass dict. That means that mutating the callable instance affects all instances of OptionClass that use that callable object. Make sure that's what you want to do, because if you want to customize the methods per-instance, you'll have to build this differently.
You could access it in class definition like
class OptionClass(object):
"""defines a bunch of options"""
#option_decorator
def option_1(self,test_text):
return("option {}".format(test_text))
option_1.set_name('foo')
Problem 3
The __call__ method in your example isn't returning a function. It's returning the result of the function_ptr invocation. But that will be a coroutine object if you define your options using async def, which you would have to do anyway if you're using the async/await syntax in the function body. This is similar to the way that yield transforms a function into a function that returns a generator object.

Multiple Inheritance With Same Method Names but Different Arguments Creates TypeError

I have a four distinct classes. There is a main base/parent class, two main classes that inherit from this parent class, and another class that inherits from both of these main classes. If I have a method with the same name but a different number of arguments as a parent class, I get a TypeError.
# Example
class Parent(object):
def check(self, arg):
tmp = {
'one': False,
'two': False
}
try:
if 'one' in arg:
tmp['one'] = True
if 'two' in arg:
tmp['two'] = True
except TypeError:
pass
return tmp
class Child(Parent):
def check(self, arg):
return Parent.check(self, arg)['one']
def method(self, arg):
if self.check(arg):
print 'One!'
class ChildTwo(Parent):
def check(self, arg):
return Parent.check(self, arg)['two']
def method(self, arg):
if self.check(arg):
print 'Two!'
class ChildThree(Child, ChildTwo):
def check(self, arg, arg2):
print arg2
return Child.check(self, arg)
def method(self, arg):
if self.check(arg, 'test'):
print 'One!'
ChildTwo.method(self, arg)
test = ChildThree()
test = test.method('one and two')
runfile('untitled6.py', wdir='./Documents')
test
One!
Traceback (most recent call last):
File "< stdin >", line 1, in < module >
File "C:\Users\py\AppData\Local\Continuum\Anaconda2\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 714, in runfile
execfile(filename, namespace)
File "C:\Users\py\AppData\Local\Continuum\Anaconda2\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 74, in execfile
exec(compile(scripttext, filename, 'exec'), glob, loc)
File "untitled6.py", line 49, in
test = test.method('one and two')
File "untitled6.py", line 46, in method
ChildTwo.method(self, arg)
File "untitled6.py", line 34, in method
if self.check(arg):
TypeError: check() takes exactly 3 arguments (2 given)
However, when I remove the second argument from the 'check' method in 'ChildThree', it seems to work fine:
class ChildThree(Child, ChildTwo):
def check(self, arg):
return Child.check(self, arg)
def method(self, arg):
if self.check(arg):
print 'One!'
ChildTwo.method(self, arg)
runfile('untitled6.py', wdir='./Documents')
One!
Two!
I am fairly new to classes/inheritance, so I am not sure why an extra argument causes a TypeError even though it calls the parent class method with a single argument.
Consider this line:
ChildTwo.method(self, arg)
You passed in self explicitly. self here is a reference to a ChildThree instance. Later, in the body of ChildTwo.method:
if self.check(arg):
It's the same self we're talking about here; self is still a reference on your ChildThree instance.
It looks like you expected self to do something magical, but it doesn't - it's just a plain old name. For it to refer to a ChildTwo instance it would have had to be called like a bound method. Compare and contrast:
my_child_two.method(arg) <-- "self" gets passed implicitly by descriptor protocol
ChildTwo.method(self, arg) <-- "self" is just whatever it is
This type of inheritance is called "The Diamond Problem". It is a topic for itself, so I'll explain on a simpler case:
class C1(object):
def check(self, arg):
return 1
def method(self, arg):
return self.check(arg)
class C2(C1):
def check(self, arg1, arg2): # this overrides C1.check!
return x + C1.check(self, arg1)
c2 = C2()
c2.method(55) # fails
C2.check overrides C1.check on all C2 instances. Therefore, when self.check(arg) is called from method, it calls C2.check for instances of C2. That will fail because C2.check takes two arguments.
How to resolve that? When overriding methods, do not change their signature (number and type of received arguments and type of return value), or you'll get in trouble.
[more advanced] You could have more freedom with functions which take *args and **kwargs.
Besides that, I see that ChildThree.check calls Child.check which calls Parent.check, but noone calls ChildTwo.check. That cannot be right.
You should either call the method on all base classes (and risk calling the Parent implementation twice, which may even be right here), or use super().

UnitTest Python Mock first call to method, second call go as usual

I am mocking a method. I want to raise an exception on the first call, but on exception, I am calling that method again with different parameters, so I want the second call to be processed normally. What do I need to do?
Code
Try 1
with patch('xblock.runtime.Runtime.construct_xblock_from_class', Mock(side_effect=Exception)):
Try 2
with patch('xblock.runtime.Runtime.construct_xblock_from_class', Mock(side_effect=[Exception, some_method])):
On the second call, some_method is returned as it is, and data is not processed with different parameters.
class Foo(object):
def Method1(self, arg):
pass
def Method2(self, arg):
if not arg:
raise
self.Method1(arg)
def Method3(self, arg):
try:
self.Method2(arg)
except:
self.Method2('some default value')
class FooTest(unittest.TestCase):
def SetUp(self):
self.helper = Foo()
def TestFooMethod3(self):
with mock.patch.object(self.helper, 'Method2',
side_effect=[Exception,self.helper.Method1]
) as mock_object:
self.helper.Method3('fake_arg')
mock_object.assert_has_calls([mock.call('fake_arg'),
mock.call('some default value')])

Decorator to invoke instance method

I have a class A with method do_something(self,a,b,c) and another instance method that validates the input and check permissions named can_do_something(self,a,b,c).
This is a common pattern in my code and I want to write a decorator that accepts a validation function name and perform the test.
def validate_input(validation_fn_name):
def validation_decorator(func):
def validate_input_action(self,*args):
error = getattr(self,validation_fn_name)(*args)
if not error == True:
raise error
else:
return func(*args)
return validate_input_action
return validation_decorator
Invoking the functions as follows
#validate_input('can_do_something')
def do_something(self,a,b,c):
return a + b + c
Problem is that i'm not sure how to maintain self through out the validation function. I've used the validation fn name with getattr so the fn could be ran in the context of the instance but i cannot do that for func(*args).
So what is the proper way to achieve this ?
Thanks.
EDIT
So following #André Laszlo answer I realized that self is just the first argument so there is no need to use getattr at all but just pass on the *args.
def validate_input(validation_fn):
def validation_decorator(func):
def validate_input_action(*args):
error = validation_fn(*args)
if not error == True:
raise error
else:
return func(*args)
return validate_input_action
return validation_decorator
Much more elegant and it also supports static methods as well.
Adding a static method to #André Laszlo example proves the decorator is working :
class Foo(object):
#staticmethod
def validate_baz(a,b,c):
if a > b:
return ValueError('a gt b')
#staticmethod
#validate_input(Foo.validate_baz)
def baz(a,b,c):
print a,b,c
>>> Foo.baz(1,2,3)
1 2 3
>>> Foo.baz(2,1,3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in validate_input_action
ValueError: a gt b
But, when i'm trying to do them same thing in a django model:
from django.db import models
from django.conf import settings
settings.configure()
class Dummy(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=10)
def can_say_name(self):
if name is None:
return Exception('Does not have a name')
#validate_input(can_say_name)
def say_name(self):
print self.name
#staticmethod
def can_create_dummy(name):
if name == 'noname':
return Exception('No name is not a name !')
#staticmethod
#validate_input(Dummy.can_create_dummy)
def create_dummy(name):
return Dummy.objects.create(name=name)
I get the following :
NameError: name 'Dummy' is not defined
So what is the different between a django model and an Object in relation to this issue ?
I think this does what you want:
def validate_input(validation_fn_name):
def validation_decorator(func):
def validate_input_action(self, *args):
error = getattr(self, validation_fn_name)(*args)
if error is not None:
raise error
else:
arglist = [self] + list(args)
return func(*arglist)
return validate_input_action
return validation_decorator
class Foo(object):
def validate_length(self, arg1):
if len(arg1) < 3:
return ValueError('%r is too short' % arg1)
#validate_input('validate_length')
def bar(self, arg1):
print "Arg1 is %r" % arg1
if __name__ == "__main__":
f = Foo()
f.bar('hello')
f.bar('')
Output is:
Arg1 is 'hello'
Traceback (most recent call last):
File "validator.py", line 27, in <module>
f.bar('')
File "validator.py", line 6, in validate_input_action
raise error
ValueError: '' is too short
Updated answer
The error (NameError: name 'Dummy' is not defined) occurs because the Dummy class is not defined yet when the validate_input decorator gets Dummy as an argument. I guess this could have been implemented differently, but for now that's the way Python works. The easiest solution that I see is to stick to using getattr, which will work because it looks up the method at run time.

What does cls() function do inside a class method?

Today I'm viewing another's code, and saw this:
class A(B):
# Omitted bulk of irrelevant code in the class
def __init__(self, uid=None):
self.uid = str(uid)
#classmethod
def get(cls, uid):
o = cls(uid)
# Also Omitted lots of code here
what does this cls() function do here?
If I got some other classes inherit this A class, call it C, when calling this get method, would this o use C class as the caller of cls()?
cls is the constructor function, it will construct class A and call the __init__(self, uid=None) function.
If you enherit it (with C), the cls will hold 'C', (and not A), see AKX answer.
For classmethods, the first parameter is the class through which the class method is invoked with instead of the usual self for instancemethods (which all methods in a class implicitly are unless specified otherwise).
Here's an example -- and for the sake of exercise, I added an exception that checks the identity of the cls parameter.
class Base(object):
#classmethod
def acquire(cls, param):
if cls is Base:
raise Exception("Must be called via subclass :(")
return "this is the result of `acquire`ing a %r with %r" % (cls, param)
class Something(Base):
pass
class AnotherThing(Base):
pass
print Something.acquire("example")
print AnotherThing.acquire("another example")
print Base.acquire("this will crash")
this is the result of `acquire`ing a <class '__main__.Something'> with 'example'
this is the result of `acquire`ing a <class '__main__.AnotherThing'> with 'another example'
Traceback (most recent call last):
File "classmethod.py", line 16, in <module>
print Base.acquire("this will crash")
File "classmethod.py", line 5, in acquire
raise Exception("Must be called via subclass :(")
Exception: Must be called via subclass :(
It's a class factory.
Essentially it the same as calling:
o = A(uid)
cls in def get(...): is A.

Categories