I want to use a special exception, but I don’t know how to specify it for the following situation:
My Python has several functions at several levels (i.e. by callings). I want to use the special exception at the second level (i.e. in the function which has been called by the function at the first (= root) level). In some functions from the second level I want to use the command ‘raise special-exception(code)’. In the function ‘special-exception(code)’ I want to look at the code. If the code is filled in, then the message must be written with the continuing after the lasting calling in the first level, else (i.e. code is not filled in) the wellknown traceback lines.
Sorry, I don’t understand your explanation of what you are trying to do.
What is code
? What do you mean, “filled in”?
I don’t understand this.
Most importantly, why do you want to mess with the traceback?
Can you show an example of what you want?
def spam():
return eggs()
def eggs():
# Second level, error happens here
...
spam()
Can you show us what traceback you want to see?
Well, I am trying to make it clear:
function1 calls function2 which calls funtion3.
function3 contains (where _ stands for space):
def function3(…):
____…
____…
____def MyException(code):
________import logging
________logging.error('Process MyException: ’ + str(code))
________# How to continue directly after the command '… = function4(…)?
____…
____…
____… = function4(…)
____…
____…
____return …
function4 calls function5 which calls funtion6.
function6 contains (where _ stands for space):
def function6(…):
____import logging
____…
____…
____if …:
________raise MyException(…):
________logging.error('Call MyException(123)
____…
____…
____xxx = 7 / 0
____# which will given a list of tracebacks like:
____# <class ‘ZeroDivisionError’>: division by zero
____# File “…”, line …, in function4: xxx = 7 / 0
____# File “…”, line …, in function3: …
____# File “…”, line …, in function2: …
____# File “…”, line …, in function1: …
____…
____…
____return …
Hopefully it is clear enough for you.
an please tell me how I can create such a block without using ____.
Please edit your post to show the code properly.
I need the solution for the following example:
function1 calls function2 which calls funtion3.
function3 contains:
def function3(…):
import logging
...
...
class MySpecialException(???):
logging.error('MySpecialException is created.')
...
...
try:
result = function4(…)
exception MySpecialException as e:
if e == '123':
logging.error('MySpecialException has been processed ' \\
'with code * + str(e) + '*')
# it must be continued after this try section
else:
# here a list of tracebacks must be created like:
# File “…”, line …, in function5: …
# File “…”, line …, in function4: …
# File “…”, line …, in function3: …
# File “…”, line …, in function2: …
# File “…”, line …, in function1: …
raise (which exception?) in order to end this procedure abnormally
...
...
return
function4 calls function5 which calls funtion6.
function6 contains:
def function6(…):
import logging
...
...
if ... :
logging.error('MySpecialException(123) is called')
raise MySpecialException(123)
...
...
_ = 7 / 0
# which must give a list of tracebacks like:
# <class ‘ZeroDivisionError’>: division by zero
# File “…”, line …, in function6: _ = 7 / 0
# File “…”, line …, in function5: …
# File “…”, line …, in function4: …
# File “…”, line …, in function3: …
# File “…”, line …, in function2: …
# File “…”, line …, in function1: …
...
...
return
Hopefully is this example clear for you in order to be able to give me any suggestion to make it possible.
Exceptions are ordinary classes, obeying the rules of definition.
>>> def fun1():
... class MyException(Exception):
... pass
... raise MyException("It happened")
...
>>> try:
... fun1()
... except MyException:
... print("Caught")
...
Traceback (most recent call last):
File "<input>", line 3, in <module>
except MyException:
NameError: name 'MyException' is not defined
So, unless you want to use exceptions only locally, define your exceptions as global to your module.
Lets continue the session in the REPL:
>>> class MyException(ValueError):
... pass
...
>>> def fun6():
... raise MyException("It happened")
...
>>> def fun5():
... fun6()
... return 1
...
>>> def fun4():
... try:
... fun5()
... except MyException as me:
... print("Caught")
... raise
...
>>> fun4()
Caught
Traceback (most recent call last):
File "<input>", line 1, in <module>
fun4()
File "<input>", line 3, in fun4
fun5()
File "<input>", line 2, in fun5
fun6()
File "<input>", line 2, in fun6
raise MyException("It happened")
MyException: It happened
This is about what you want, but for the code. I will come back to that.
-
The
MyException
class now inherits fromValueError
, which is a child of Exception. Will work also and catching ValueError will also catch MyException -
The traceback (yes, it is only 1 traceback that shows all steps) shows exactly what was called. I printed it by raising it again, it is easy. You can access is also through the
__traceback__
attribute: “A traceback object is normally created automatically when an exception is raised and attached to it as the__traceback__
attribute, which is writable.”.
I would never pass a code to identify what type of exception is raised. Always define multiple exception subclasses and switch between exceptions by type. The syntax makes that easy and your code clearer.
Unless the code came from elsewhere (OSError incorporates the OS-provided error code).
Thank you for supplying an excellent example of what I mean. You could usually identify an OSError by the OS supplied error number, yet it has several subclasses that make the client code easier and clearer. Of course the error number should be kept by the subclasses, so you can always dig deeper.
@Pejamide : What is discussed here is this part of the exception hierarchy:
├── OSError
│ ├── BlockingIOError
│ ├── ChildProcessError
│ ├── ConnectionError
│ │ ├── BrokenPipeError
│ │ ├── ConnectionAbortedError
│ │ ├── ConnectionRefusedError
│ │ └── ConnectionResetError
│ ├── FileExistsError
│ ├── FileNotFoundError
│ ├── InterruptedError
│ ├── IsADirectoryError
│ ├── NotADirectoryError
│ ├── PermissionError
│ ├── ProcessLookupError
│ └── TimeoutError
Most of those errors could be identified by the OSError.errno
attribute:
“The constructor often actually returns a subclass of OSError
, as described in OS exceptions below. The particular subclass depends on the final errno
value.”
Yet, they are distinguished by type to enable you to write easier to understand and clearer code.
>>> try:
... f = open("/usr/local/nofile", "r")
... except FileNotFoundError:
... print("Caught")
...
Caught
I tried as follows:
...
...
def MySpecialExecption(PermissionError):
pass
...
...
try:
...
...
except MySpecialExecption as e:
print('MySpecialExecption has been exceuted here.')
print(e)
...
...
But I got the message as follows:
<class 'TypeError'>: catching classes that do not inherit from BaseException is not allowed
What to do now?
An exception is a class, not a function. Functions do not inherit from BaseException.
>>> def MyException(PermissionError):
... pass
...
>>> try:
... raise MyException("Oops!")
... except MyException as me:
... print(me)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: exceptions must derive from BaseException
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError: catching classes that do not inherit from BaseException is not allowed
>>> class MyException(PermissionError):
... pass
...
>>> try:
... raise MyException("Oops!")
... except MyException as me:
... print(me)
...
Oops!
I have specified in the function ‘fn3’:
class MyException(PermissionError):
pass
And the function ‘fn6’ which is called by fn5, fn4 and fn3 resp.:
raise MyException(123)
But I got the folloeing error message:
<class ‘NameError’>: name ‘ExecptionForReentry’ is not defined
What have i to do yet?
I don’t know. There must be something else going wrong. This works:
>>> class MyException(PermissionError):
... pass
...
>>> raise MyException(123)
Traceback (most recent call last):
File "<input>", line 1, in <module>
raise MyException(123)
MyException: 123
So your original problem is solved. Where in your code does this error come up? You can find that in the traceback. If you want more help, show the traceback,
Also observe that the reported error is a NameError. What is causing that NameError
? Also to be found in the traceback.
I’m very sorry for my previous unclear question.
Hence my corrected question.
The function ‘fn3’ which is called by the functions ‘fn1’ and ‘fn2’ respectively, contains:
...
...
class MyException(PermissionError):
pass
...
...
And the function ‘fn6’ which is called by fn5, fn4 and fn3 respectively. It contains:
...
...
raise MyException(123)
...
...
But I got the following error message:
<class ‘NameError’>: name ‘MyException’ is not defined
with tracebacks:
<class 'NameError'>: name 'MyException' is not defined called by File "fn6.py", line 52, in fn6: raise MyException(123)
... called by File "fn5.py", line 116, in fn5: .......
... called by File "fn4.py", line 100, in fn4: .......
... called by File "fn3.py", line 506, in fn3: .......
Unfortunately I d’not know how to specify each function for your test, as I am using the command ‘importlib.import_module’ for two functions ‘fn3’ and ‘fn6’.
What should I have to do extra?
I’m very sorry for my previous unclear question.
Hence my corrected question.The function ‘fn3’ which is called by the functions ‘fn1’ and ‘fn2’ respectively, contains:
class MyException(PermissionError): pass
Look good.
And the function ‘fn6’ which is called by fn5, fn4 and fn3 respectively. It contains:
raise MyException(123)
Looks good.
But I got the following error message:
<class ‘NameError’>: name ‘MyException’ is not defined
with tracebacks:
<class ‘NameError’>: name ‘MyException’ is not defined called by File “fn6.py”, line 52, in fn6: raise MyException(123)
… called by File “fn5.py”, line 116, in fn5: …
… called by File “fn4.py”, line 100, in fn4: …
… called by File “fn3.py”, line 506, in fn3: …Unfortunately I d'not know how to specify each function for your test, as I am using the command 'importlib.import_module' for two functions 'fn3' and 'fn6'. What should I have to do extra?
It looks like your functions are all defined in separate files. (Is
there a reason for that?) Thus the name fn5
is initially only known
in the code in the file fn5.py
and so forth.
Because of this separate, you’re importing the names of functions to
make them known in the code which uses them, eg something like:
from fn5 import fn5
It looks like you have defined MyException
in the fn3.py
file? Like
the fn3
function, you need to import the name MyException
to use it
elsewhere. So if the file fn6.py
from the traceback has a line like:
from fn3 import fn3
that needs to be extended like:
from fn3 import fn3, MyException
so that the name MyException
is also known.
Cheers,
Cameron Simpson cs@cskk.id.au
My system saves all addresses of imported modules in the table. In this case my system can get the address of the specific function there for processing.
Concerning your simple solution, all my functions ‘fn…’ are imported via the special function ‘importlib.import_module’. In this case I cannot use your simple solution ‘from fn3 import MyException’. That does give the error:
<class ‘ModuleNotFoundError’>: No module named ‘fn3’.
What to do now?
Whatever incantation you’re using with importlib
to import, say fn3
,
you need to use to import MyException
. If you’ve imported the module
containing the MyException
definition, let us call that module M
,
then you can access the exception as M.MyException
. Or you can put
this:
MyException = M.MyException
and just use MyException
from then on. That’s effective what the from M import MyException
statement does anyway.
Cheers,
Cameron Simpson cs@cskk.id.au
In order to import a function from the specified map, I use the following commands for needed functions ‘function…’:
functionData = importlib.import_module('......./......./function...')
returncode = getattr(functionData, 'function...')('aaa', 'bbb', 'ccc')
Is there better solution for this the cumbersome routine?
Now I wonder whether I can import MyException in the function ‘function6’ as the following command?
MyException = function3.MyException
Certainly, the import
statement.
However, in order to find the module or package, your files need to be in a place where the default finder will find them.
No, but import MyException from function3
will work. @cameron mentioned this previously.
Your function3
module needs to be in the paths the default finder looks. I.e. in the current directory, in the site packages (where things installed using pip are placed) or in the standard library.
My program ‘fn3’ contains:
.......
sys.path.insert(0, 'D:/Server/PythonNew/bsx/pyx')
sys.path.insert(0, 'D:/Server/PythonNew/prd/pyx')
sys.path.insert(0, 'D:/Server/PythonNew/tst/pyx')
logging.error('-Test fn3 1-')
from fn4 import fn4
logging.error('-Test fn3 2-')
fn4(.......)
logging.error('-Test fn3 3-')
.......
My program ‘fn4’ contains:
.......
class MyException(PermissionError):
logging.error('MyException classed!')
.......
logging.error('-Test fn4 1-')
from fn5 import fn5
logging.error('-Test fn4 2-')
fn5(.......)
logging.error('-Test fn4 3-')
.......
My program ‘fn5’ contains:
.......
logging.error('-Test fn5 1-')
from fn4 import MyException
logging.error('-Test fn5 2-')
MyException = fn4.MyException
logging.error('-Test fn5 3-')
.......
The line ‘from fn4 import MyException’ gives error:
<class ‘ImportError’>: cannot import name ‘MyException’ from fn4’.
Without the line ‘from fn4 import MyException’, the line ‘MyException = fn4.MyException’ gives error:
<class ‘NameError’>: name ‘fn4’ is not defined.
What should one or more abovementioned programs to be corrected?
My program ‘fn3’ contains:
sys.path.insert(0, 'D:/Server/PythonNew/bsx/pyx') sys.path.insert(0, 'D:/Server/PythonNew/prd/pyx') sys.path.insert(0, 'D:/Server/PythonNew/tst/pyx')
Ah, you’re adjusting the import path. Good!
from fn4 import fn4 fn4(.......)
My program ‘fn4’ contains:
class MyException(PermissionError): logging.error('MyException classed!') ....... from fn5 import fn5 fn5(.......)
My program ‘fn5’ contains:
logging.error('-Test fn5 1-') from fn4 import MyException
The line ‘from fn4 import MyException’ gives error:
<class ‘ImportError’>: cannot import name ‘MyException’ from fn4’.
Please transcribe the entire message. Usually this one contains more
information.
This issue arises because you have a circular import. fn3
imports
fn4
imports fn5
imports fn4
.
When you import files, they are run! An import
statement does not
return until the file it is importing has run to completion. So a
circular import cannot complete - because an “in progress” import is
still in progress. If it was just run naively you would get a Python
recursion error as the modules imported each other in a loop.
The import machinery knows that the import of fn4
is still in progress
during the import of fn3
. So when fn4
’s import runs, importing fn5
,and then fn5
’s import tries to import fn4
, the import machinery
raises this exception because fn4
has not completed.
Without the line ‘from fn4 import MyException’, the line ‘MyException = fn4.MyException’ gives error:
<class ‘NameError’>: name ‘fn4’ is not defined.
Yes, you’ll need the import
to define the name, (It would be no
different with your previous methods using the importlib
module - the
import
statement just runs that stuff conveniently and reliably for
you).
What should one or more abovementioned programs to be corrected?
The import chain you have looks like this ASCII diagram:
fn3 -> fn4 -> fn5 -+
^ |