How to enforce unicode arguments for methods?
Question
I have a model class with getter and setter methods, and the occasional static methods. I would like to enforce the usage of unicode strings as arguments for specific methods and using decorators was the first idea I had. Now I have something like this:
import types
class require_unicode(object):
def __init__(self, function):
self.f = function
def __call__(self, string):
if not isinstance(string, types.UnicodeType):
raise ValueError('String is not unicode')
return self.f(string)
class Foo(object):
something = 'bar'
@staticmethod
@require_unicode
def do_another(self, string):
return ' '.join(['baz', string])
@require_unicode
def set_something(self, string):
self.something = string
foo = Foo()
foo.set_something('ValueError is raised')
foo.set_something(u'argument count error')
foo.do_another('ValueError is raised')
foo.do_another(u'argument count error')
In the above code the method call inside decorator's __call__
fails due to wrong argument count (because the 'foo' object ref is missing?). Before doing something stupid I wanted to ask you guys. How this should be done?
Solution
I think, your problem is with the @staticmethod decorator, not with your require_unicode decorator. Staticmethods, unlike classmethods don't receive the reference to the class as the first argument, so your argument signature is wrong.
You must either change do_another to be a @classmethod, or remove self
from the arguments.
EDIT: and, mind you, - @classmethod-decorated methods receive the class as the first argument, while instance methods receive the reference to the instance of the class (self). So it is a good idea to name the first argument to a classmethod "cls" or something, not "self" so it doesn't confuse anyone.
OTHER TIPS
I would think that this was unpythonic - you should never check the type of your arguments, but instead check that they have the necessary methods and attributes. The simplest way to do this is by assuming they are there and getting an exception otherwise, but I guess you could do getattr
too. Just don't check the type of things.
Another option is to use assertions. It depends on whether passing a non-unicode type into your methods should be considered a programming error that should be evident during development.
import types
class Foo:
def set_something(self, string):
assert isinstance(string, types.UnicodeType), 'String is not unicode'
self.something = string
This will raise an AssertionError
exception whenever string
is not of type unicode, but only when the Python interpretter is run in "deubg" mode. If you run Python with the -O
option, the assert is efficiently ignored by the interpretter.