# User-defined exception

**URL:** <https://discuss.python.org/t/user-defined-exception/20704>\
**Category:** Python Help\
**Tags:** help\
**Created:** [November 3, 2022, 1:52pm UTC](https://discuss.python.org/t/user-defined-exception/20704 "2022-11-03T13:52:46Z")\
**Posts on this page:** 15\
**Page:** 2

<div class="post-metadata">

**Author:** ![steven.daprano](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steven.daprano/32/1083_2.png) [@steven.daprano](https://discuss.python.org/u/steven.daprano)\
**Post date:** [November 25, 2022, 2:14am UTC](https://discuss.python.org/t/user-defined-exception/20704/21 "2022-11-25T02:14:43Z")

</div>

[quote]  
The import chain you have looks like this ASCII diagram:

```auto
X fn3 -> fn4 -> fn5 -+
X ^ |

```

[\quote]

Column of X’s added in an attempt to prevent Discuss from mangling the text further, just because I don’t trust the software.

My guess is that you had a row of dashes. Discuss truncates email posts just before a row of dashes (with or without whitespace) **even if you guard it with code fences or an indent**.

Here’s a test: the next few lines contain a row of hyphens, followed by a line of text. My prediction is that this post gets truncated at the comment below.

```
# The next line is a row of hyphens

```

---

<div class="post-metadata">

**Author:** ![cameron](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cameron/32/2658_2.png) [@cameron](https://discuss.python.org/u/cameron)\
**Post date:** [November 25, 2022, 11:37pm UTC](https://discuss.python.org/t/user-defined-exception/20704/22 "2022-11-25T23:37:21Z")

</div>

> [quote]  
> The import chain you have looks like this ASCII diagram:
> 
> ```auto
> X fn3 -> fn4 -> fn5 -+
> X ^ |
> 
> ```
> 
> [\quote]
> 
> Column of X’s added in an attempt to prevent Discuss from mangling the text further, just because I don’t trust the software.

Thank you.

> My guess is that you had a row of dashes. Discuss truncates email posts just before a row of dashes (with or without whitespace) **even if you guard it with code fences or an indent**.

Looks like it is worse than that. I had a row of dashes with  
leading/trailing plus signs.

Thanks for the heads up. I’ll repost with something different. And I’ll  
flag this for filing as a bug with the Discourse folks. Not the first  
time this has happenned to me, and presumably not for you either.

Thanks,  
Cameron Simpson [cs@cskk.id.au](mailto:cs@cskk.id.au)

---

<div class="post-metadata">

**Author:** ![cameron](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cameron/32/2658_2.png) [@cameron](https://discuss.python.org/u/cameron)\
**Post date:** [November 25, 2022, 11:41pm UTC](https://discuss.python.org/t/user-defined-exception/20704/23 "2022-11-25T23:41:05Z")

</div>

@Pejamide before I was so rudely interrupted by the Discourse software,  
I was saying:

> > What should one or more abovementioned programs to be corrected?
> 
> The import chain you have looks like this ASCII diagram:
> 
> ```
> fn3 -> fn4 -> fn5 -+
> ^ |
> 
> ```

There was just a closed loop there. The followup text, discarded by  
Discourse, was:

thus the import loop.

The usual fix is that the stuff you want should be in another “lower  
level” module which defines `fn4`. Your current issue is that `fn4`  
needs `fn5` and `fn5` needs `fn4`. You’d  
fix this by taking the things they both need and moving them into some  
common module eg “misc”. Example:

```
 misc.py
     class MyException(OtherException):
         ...
 fn4.py:
     from misc import MyException
     def fn4():
         ...
 fn5.py:
     from misc import MyException
     def fn5():
         ...
 fn3.py
     from fn4 import fn4
     from fn5 import fn5
     ... use fn4 and/or fn5 as required ...

```

Another approach would be to just merge `fn4.py` and `fn5.py` into a  
single module so that they do not try to import each other. I’m  
presuming there’s a reason that they are  
separate though?

A third alternative is the “late import”. This is the less desirable  
approach, because it’s a bit of a hack which cannot always be used - it  
is usually better to structure your  
modules in a bit of a hierachy as above. The late import:

```
 fn4.py:
     from fn5 import fn5
 fn5.py:
     def fn5():
         from fn4 import fn4, MyException
         ... use fn4 or MyException in here ..

```

This works because the inner import is not run unless the `fn5()`  
function as actually called. By that stage both `fn4` and `fn5` have  
been imported.

Usually we take a circular import to mean that your modules can be  
better structures in a clean hierarchy instead of having two modules  
codependent.

Occasionally that can’t be done, and a late import is the usual fix. But  
try to structure your modules differently first.

Cheers,  
Cameron Simpson [cs@cskk.id.au](mailto:cs@cskk.id.au)

---

<div class="post-metadata">

**Author:** ![Pejamide](https://avatars.discourse-cdn.com/v4/letter/p/f07891/32.png) [@Pejamide](https://discuss.python.org/u/Pejamide)\
**Post date:** [November 26, 2022, 8:23pm UTC](https://discuss.python.org/t/user-defined-exception/20704/24 "2022-11-26T20:23:05Z")

</div>

To my disappointment, your advice to use the following command doesn’t work either:

```auto
 MyException = M.MyException

```

I have reorganized my program as follows:

My function fn3 contains:

```auto
.......
from fnEXC import fnEXC 
fnEXC(.......)
.......
try:
    from fn4 import fn4
    fn4(.......)
except MyException as e:
    logging.error('MyException executing...')
    logging.error(e)
.......

```

My function ‘fnEXC ’ contains fully:

```auto
def fnEXC (.......):
    class MyException(PermissionError):
        import logging
        logging.error('MyException classed!')

```

My function ‘fn4’ contains:

```auto
.......
from fn5 import fn5
fn5(.......)
.......

```

My function ‘fn5’ contains:

```auto
.......
from fnEXC import MyException
MyException = fnEXC.MyException
raise MyException('123')
.......

```

I got the following error

```auto
<class 'ImportError'>: cannot import name 'MyException' from 'fnEXC ' (D:\Server/PythonNew/prd/pyx\fnEXC .py)
... called by File "D:\Server/PythonNew/tst/pyx\fn5.py", line 32, in fn5: from fnEXC import MyException
... called by File "D:\Server/PythonNew/tst/pyx\fn4.py", line 33, in fn4: fn5(glb)
... called by File "D:\Server\PythonNew\prd\pyx\fn3.py", line 60, in fn3: fn4(glb)

```

Without the line ‘from fnEXC import MyException’ I got the following error:

```auto

```

Help, what should I have doing erroneous? What should the solution be in this difficult situation?

---

<div class="post-metadata">

**Author:** ![cameron](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cameron/32/2658_2.png) [@cameron](https://discuss.python.org/u/cameron)\
**Post date:** [November 26, 2022, 10:01pm UTC](https://discuss.python.org/t/user-defined-exception/20704/25 "2022-11-26T22:01:12Z")

</div>

This code defines a function named `fnEXC`. It _does not_ define an  
exception class named `MyException`, because the function is not  
_called_, and therefore the code inside it is not _executed_ and anyway  
it would define the exception class as a local variable, which would  
vanish on return from the function.

Just put this in your `fnEXC.py` file:

```
 class MyException(PermissionError):
     import logging
     logging.error('MyException classed!')

```

and use:

```
 from fnEXC import MyException

```

Cheers,  
Cameron Simpson [cs@cskk.id.au](mailto:cs@cskk.id.au)

---

<div class="post-metadata">

**Author:** ![Pejamide](https://avatars.discourse-cdn.com/v4/letter/p/f07891/32.png) [@Pejamide](https://discuss.python.org/u/Pejamide)\
**Post date:** [November 27, 2022, 1:28pm UTC](https://discuss.python.org/t/user-defined-exception/20704/26 "2022-11-27T13:28:27Z")

</div>

Unfortunately it does not work in my program, because the section ‘try + exception MyException’ must be processed in my function ‘fn3’. In this case the command ‘raise MyException’ in my function ‘fn5’ must then go to the command ‘exception MyException’ in my funxtion ‘fn3’.  
Whta to do in this most important situation?

---

<div class="post-metadata">

**Author:** ![Pejamide](https://avatars.discourse-cdn.com/v4/letter/p/f07891/32.png) [@Pejamide](https://discuss.python.org/u/Pejamide)\
**Post date:** [December 6, 2022, 4:16pm UTC](https://discuss.python.org/t/user-defined-exception/20704/27 "2022-12-06T16:16:37Z")

</div>

Unfortunately the command ‘raise MyException(‘123’)’ in the function ‘fn5’ does NOT jump to the command 'except MyException as e:  
’ in the function ‘fn3’.  
If it cannot be solved in this case, then it is NOT possible in a Python program, is it?

---

<div class="post-metadata">

**Author:** ![cameron](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cameron/32/2658_2.png) [@cameron](https://discuss.python.org/u/cameron)\
**Post date:** [December 6, 2022, 9:11pm UTC](https://discuss.python.org/t/user-defined-exception/20704/28 "2022-12-06T21:11:13Z")

</div>

It’s unclear to me what you’re trying to achieve.

When an exception is raised, the _current call stack_ is unwound looking  
for an `except` clause which matches the exception. If one is found that  
clause runs. If not, the unwind gets all the way out to the Python  
system wide handler, which is what prints the stack trace etc.

If `fn3` did not call `fn5`, then `fn3` _will not_ be involved in  
handling the exception.

As I recall, you have had a few problems:

- defining the `MyException` class, which I presume you’ve now  
accomplished
- importing the `MyException` class name for use in a module, which I  
also presume you’ve now accomplished if you’re successfully raising  
the exception
- handling the exception with a `try`/`except` when it occurs

Can you put the `fn3()` function, the `fn5()` function and the  
`MyException` class _all_ in a single file which reproduces your problem  
when it runs?

Then show us that code and the output.

Thanks,  
Cameron Simpson [cs@cskk.id.au](mailto:cs@cskk.id.au)

---

<div class="post-metadata">

**Author:** ![Pejamide](https://avatars.discourse-cdn.com/v4/letter/p/f07891/32.png) [@Pejamide](https://discuss.python.org/u/Pejamide)\
**Post date:** [December 7, 2022, 2:20pm UTC](https://discuss.python.org/t/user-defined-exception/20704/29 "2022-12-07T14:20:08Z")

</div>

Here you have the required information.  
My function fnEXP contains:

```auto
def fnEXP():
    class MyException(PermissionError):
        import logging
        logging.error('MyException classified!')

```

My function fn3 contains:

```auto
from fnEXP import fnEXP 
fnEXP()
logging.error('MyException classified in fnEXP')
.......
try:
    from fn4 import fn4
    fn4(.......)
except MyException as e:
    logging.error('MyException executing...')
    logging.error(e)

```

My function ‘fn4’ contains:

```auto
.......
from fn5 import fn5
fn5(.......)
.......

```

My function ‘fn5’ contains:

```auto
.......
from fnEXP import fnEXP 
fnEXP()
logging.error('MyException classified in fn5')
.......
raise MyException('123')

```

I got the following error

```auto
'MyException classified!'
MyException classified in fn3
'MyException classified!'
MyException classified in fn5
<class 'NameError'>: name 'MyException ' is not defined
... called by File "D:\Server\PythonNew\prd\pyx\fn3.py", line 60, in fn3: except MyException as e: 

```

What to do now?

---

<div class="post-metadata">

**Author:** ![abessman](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abessman/32/8367_2.png) [@abessman](https://discuss.python.org/u/abessman)\
**Post date:** [December 7, 2022, 2:55pm UTC](https://discuss.python.org/t/user-defined-exception/20704/30 "2022-12-07T14:55:50Z")

</div>

`MyException` is defined inside `fnEXP` and therefore cannot be accessed outside of `fnEXP`. You need to either define `MyException` on the module level or return it from the function.

---

<div class="post-metadata">

**Author:** ![Pejamide](https://avatars.discourse-cdn.com/v4/letter/p/f07891/32.png) [@Pejamide](https://discuss.python.org/u/Pejamide)\
**Post date:** [December 7, 2022, 5:52pm UTC](https://discuss.python.org/t/user-defined-exception/20704/31 "2022-12-07T17:52:18Z")

</div>

Please tell me how I can define MyException on the module. Please with some examples as I am new for those atters.  
Ans please tell me how and what I have return of fnEXP with some examples.

---

<div class="post-metadata">

**Author:** ![cameron](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cameron/32/2658_2.png) [@cameron](https://discuss.python.org/u/cameron)\
**Post date:** [December 7, 2022, 9:31pm UTC](https://discuss.python.org/t/user-defined-exception/20704/32 "2022-12-07T21:31:01Z")

</div>

> Here you have the required information.  
> My function fnEXP contains:

You seem to be conflating functions with files. There is no need to have  
these functions each in their own file. You’ll be a lot better off  
having a single file defining your various functions unless there’s some  
special reason to break things up.

With everything in a single file there’s no need to import names.

> ```auto
> def fnEXP():
> class MyException(PermissionError):
> import logging
> logging.error('MyException classified!')
> 
> ```

Alexander has already mentioned this, and it has also been mentioned  
before. This function `fnEXP` defines a _local_ class named  
`MyException`. And then discards it (as _any_ local variable is  
descarded when you leave a function).

Also, that class is only defined when `fnEXP` is actaully called/run.  
The file containing `fnEXP` _only_ defines the `fnEXP()` function. It  
does not call it.

Usually you’d define a class as a top level name. In your case, you  
might make the contents of the `fnEXP` file just this:

```
 class MyException(PermissionError):
     import logging
     logging.error('MyException classified!')

```

Which would define `MyException` at the module level, immediately.  
There’s no need for the `fnEXP()` function, as to my eye it does not not  
anything else. So it can be discarded.

> My function fn3 contains:
> 
> ```auto
> from fnEXP import fnEXP
> fnEXP()
> 
> ```

This is an odd way to do things (and ineffective, as you discover  
later). It looks like you’re calling the `fnEXP()` function in order to  
define the `MyException` class. But because that class is a _local  
variable_ in the `fnEXP()` function, it is forgotten as soon as you  
return from the function, and was never visible outside the function  
anyway.

If you change the `fnEXP` file as suggested above, to just define the  
`MyException` class at the top level, and drop the `fnEXP()` function  
completely, you’ll end up with a module level `MyException` name.

And when you’ve done that you can go:

```
 from fnEXP import MyException

```

That line binds the module level name `MyException` in the `fn3` file to  
the same things to which is it bound in the `fnEXP` file. And that is  
how the name `MyException` becomes usable in the `fn3` file.

When you run it:

> ```auto
> try:
> from fn4 import fn4
> fn4(.......)
> except MyException as e:
> logging.error('MyException executing...')
> logging.error(e)
> 
> ```

With your code, this line will raise the `NameError` you see because you  
never imported the name `MyException` itself. If you change `fnEXP` to  
define `MyException` as a top level name and then _import_ that name to  
the `fn3` file, _then_ the name `MyException` will be known and the  
`try`/`except` will work.

Cheers,  
Cameron Simpson [cs@cskk.id.au](mailto:cs@cskk.id.au)

---

<div class="post-metadata">

**Author:** ![Pejamide](https://avatars.discourse-cdn.com/v4/letter/p/f07891/32.png) [@Pejamide](https://discuss.python.org/u/Pejamide)\
**Post date:** [December 8, 2022, 7:51pm UTC](https://discuss.python.org/t/user-defined-exception/20704/33 "2022-12-08T19:51:09Z")

</div>

My program has been reorganized as follows:

My function fn3 contains:

```auto
def fn3():
  import logging
  logging.error('fn3: -001-')
  class MyException(PermissionError):
    import logging
    logging.error('MyException classified!')
  try:
    logging.error('fn3: -002-')
    from fn4 import fn4
    logging.error('fn3: -003-')
    fn4()
    logging.error('fn3: -004-')
  except MyException as e:
    logging.error('fn3: -005-')
    logging.error(e)
    logging.error('fn3: -006-')
  logging.error('fn3: -007-')

```

My function ‘fn4’ contains:

```auto
def fn4():
  import logging
  logging.error('fn4: -001-')
  from fn5 import fn5
  logging.error('fn4: -002-')
  fn5()
  logging.error('fn4: -003-')

```

My function ‘fn5’ contains:

```auto
def fn5():
  import logging
  logging.error('fn5: -001-')
  raise MyException('123')
  logging.error('fn5: -002-')

```

It gives errors:

````auto
fn3: -001-
MyException classified!
fn3: -002-```
fn3: -003-
fn4: -001-
fn4: -002-
fn5: -001-
<class 'NameError'>: name 'MyException' is not defined
... called by File "D:\Server\...\fn5.py", line 4, in fn5: raise MyException('123')
... called by File "D:\Server\...\fn4.py", line 6, in fn4: fn5()
... called by File "D:\Server\...\fn3.py", line 11, in fn3: fn4()

````

Help, how to solve that difficult problem?

---

<div class="post-metadata">

**Author:** ![cameron](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cameron/32/2658_2.png) [@cameron](https://discuss.python.org/u/cameron)\
**Post date:** [December 8, 2022, 9:22pm UTC](https://discuss.python.org/t/user-defined-exception/20704/34 "2022-12-08T21:22:38Z")

</div>

You’re _still_ defining `MyException` as a _local variable_ in the  
function `fn3()`. That makes it _unknown_ outside the function, hence  
the `NameError` later.

Might I suggest:

- define `MyException` outside the function as a module level name
- import `MyException` in the files where it is used, so that they have  
that name available
- import `logging` once at the top of each file - it is easier to read

So your fn3 file would look like this:

```
 import logging

 class MyException(PermissionError):
   logging.error('MyException classified!')

 def fn3():
   from fn4 import fn4
   logging.error('fn3: -001-')
   try:
     logging.error('fn3: -002-')
     logging.error('fn3: -003-')
     fn4()
     logging.error('fn3: -004-')
   except MyException as e:
     logging.error('fn3: -005-')
     logging.error(e)
     logging.error('fn3: -006-')
   logging.error('fn3: -007-')

```

and fn4 looks like this:

```
 import logging

 def fn4():
   from fn5 import fn5
   logging.error('fn4: -001-')
   logging.error('fn4: -002-')
   fn5()
   logging.error('fn4: -003-')

```

and fn5 looks like this:

```
 import logging

 def fn5():
   from fn3 import MyException
   logging.error('fn5: -001-')
   raise MyException('123')
   logging.error('fn5: -002-')

```

Normally we would also be be putting the imports of `fn3`, `fn4`, `fn5`  
at the tops of files but you have a circular dependency (`fn5` needs  
`fn3` needs `fn4` needs `fn5` …) so those imports need to be deferred.

The important thing here is to define `MyException` as a module level  
nam in `fn3`, and to import `MyException` in the modules which use it.

Cheers,  
Cameron Simpson [cs@cskk.id.au](mailto:cs@cskk.id.au)

---

<div class="post-metadata">

**Author:** ![Pejamide](https://avatars.discourse-cdn.com/v4/letter/p/f07891/32.png) [@Pejamide](https://discuss.python.org/u/Pejamide)\
**Post date:** [December 9, 2022, 8:12pm UTC](https://discuss.python.org/t/user-defined-exception/20704/35 "2022-12-09T20:12:43Z")

</div>

Yay! Thank you so much for your enlightening example, which finally made my program work perfectly! I do admire your terribly persistent patience for me.

Now I wonder, if you can answer my other problem “How use dynamic function name in import function?” in the same way. I usually learn a lot from examples. Hence this polite request.

[Previous page](https://discuss.python.org/t/user-defined-exception/20704.md?page=1)
