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.
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:
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:
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