6

I got a strange error while working with Python unittest. I have two folders in my project:

project
    code
        __init__.py        (empty)
        app.py             (defines my App class)
    test
        test.py            (contains my unit tests)

test.py is:

import os, sys, unittest
sys.path.insert(1, os.path.join(sys.path[0],'..'))
from code.app import App

class test_func1(unittest.TestCase):
    ...

When I run test.py I get the message:

Traceback (most recent call last):
    File "<frozen importlib._bootstrap>", line 2218, in _find_and_load_unlocked
AttributeError: 'module' object has no attribute '__path__'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "...test.py, line 5, in <module>
    from code.app import App
ImportError: No module named 'code.app': 'code' is not a package

After verifying that __init__.py was present and banging my head for a while, on a whim I changed the name of the app directory from code to prog:

import os, sys, unittest
sys.path.insert(1, os.path.join(sys.path[0],'..'))
from prog.app import App

... and everything was suddenly fine. Unittest imported my app properly and ran the tests.

I've searched through https://docs.python.org/3.5/reference/lexical_analysis.html#keywords and https://docs.python.org/3/reference/import.html#path-entry-finders and don't see any indication that code is an illegal directory name. Where would this be documented, and what other directory names are reserved?

System: python 3.4.3 [MSC v1600 32 bit] on win32, Windows 7

Dave
  • 3,834
  • 2
  • 29
  • 44
  • 3
    `code` isn't a reserved name, but there is an [existing module](https://docs.python.org/3/library/code.html) in the standard library by that name, so naming your module `code` is a bad idea, like naming your list `list`. I'd expect your module to shadow the built-in with the information you've provided, but there are a number of possibilities that would make it go the other way. – user2357112 Mar 17 '16 at 16:29
  • Correct me if i'm wrong, but you're supposed to do `from code import app`, depending on what you've defined in `__init__.py`. Maybe you can do `from code.app ...` if `app` is defined in `__init__.py`, if so ignore my comment. – Torxed Mar 17 '16 at 16:29
  • http://stackoverflow.com/questions/12172791/changes-in-import-statement-python3 – chepner Mar 17 '16 at 16:32
  • @Torxed, it is more explicit to do `from prog import app` and then use the qualified `app.App` in the script. That doesn't require anything in `__init__.py`, but it's only necessary if you want to import and use two different modules that both define `App`. – Dave Mar 17 '16 at 17:36
  • Note, I wouldn't have even run across this but for the fact that I was having problems with user-defined Exceptions and needed to come up with a tiny example to post on SO. The tiny example including Exceptions works fine (as long as it has a non-colliding package name), so now it's back to the main problem. – Dave Mar 17 '16 at 19:28

1 Answers1

5

code isn't reserved, but it is already defined in the standard library, where is it a regular module and not package. To import from your package, you should use a relative import.

from .code.app import App
chepner
  • 497,756
  • 71
  • 530
  • 681
  • 1
    According to the PEP-0404 question you should be correct. But when I try `from .code.app import App`, I get "SystemError: Parent module ' ' not loaded, cannot perform relative import". The only thing that works is the supposedly now-illegal `from prog.app import App` (without the leading dot) – Dave Mar 17 '16 at 17:22