An object that throws an exception for any use.

I need to create an object that will raise a custom exception, UnusableObjectError , when it will be used in any way (creating it should not throw an exception).

 a = UnusableClass() # No error b = UnusableClass() # No error a == 4 # Raises UnusableObjectError 'x' in a # Raises UnusableObjectError for i in a: # Raises UnusableObjectError print(i) # ..and so on 

I came up with the code below, which seems to behave as expected.

 class UnusableObjectError(Exception): pass CLASSES_WITH_MAGIC_METHODS = (str(), object, float(), dict()) # Combines all magic methods I can think of. MAGIC_METHODS_TO_CHANGE = set() for i in CLASSES_WITH_MAGIC_METHODS: MAGIC_METHODS_TO_CHANGE |= set(dir(i)) MAGIC_METHODS_TO_CHANGE.add('__call__') # __init__ and __new__ must not raise an UnusableObjectError # otherwise it would raise error even on creation of objects. MAGIC_METHODS_TO_CHANGE -= {'__class__', '__init__', '__new__'} def error_func(*args, **kwargs): """(nearly) all magic methods will be set to this function.""" raise UnusableObjectError class UnusableClass(object): pass for i in MAGIC_METHODS_TO_CHANGE: setattr(UnusableClass, i, error_func) 

(some improvements made as suggested by Duncan in the comments)


Questions:
Is there an already existing class that behaves as described?

If not, is there a flaw in my UnusableClass() (for example, a situation where using class instances did not raise an error), and if so, how can I fix these flaws?

+5
source share
2 answers

Turns off metaclasses, and the dunder (double underscore) methods do not combine well (which is unsuccessful, as this would be a more simplified way to implement this).

I could not find any imported list of magic method names, so I created it and posted it on PyPi ( https://pypi.python.org/pypi/magicmethods/0.1.1 ). With its help, the UnusableClass implementation can be written as a simple class decorator:

 import magicmethods class UnusableObjectError(Exception): pass def unusable(cls): def _unusable(*args, **kwargs): raise UnusableObjectError() for name in set(magicmethods.all) - set(magicmethods.lifecycle): setattr(cls, name, _unusable) return cls @unusable class UnusableClass(object): pass 

magicmethods.lifecycle contains __new__ , __init__ and __del__ . You can customize this.

This implementation also handles:

 a = UnusableClass() with a: print 'oops' 
+2
source

You can use __getattribute__ to block access to all attributes, except for special __ attributes, such as __contains__ or __eq__ , which are not caught by __getattribute__ , and use whitelist to allow access to some methods:

 class UnuseableClass(object): whitelist = ('alpha', 'echo',) def __init__(self): self.alpha = 42 def echo(self, text): print text def not_callable(self): return 113 def __getattribute__(self, name): if name in type(self).whitelist: return super(UnuseableClass, self).__getattribute__(name) else: raise Exception('Attribute is not useable: %s' % name) unuseable_object = UnuseableClass() print(unuseable_object.alpha) unuseable_object.echo('calling echo') try: unuseable_object.not_callable() except Exception as exc: print(exc.message) 

If you really need to catch even special method calls, you can use How to catch any method called by an object in python? .

+1
source

All Articles