执行python setup.py测试时的ImportError

时间:2017-09-30 15:34:35

标签: python bash unit-testing import

我制作了一个简单的python应用程序。我不知道我是否正确地这样做,所以请在评论中纠正我,或者如果你有答案

错误:

ImportError: No module named 'taskhandler'

和:

ImportError: No module named 'styles' while doing `python3 setup.py test

文件结构:

.
├── MANIFEST.in
├── pydotask.egg-info
│   ├── dependency_links.txt
│   ├── not-zip-safe
│   ├── PKG-INFO
│   ├── SOURCES.txt
│   └── top_level.txt
├── README.md
├── setup.py
├── task_mod
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-35.pyc
│   │   ├── pydo.cpython-35.pyc
│   │   └── taskhandler.cpython-35.pyc
│   ├── pydo.py
│   ├── styles
│   │   ├── __init__.py
│   │   ├── __pycache__
│   │   │   ├── __init__.cpython-35.pyc
│   │   │   ├── termcolor.cpython-35.pyc
│   │   │   └── text_style.cpython-35.pyc
│   │   ├── termcolor.py
│   │   └── text_style.py
│   ├── taskhandler.py
│   └── tasks.csv
└── update.txt

5 directories, 22 files

' task_mod / pydo.py':

#!/usr/bin/env python3

''' To Do App in Python '''

import sys, os
import taskhandler as task
from styles import text_style as text
from styles import termcolor

task_mod/taskhandler.py

#!/usr/bin/env python3

import sys, os
import csv
from styles import termcolor
from styles import text_style as text

setup.py

from setuptools import setup

def readme():
    with open('README.md') as readme:
        return readme.read()

setup(
        name = 'pydotask',
        version = '0.2',
        description = 'PyDo is a CLI Application to keep you on track with your tasks and projects',
        long_description = readme(),
        classifiers = [
            'Development Status :: 3 - Alpha',
            'Programming Language :: Python :: 3.5',
            'Topic :: Office/Business :: Scheduling'
            ],
        keywords = 'utilities office schedule task reminder',
        url = '',
        author = 'Abhishta Gatya',
        author_email = 'abhishtagatya@yahoo.com',
        packages = ['task_mod'],
        scripts = ['task_mod/pydo'],
        python_requires = '>=3',
        include_package_data = True,
        zip_safe = False
        )

如何解决这个问题?

注意:如果我运行python3 task_mod/pydo.py,它运行正常!但是当我尝试测试它时,它会产生2个ImportErrors。

2 个答案:

答案 0 :(得分:2)

您必须指定setup.py中使用的所有模块,而不仅仅是顶级文件夹。因此,在您的setup.py文件中,将行packages = ['task_mod'],替换为packages = ['task_mod', 'task_mod.styles', 'task_mod.taskhandler'],

或者,在不更改setup.py的情况下,您可以使用import task_mod.stylesfrom task_mod import styles导入。然后,您可以使用styles.termcolor等样式的文件。

或者,您可以使用setuptool的黑魔法功能find_packages,如下所示:packages = find_packages(),

Heroku Log

答案 1 :(得分:1)

首先,请注意您在task_mod中提供了名为setup.py的包。这意味着,您应该import task_modimport task_mod.blah,而不是import blah。因为您没有在库中提供blah。尝试将导入更改为绝对导入。

其次,如果您仍然需要相对导入(这是对单个库执行操作的常见做法 - 那么维护代码会更容易),您应该相对导入:from .styles import termcolor(注意点)

第三,相对进口只会影响模块和模块。包,而不是您直接执行的脚本(因为pydo.py是包__main__,而不是task_mod.pydo,它会更改所有内容)。对于脚本,您有两种选择:

选择A(马马虎虎):始终导入绝对包/模块名称(pydo.py中的import task_mod.taskhandler as tashhandler;还from task_mod.styles import termcolor等)。

选择B(最佳实践):永远不要将任何脚本导出为库的一部分(仅用于构建/测试/ CI / CD目的)。而是导出控制台脚本的入口点(google:setuptools入口点)。

setup( .... entry_points={ 'console_scripts': [ 'pydo = task_mod.pydo:main', ], }, )

当然,在该模块中定义main()函数。

shebangs(#!...python3)在这里完全不相关。

<强> UPD:

如果您在导入方面遇到问题,请记住:

您应该以某种方式使您的包在PYTHONPATH env var(或sys.path内部变量)上。这正是Python在import things时查找内容的地方。

你可以print(sys.path)在任何导入之前查看它为什么会这样发生 - 第一个元素将是你的脚本的目录,它将在task_mod/pydo.py和{}之间变化。 setup.py来电。{/ p>

当您在主项目目录(python3 setup.py)中运行脚本时,sys.path从项目的目录开始。 task_mod在那里,你可以导入它。此外,当您执行类似pip install -e .之类的操作时,软件包也将被安装&#34;进入Python / virtualenv库列表,但以不同的方式。

但是,当您运行python3 task_mod/pydo.py时,您当前的目录为.../task_mod/。在那里,你找不到task_mod包(因为它是一层上层)。

另一方面,当您运行python3 setup.py时,您当前的目录是项目的目录,而您无法导入styles&amp; taskhandler直接就像你做的那样(没有task_mod.前缀)。

这正是您永远不要依赖sys.path,并且永远不要直接使用脚本并假设其位置的原因。因为它各不相同。

您可以尝试运行PYTHONPATH=. python3 task_mod/pydo.py使其与setup.py(或PYTHONPATH=./task_mod/ python3 setup.py相同,以使其与task_mod/pydo.py相同)。但这是一个让它成功的肮脏黑客。相反,您应该根据Python的惯例正确布局您的库。