скрипт, который добавляет пакеты в импорт sys.path, как и ожидалось, при запуске из ipython, но выдает исключение, когда скрипт запускается из python

Я озадаченный энтузиаст Python. Я разместил Что еще я могу сделать, чтобы устранить неполадки, связанные с пакетом, который не импортируется в python, но импортируется в ipython, находясь в virtualenv? думая, что у меня возникла проблема с моим virtualenv. Дальнейшее устранение неполадок показало, что это, вероятно, не так.

Я был бы признателен за любую информацию или советы по устранению неполадок, чтобы я мог продолжить разработку пакета. Заранее спасибо!

Краткий обзор моей проблемы в системе Ubuntu 14.04.1 LTS с Python 2.7.6 .:

  1. У меня есть скрипт с именем test_dummy.py, который добавляет пути к пакетам в sys.path, а затем пытается импортировать пакеты.
  2. Пакеты импортируются без ошибок, когда скрипт запускается с run test_dummy.py внутри ipython.
  3. Исключения ImportError выдаются для определенных пакетов, когда скрипт запускается с python test_dummy.py.
  4. Что больше всего расстраивает, так это то, что пакеты, которые содержат код, т.е. больше, чем просто импорт __init__.py файла без исключения. Простые тестовые пакеты, содержащие только файл __init__.py, не импортируются должным образом. Я не могу определить, что заставляет простейшие пакеты генерировать исключения при импорте, когда скрипт вызывается из python, то есть python test_dummy.py.

Мой pwd такой:

.
├── browser
├── display
├── hello_world
├── singleton
├── test_a
└── tests

test_a как таковой:

test_a
├── __init__.py
└── __init__.pyc

hello_world как таковой:

hello_world/
├── hello.py
├── hello.pyc
├── __init__.py
└── __init__.pyc

hello.py как таковой:

HELLO = 'Hello, world!'
print HELLO

Все остальные пакеты ['browser', 'display', 'singleton'] содержат файлы init.py и другой код, который при запуске не создает никаких известных исключений.

тесты такие:

tests
└── test_dummy.py

Код в test_dummy.py:

import importlib
import os
import sys
HOME = os.path.expanduser('~')
PYTHON = os.path.join(HOME, 'development/my_python')
PACKAGES = [
    'browser',
    'display',
    'singleton',
    'test_a',
    'hello_world',
]
MODULES = [
    '',
    '',
    '',
    '',
    'hello',
]
IMPORTS = ['.'.join((pkg, module)).strip('.')
           for pkg, module
           in zip(PACKAGES, MODULES)]
"""
append sys.path with PACKAGES if package exists and not already
in the sys.path
"""
for package in PACKAGES:
    package = os.path.join(PYTHON, package)
    if os.path.exists(package) is True:
        if package not in sys.path:
            print "loading package '{0}'".format(package)
            sys.path.append(package)
        else:
            print "package '{0}' already in sys.path".format(package)
    else:
        message = "Package '{0}' does not exist.".format(package)
        raise IOError(message)
"""
import IMPORTS if the package is in sys.path
"""
for item in IMPORTS:
    pkg_in_path = [pkg == os.path.basename(path)
                   for pkg in PACKAGES for path in sys.path]
    if any(pkg_in_path):
        print "loading '{0}'".format(item)
        importlib.import_module(item)
    else:
        raise AttributeError("{0} not in sys.path".format(item))

Результаты ipython:

$ ipython
# result
Python 2.7.6 (default, Mar 22 2014, 22:57:26)
Type "copyright", "credits" or "license" for more information.

IPython 2.2.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.
Warning: disable autoreload in ipython_config.py to improve performance.

In [3]: run tests/test_dummy.py
loading package '/home/dmmmd/development/my_python/browser'
loading package '/home/dmmmd/development/my_python/display'
loading package '/home/dmmmd/development/my_python/singleton'
loading package '/home/dmmmd/development/my_python/test_a'
loading package '/home/dmmmd/development/my_python/hello_world'
loading 'browser'
loading 'display'
loading 'singleton'
loading 'test_a'
loading 'hello_world.hello'
Hello, world!

результаты от python tests/test_dummy.py:

loading package '/home/dmmmd/development/my_python/browser'
loading package '/home/dmmmd/development/my_python/display'
loading package '/home/dmmmd/development/my_python/singleton'
loading package '/home/dmmmd/development/my_python/test_a'
loading package '/home/dmmmd/development/my_python/hello_world'
loading 'browser'
loading 'display'
loading 'singleton'
loading 'test_a'
Traceback (most recent call last):
  File "tests/test_dummy.py", line 46, in <module>
    importlib.import_module(item)
  File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
ImportError: No module named test_a

Импорт пакета «test_a» в интерпретатор Python не вызывает исключения:

Python 2.7.6 (default, Mar 22 2014, 22:57:26)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path.append('/home/dmmmd/development/my_python/test_a')
>>> import test_a
>>> print test_a
<module 'test_a' from 'test_a/__init__.pyc'>
>>>

person dmmfll    schedule 01.09.2014    source источник
comment
Как выглядит __init__.py в test_a? А в browser?   -  person t.pimentel    schedule 01.09.2014
comment
browser/__init__.py содержит комментарий и from browser import Firefox. В test_a файл init.py пуст.   -  person dmmfll    schedule 01.09.2014
comment
Я не знаю, в чем проблема, вы пытались добавить код в test_a или изменить имя папки browser на test_a и посмотреть, импортируется ли он?   -  person t.pimentel    schedule 01.09.2014
comment
Это сложная проблема, определенно выходящая за рамки моих ограниченных знаний. Смотрите ответ, который я разместил. Спасибо за помощь, t.pimentel. Я попытался изменить имена test_a и browser. Исключения по-прежнему выбрасывались.   -  person dmmfll    schedule 01.09.2014


Ответы (1)


Я нашел решение, хотя это решение не решает проблему, почему определенные пути пакетов, добавленные специально в sys.path, не импортируются, когда скрипт запускается с python test_dummy.py.

Изначально я столкнулся с этой проблемой при попытке использовать py.test. В в документации py.test я видел этот совет об «управлении вашим проектом с помощью virutalenv, pip и редактируемого режима». Я проигнорировал его, потому что считал его слишком продвинутым для моего уровня знаний Python.

Я решил попробовать этот совет, прочитав о "создание собственного проекта Python".

В pwd я создал файл setup.py со следующим кодом:

from setuptools import setup, find_packages

setup(name='import_troubleshooting', version='1.0')
packages = find_packages(exclude=[
    'my_django',
    'fake*',
    'tests*'
])

Затем я выполнил следующий код в командной строке:

pip install -e .  # the pip way (which just calls "setup.py develop")

Затем я выполнил следующий код с ожидаемыми результатами:

$ python tests/test_dummy.py
# output    
package '/home/dmmmd/development/my_python/browser' already in sys.path
package '/home/dmmmd/development/my_python/display' already in sys.path
package '/home/dmmmd/development/my_python/singleton' already in sys.path
loading package '/home/dmmmd/development/my_python/test_a'
loading package '/home/dmmmd/development/my_python/hello_world'
loading 'browser'
loading 'display'
loading 'singleton'
loading 'test_a'
loading 'hello_world.hello'
Hello, world!

Ничто из этого не объясняет мне, почему я не мог добавить пути к пакетам в специальном режиме без предварительной установки моих пакетов с помощью pip install -e .. Странно тоже, что сбой только при передаче скрипта на python. ipython test_dummy.py работает без предварительной установки моих локальных пакетов.

Однако я рад узнать кое-что об установке и упаковке Python. Сценарий test_dummy.py теперь работает должным образом при вызове из python tests/test_dummy.py.

Теперь я не понимаю, почему три пакета уже находятся в sys.path, когда запускается скрипт test_dummy.py:

package '/home/dmmmd/development/my_python/browser' already in sys.path
package '/home/dmmmd/development/my_python/display' already in sys.path
package '/home/dmmmd/development/my_python/singleton' already in sys.path

Я не помню, чтобы я делал что-то, что добавляло бы их к sys.path, но это возможно, так как я делал различные уроки. Их нет в sys.path ни в какой другой среде, где я не запускал созданный setup.py.

Мое замешательство — это симптом сложности Python, а не причина!

Спасибо за ваш вклад.

NB: это вывод python test_dummy.py после нового виртуального окружения:

$ pip install -e .
# install output unremarkable
$ python tests/test_dummy.py
# output
    loading package '/home/dmmmd/development/my_python/automated_browsing/browser'
loading package '/home/dmmmd/development/my_python/automated_browsing/display'
loading package '/home/dmmmd/development/my_python/automated_browsing/singleton'
loading package '/home/dmmmd/development/my_python/automated_browsing/hello_world'
loading package '/home/dmmmd/development/my_python/automated_browsing/test_a'
loading 'browser'
loading 'display'
loading 'singleton'
loading 'hello_world.hello'
Hello, world!
loading 'test_a'
person dmmfll    schedule 01.09.2014