1

I'm using a from . import module statement to do exactly that: import a local module to my script. The script and module reside in the same folder.

# module.py
def foo():
    print('Foo!')

# script.py
from . import module
module.foo()

> ImportError: cannot import name 'module'

This should be pretty easy, and doing just import module does work, but as this answer suggests one should, I modified the statements to the former form.

The end goal is to have a package, from which I can use things, but also to have executable scripts inside the package that import other parts of that package. Apparently, after a few days worth of searching and a few questions I still don't quite understand the import and packaging machinery.

These might be the cause:

  • Import statements are different in 2.7 and 3.x, I'm using 3.6, the question was on 2.7
  • Relative imports are different inside packages (folder with __init__.py)
  • The working directory is different or the folders are not in sys.path

Having an __init__ file does not make a difference at least in a fresh project in PyCharm. Also, the working directory is set to the folder of the sources and it is in path.

Have I missed something? Or rather, what's the correct way of achieving the functionality described in the end goal? Any help is greatly appreciated!

Felix
  • 2,548
  • 19
  • 48
  • I don't think you can do relative imports unless you are in a module. Your script is not a module. You may be able to do something like call it as a module `python -m script` but when you get to tha tstage you are probably not doing things correctly. – Mike Robins Jul 19 '18 at 06:16

1 Answers1

4

Since writing this answer I have realised it is more convenient and better style in my humble opinion to install the package with pip install -e . and use absolute imports. So even within a package writing from package.sub.module import thing. This makes refactoring a lot easier and there's no need to ever manipulate module variables or sys.path.


When running a script directly, Python consideres the name (a special variable, __name__) of that script to be "__main__". In case of an import, the name is set to the name of the module. In the latter case relative imports are fine. But import actually looks at the combination of __name__ and another special variable, __package__, which is None for an executed script, but the path to a module for an imported module, e.g. parent.sub.

The searched variable is... drumroll...

__package__ + '.' + __name__

The secret ingredient is manipulating __package__:

# script.py
__package__ = 'package_name'   # or parent.sub.package
from . import module

This lets Python know you are inside a package even though the script is executed directly. However, the top level folder needs to be in sys.path and the package name has to reflect that directory structure.

See this very comprehensive answer on the topic of relative imports.

Felix
  • 2,548
  • 19
  • 48