Unusual import of a class in Python

Question:

There is a file exceptions.py present in kubernetes.client folder where ApiException class is defined. So I can write the following line in my own file say myfile.py and use the ApiException for raising exception.

some_folder.myfile.py code snippet:

from kubernetes.client.exceptions import ApiException
.....
.....
    try:
        .....
    except ApiException as e:
        .....

That is fine.

Also in rest.py present in kubernetes.client folder is importing the same class ApiException and raising some exception.

kubernetes.client.rest.py code snippet:

from kubernetes.client.exceptions import ApiException
.....
.....
     if not 200 <= r.status <= 299:
         raise ApiException(http_resp=r)

That is also fine. But I am pretty much confused to see the below things as ApiException is imported from kubernetes.client.rest in some_file.py file (see below), not from kubernetes.client.exceptions where actual class definition for ApiException is present.

some_folder.some_file.py code snippet:

from kubernetes.client.rest import ApiException
.....
.....
    try:
       .....
    except ApiException as e:
       .....

The above code is working but I am really surprised. Can somebody explain me what is happening here. Sorry I am new to Python.

Note:

  1. ApiException class is not defined in kubernetes.client.rest, it is only defined in kubernetes.client.exceptions
  2. I have searched many articles at online but did not get much information.
Asked By: Surya

||

Answers:

The name ApiException is also defined in kubernetes.client.rest, because it’s been imported there. kubernetes.client.rest is using it, so it exists there. Any name that exists at the top level of a module is an attribute of that module and can be imported from elsewhere. It doesn’t matter how that name got to be defined there.

Arguably the class should be imported from its canonical location where it has been defined, but it doesn’t have to be. some_folder.some_file.py might not know where the exception has been originally defined, if it only interacts with kubernetes.client.rest and just needs to catch exceptions raised there.


You will often see this technique used in __init__.py files to simply re-export some classes defined in submodules under a simpler name, e.g.:

# foo/__init__.py
from .submodule import Foo
from .othermodule import Bar

This allows users of foo to from foo import Foo, instead of having to do from foo.submodule import Foo, but it still keeps the implementation of foo clean and separated into multiple files.

Answered By: deceze
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.