Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Importing library classes in Python

I have following project hierarchy:

project_dir
  lib
    __init__.py
    ...
    some_script.py
    ...
    agent
      __init__.py
      ...
      errors.py
      some_agent_script.py
      ...

There is the SomeException class definition in lib/agent/erros.py I use following code to import them inside lib/agent/some_agent_script.py:

from errors import SomeException

Also I use following code to import in lib/some_script.py

from agent.errors import SomeException

The problem is when I raise a SomeException in lib/agent/some_agent_script.py then lib/some_script.py can not catch it in an except block:

try:
    # Here comes a call to lib/agent/some_agent_script.py function
    # that raises SomeException
except SomeException, exc:
    # Never goes here
    print(exc)
except Exception, exc:
    print(exc.__class__.__name__) # prints "SomeException"

    # Let's print id's
    print(id(exc.__class__))
    print(id(SomeException))
    # They are different!

    # Let's print modules list
    pprint.pprint(sys.modules)

I can see in sys.modules that erros module was imported twice: the first is with 'agent.errors' key and the second is with 'lib.agent.errors' key

The following code goes right, but it's not a beautiful solution:

agent_errors = sys.modules.get('agent.errors')
from agent_errors import SomeException

try:
    # Here comes a call to lib/agent/some_agent_script.py function
except SomeException:
    print('OK')

What should I do to make this module not to import twice?

like image 452
fey Avatar asked Nov 03 '22 12:11

fey


1 Answers

You should always use fully qualified imports.

from lib.agent.errors import SomeException

Do this in every module that uses it. Then it will always have the same package name. You should probably also change the top-level package name. The name "lib" is too generic.

This will also save you some headaches if you happen to name a module the same as a base, or "stock", module. For example, suppose you created a module lib/agent/socket.py and in lib/agent/some_agent_script.py you wrote import socket. You would not actually get your module, but the stock one.

So it's better to get in the habit of always using fully qualified package names, off a common root if you can.

An alternative is to use absolute imports.

from __future__ import absolute_import

import .errors

Note the leading dot. This explicitly imports from the current package. It should also fix your problem, but I admit I haven't tried it.

like image 63
Keith Avatar answered Nov 15 '22 05:11

Keith