在 travis 中安装和测试 python 项目
Installing and testing a python project in travis
我有这样的文件结构:
./
project_name/
__init__.py
setup.py
tests/
.travis.yml
所以我 运行 py.test 在我的 .travis.yml 中。根据我安装包的方式,它要么工作要么我遇到错误。
如果我使用 pip install -e .
安装软件包,一切都很好,但这有一个缺点,即不是一个真实的安装场景。
如果我使用 pip install .
安装软件包,它的安装方式与在非开发模式下的另一台计算机上的安装方式相同。但是,出现了一个问题:当我运行 pytest时,我的测试使用import project_name
。然后,python 从目录本地导入而不是使用已安装的包,导致 ImportMismatchError
.
处理此问题的最佳方法是什么?
一个解决方案可能是在顶层创建一个名为 tox.ini
的文件以与 tox 一起使用。这是一个负责构建环境的工具 - 它类似于 make
但更具体地用于 python 的东西。如果你做一个 tox.ini
:
[tox]
envlist = py
[testenv]
commands = pytest tests
deps =
pytest
然后用 pip3 install tox
安装 tox
,然后只需在命令行中输入命令 tox
,它将负责安装软件包并 运行在隔离的虚拟环境中进行测试。
然后,您可以在 travis.yml
:
中执行此操作
language: python
python:
- 3.6
install:
- pip install tox
script:
- tox
Travis 将使用 tox
以更可重现的方式 运行 进行测试。
如果您想 运行 对已安装的代码进行测试,您需要一个包含将要安装的所有源代码的中间目录(不是包);它的通用名称只是 src
。示例布局:
project_root
├── src
│ ├── spam
│ │ ├── __init__.py
│ │ └── eggs.py
│ └── ...
├── tests
│ ├── test_spam.py
│ └── ...
└── setup.py
调整安装脚本以支持 src
目录:
# setup.py
from setuptools import setup, find_packages
setup(
name='spam',
...
packages=find_packages('src'),
package_dir={'': 'src'},
...
)
使用此布局,虽然当前目录 (project_root
) 仍添加到 sys.path
,但所有包都已隐藏,无法导入。这样,您就必须安装您的包才能调用测试,并且始终测试已安装的代码。通常,您在编写代码时通过 pip install --editable .
在本地计算机上以开发模式安装包,并在 CI 服务器上通过 pip install .
安装包,测试将在实际包上执行安装。另一个优点是此布局不允许您在安装脚本中导入包的源代码,安装时不会 运行 陷入先有鸡还是先有蛋的问题(要安装您的代码,您的代码必须已经安装).
如果你有松散的模块,我更喜欢使用 pathlib
:
py_modules=[p.name for p in pathlib.Path('src').glob('*.py')]
如果您仍然需要 Python 2 兼容性,解决方案可能如下所示:
py_modules=[os.path.splitext(os.path.basename(p))[0] for p in glob.glob("src/*.py")]
我有这样的文件结构:
./
project_name/
__init__.py
setup.py
tests/
.travis.yml
所以我 运行 py.test 在我的 .travis.yml 中。根据我安装包的方式,它要么工作要么我遇到错误。
如果我使用 pip install -e .
安装软件包,一切都很好,但这有一个缺点,即不是一个真实的安装场景。
如果我使用 pip install .
安装软件包,它的安装方式与在非开发模式下的另一台计算机上的安装方式相同。但是,出现了一个问题:当我运行 pytest时,我的测试使用import project_name
。然后,python 从目录本地导入而不是使用已安装的包,导致 ImportMismatchError
.
处理此问题的最佳方法是什么?
一个解决方案可能是在顶层创建一个名为 tox.ini
的文件以与 tox 一起使用。这是一个负责构建环境的工具 - 它类似于 make
但更具体地用于 python 的东西。如果你做一个 tox.ini
:
[tox]
envlist = py
[testenv]
commands = pytest tests
deps =
pytest
然后用 pip3 install tox
安装 tox
,然后只需在命令行中输入命令 tox
,它将负责安装软件包并 运行在隔离的虚拟环境中进行测试。
然后,您可以在 travis.yml
:
language: python
python:
- 3.6
install:
- pip install tox
script:
- tox
Travis 将使用 tox
以更可重现的方式 运行 进行测试。
如果您想 运行 对已安装的代码进行测试,您需要一个包含将要安装的所有源代码的中间目录(不是包);它的通用名称只是 src
。示例布局:
project_root
├── src
│ ├── spam
│ │ ├── __init__.py
│ │ └── eggs.py
│ └── ...
├── tests
│ ├── test_spam.py
│ └── ...
└── setup.py
调整安装脚本以支持 src
目录:
# setup.py
from setuptools import setup, find_packages
setup(
name='spam',
...
packages=find_packages('src'),
package_dir={'': 'src'},
...
)
使用此布局,虽然当前目录 (project_root
) 仍添加到 sys.path
,但所有包都已隐藏,无法导入。这样,您就必须安装您的包才能调用测试,并且始终测试已安装的代码。通常,您在编写代码时通过 pip install --editable .
在本地计算机上以开发模式安装包,并在 CI 服务器上通过 pip install .
安装包,测试将在实际包上执行安装。另一个优点是此布局不允许您在安装脚本中导入包的源代码,安装时不会 运行 陷入先有鸡还是先有蛋的问题(要安装您的代码,您的代码必须已经安装).
如果你有松散的模块,我更喜欢使用 pathlib
:
py_modules=[p.name for p in pathlib.Path('src').glob('*.py')]
如果您仍然需要 Python 2 兼容性,解决方案可能如下所示:
py_modules=[os.path.splitext(os.path.basename(p))[0] for p in glob.glob("src/*.py")]