dynamically defined class not visible in importing module python - python

A temporary exception class is defined dynamically using 'type' in a python script meant to be used as module. When an instance of this class is caught in importing script it doesn't recognize the class.
Below is code snippet
# the throwing module, defines dynamically
def bad_function():
ExceptionClass = type( "FooBar", (Exception,),
{ "__init__": lambda self, msg: Exception.__init__(self, msg) })
raise ExceptionClass("ExceptionClass")
the using code
import libt0
try:
libt0.bad_function()
#except libt0.FooBar as e:
#print e
except Exception as e:
print e
print e.__class__
can it be explained why libt0.FooBase is not visible to this script? observer output of last line.

It's not clear how you expect FooBar to exist without doing something like this
def bad_function():
ExceptionClass = type( "FooBar", (Exception,),
{ "__init__": lambda self, msg: Exception.__init__(self, msg) })
globals()['FooBar'] = ExceptionClass
raise ExceptionClass("ExceptionClass")

You created the class inside a function, so it doesn't exist as a name in the module's global namespace. In fact, it doesn't exist at all except while bad_function is executing. It's the same reason why this fails:
# file1.py
def good_function():
x = 2
# file2.py
import file1
print file1.x
Your exception class is just a local variable inside bad_function.

Related

How to access a variable outside of a class function if it wasn't passed to the function

I have been tasked to modify the behavior of a function in one of our Python classes.
Our function takes a few parameters, one being a debug flag. Currently the if the debug flag is not specified then we assume it to be False. What we need it to do is when debug is not specified, check the variable "debug" from the calling code and use that value, if it exists.
I would simply change the name of the debug parameter in the function declaration, except that we have a lot of legacy code that uses that flag.
This is in Jupyter Lab, if it makes any difference.
Sample code:
class MyClass:
#classmethod
def fn(self, debug=None):
if debug is None:
try:
debug = parent.debug
except Exception as e:
print(e)
debug = "BAD"
return debug
debug = True
x = myClass
print( x.fn() )
I would want the output to be "True" but it ends up being:
global name 'parent' is not defined
BAD
Is what I am trying to do possible? If so, how?
Use globals()['debug'] instead.
Or replace your fn() method to:
#classmethod
def fn(self, debug=None):
if debug is None:
debug = globals().get('debug', 'BAD')
return debug
You access variable parent which us not defined in your code.
Firstly, the MyClass in your code isn't inherited from any other class. Technically, the class doesn't have any parent(except the obj class by default), so it's impossible to access something that doesn't exist like 'parent.debug'. Secondly, as for your problem, I'm assuming that you want to access the debug variable that is initialized outside the class then you can easily do that by doing something like this:
global debug
class MyClass:
#classmethod
def fn(self, debug=None):
if debug is None:
try:
debug = debugOut
except Exception as e:
print(e)
debug = "BAD"
return debug
debugOut = True
x = MyClass()
print(x.fn())
The above code returns True

How to prevent methods from being called if something went wrong within __init__?

I'm building this class called LanguagePack. It loads a .csv files from harddrive and parse it. I broke the initialisation process into 3 separate functions (is this appropriate?) and I want to disabled all methods if this initialisation failed.
class LanguagePack:
def __init__ (self):
try:
self._read ()
self._validator ()
self._slice ()
except UnicodeDecodeError:
print ('File is not in UTF-8 (BOM) encoding.')
except KeyError:
print ('Column name incomplete.')
except:
print ('Unknown error.')
else:
pass
def _read (self):
pass
def _validator (self):
pass
def _slice (self):
pass
def foo (self):
pass
Currently even if something went wrong during initialisation, the methods (like foo) is still callable. These method are dependent on the variables created during initialisation. Unpredicatable errors would occur.
The simplest thing to do is re-raise each exception you haven't handled.
class LanguagePack:
def __init__ (self):
try:
self._read ()
self._validator ()
self._slice ()
except UnicodeDecodeError:
print ('File is not in UTF-8 (BOM) encoding.')
raise
except KeyError:
print ('Column name incomplete.')
raise
except Exception:
print ('Unknown error.')
raise
Consider having each of the helper methods _read et al. do their own logging, rather than catching and re-raising the exceptions in __init__.
LanguagePack.__init__ may not know how to handle these errors, but whoever is creating the instance might. Let them decide whether to
catch and ignore the exception that __init__ itself (re)raises.
try to instantiate the class again (in either the same or a different way)
give up and exit the program
do something else
If you really want to keep the instance, although it could not be initialized correctly, you could just overload the __getattr__ method and check for some flag you raise, when you catch an exception.
You should use the __new__ function:
class LanguagePack:
def __new__ (cls):
try:
#do your checks here isntead of _read, _validator and _slice
except UnicodeDecodeError:
print ('File is not in UTF-8 (BOM) encoding.')
return None
except KeyError:
print ('Column name incomplete.')
return None
except:
print ('Unknown error.')
return None
else:
#if you're class is of basic type object:
return object.__new__(cls)
#this will return the class object and call your init
def __init__(self):
#do some stuff if you need
pass
Use __new__ funcion only if you need to check something during the class creation or if you want to return something (__init__ returns None)

why is pylint complaining about missing Exception.message?

I usually declare a base exception for my modules which does nothing, from that one I derive custom errors that could have additional custom data: AFAIK this is the Right Way™ to use exeptions in Python.
I'm also used to build a human readable message from that custom info and pass it along, so I can refer to that message in error handlers. This is an example:
# this code is meant to be compatible with Python-2.7.x
class MycoolmoduleException(Exception):
'''base Mycoolmodule Exception'''
class TooManyFoo(MycoolmoduleException):
'''got too many Foo things'''
def __init__(self, foo_num):
self.foo_num = foo_num
msg = "someone passed me %d Foos" % foo_num
super(TooManyFoo, self).__init__(msg)
# .... somewhere else ....
try:
do_something()
except Exception as exc:
tell_user(exc.message)
# real world example using Click
#click.command()
#click.pass_context
def foo(ctx):
'''do something'''
try:
# ... try really hard to do something useful ...
except MycoolmoduleException as exc:
click.echo(exc.message, err=True)
ctx.exit(-1)
Now, when I run that code through pylint-2.3.1 it complains about my use of MycoolmoduleException.message:
coolmodule.py:458:19: E1101: Instance of 'MycoolmoduleException' has no 'message' member (no-member)
That kind of code always worked for me (both in Python2 and Python3) and hasattr(exc, 'message') in the same code returns True, so why is pylint complaining? And/or: how could that code be improved?
(NB the same happens if I try to catch the built in Exception instead of my own MycoolmoduleException)

Simplify try-except blocks in Python

I have a number of modules. They all have similar try-except blocks in each file, like this:
from shared.Exceptions import ArgException # and others, as needed
try:
do_the_main_app_here()
except ArgException as e:
Response.result = {
'status': 'error',
'message': str(e)
}
Response.exitcode('USAGE')
# more blocks like the above
with ArgException (and other exceptions) being defined as:
from abc import ABCMeta, abstractmethod
class ETrait(Exception):
__metaclass__ = ABCMeta
#abstractmethod
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
class ArgException(ETrait): pass
Since every module uses similar code to catch exceptions, is there a way to put the exception catching into a shared file that is used by all modules?
I would not do that, but you could create a function in a module like :
from shared.Exceptions import ArgException # and others, as needed
def try_exec(execution_function)
try:
execution_function()
except ArgException as e:
Response.result = {
'status': 'error',
'message': str(e)
}
Response.exitcode('USAGE')
and then call try_exec(do_the_main_app_here) whenever you need to try catch your block of instructions, passing the parameters you need to have the correct context.
The answer is Yes, you can create a module to do that.
The easiest way would be to create a function accepting two parameters: another function with the code that you want to "try" and an "action" to be taken in case of exception.
Then:
def myModuleFunction(tryThisCode, doThis):
try:
returnValue = tryThisCode()
return returnValue
except ArgException as e:
if (doThis == "doThat"):
...
else:
...
Then, after importing your new module, you can use your function like this:
myModuleFunction(divideByZero, 'printMe')
Assuming you have a function called divideByZero();
I hope this helps.

How do I handle user defined exceptions in Python?

If I have an Error module defined containing my application defined exceptions as something like:
class Error(Exception):
pass
class NoSchemaVersion(Error):
def __init__(self):
self.code = 1
self.msg = "No schema version specified"
pass
class NoMsgType(Error):
def __init__(self):
self.code = 2
self.msg = "No message type specified"
pass
How do I would I handle specific exceptions when they are raised. I tried something like:
import Error
errors = Error.Error()
try:
<do some stuff>
except errors.NoMsgType:
<stuff>
but I get the message:
AttributeError: 'Error' object has no attribute 'NoMsgType'
What am I doing wrong?
Error.Error() (stored in error) constructs a new value of the Error class, but NoMsgType is a separate class that isn't actually part of Error, and so error.NoMsgType doesn't exist. To catch a NoMsgType, you should just write except Error.NoMsgType:.
I gues you need to do simething like this:
try:
somecode
except Error.NoMsgType:
morecode

Categories