Eric Snow added the comment:

Things are working as they should here.  The key points:

* when running a script, sys.path[0] is set to the script's directory (with no 
script sys.path[0] is set to the CWD, see issue13475),
* pkg/tests/__init__.py is loaded and executed twice: once as the script under 
the __main__ module and once during import as pkg.tests,
* Python does not handle circular imports very well,
* bad things happen when a "top-level" module has the same name as a module in 
the stdlib.

Together those explain what's going on.  The import you did at the REPL 
happened with '' at sys.path[0], so modules are found at the right relative 
places: pkg, pkg.http, pkg.tests, and pkg.tests.http.  There is no script 
involved, just imports, so no double-loading happens.

Things go south when you run "PYTHONPATH=. python3 pkg/tests/__init__.py".  
First of all, pkg/tests/__init__.py is executed twice: once as the script and 
once under import.  Though you set PYTHONPATH, sys.path[0] is set to 
"pkg/tests", the directory the script is in.  sys.path[1] is ".", what you were 
expecting to be at sys.path[0].  So when finding modules, the import system 
will first look in "pkg/tests" then in ".".  Thus the pkg.* imports work as 
expected.  However, "from http.client import HTTPConnection" in 
pkg/tests/http.py finds the same http.py (this time as the "http" module 
instead of "pkg.tests.http") in pkg/tests rather than the stdlib module as you 
expected.  So it tries to import it a second time with a different module name. 
 Since pkg/tests/http.py is already being loaded due to pkg/test/__init__.py, 
you get a circular import.  Even if you did not get the circular import you 
would have gotten an ImportError for "http.client" since pkg/tests/http.py 
neither behaves li
 ke a package nor actually has any "client" submodule.

Part of the fix is to use relative imports where appropriate.  For instance, 
change pkg/tests/__init__.py like this:

  from . import http

Also, don't run pkg/tests/__init__.py directly.  Instead try this:

  PYTHONPATH=. python3 -m pkg.tests

However, this implies that you wanted to run the package as a script, so you 
should have pkg/tests/__main__.py which would import pkg.tests.  Alternately, 
you could have a dedicated script elsewhere, perhaps next to the pkg directory 
that does the same thing.  Here's what I mean:

some_project/
  pkg/
    tests/
      __init__.py
      __main__.py (option 1)
      http.py
    __init__.py
  run_unittests.py (option 2)

Finally, don't name your modules with the same names as those in the stdlib. 
<wink>

----------
nosy: +eric.snow

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue16570>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to