簡體   English   中英

pytest 'ImportError: No module named YadaYadaYada' 的 PATH 問題

[英]PATH issue with pytest 'ImportError: No module named YadaYadaYada'

我使用 easy_install 在 Mac 上安裝 pytest 並開始為具有如下文件結構的項目編寫測試:

repo/
   |--app.py
   |--settings.py
   |--models.py
   |--tests/
          |--test_app.py

在 repo 目錄中運行py.test ,一切都如你所料

但是當我在 linux 或 windows 上嘗試同樣的事情時(兩者都有 pytest 2.2.3),每當它從我的應用程序路徑中第一次導入某些東西時,它就會吠叫。 例如from app import some_def_in_app

我是否需要編輯我的 PATH 才能在這些系統上運行 py.test? 有沒有人經歷過這個?

我不確定為什么 py.test 沒有在 PYTHONPATH 本身中添加當前目錄,但這里有一個解決方法(從存儲庫的根目錄執行):

python -m pytest tests/

它之所以有效,是因為 Python 會為您在 PYTHONPATH 中添加當前目錄。

pytest>=7的推薦方法:使用pythonpath設置

最近, pytest新增了一個核心插件,支持通過pythonpath配置值修改sys.path 因此,該解決方案現在要簡單得多,並且不再需要任何解決方法:

pyproject.toml示例:

[tool.pytest.ini_options]
pythonpath = [
  "."
]

pytest.ini示例:

[pytest]
pythonpath = .

路徑條目是相對於根目錄計算的,因此. 在這種情況下,將repo目錄添加到sys.path

還允許多個路徑條目:對於布局

repo/
├── src/
|   └── lib.py
├── app.py
└── tests
     ├── test_app.py
     └── test_lib.py

配置

[tool.pytest.ini_options]
pythonpath = [
  ".", "src",
]

或者

[pytest]
pythonpath = . src

applib模塊都添加到sys.path ,所以

import app
import lib

兩者都可以。

原始答案(不推薦用於最近的 pytest 版本;僅用於pytest<7 ): conftest解決方案

侵入性最小的解決方案是在repo/目錄中添加一個名為conftest.py的空文件:

$ touch repo/conftest.py

而已。 無需編寫自定義代碼來修改sys.path或記住拖動PYTHONPATH或將__init__.py放入不屬於它的目錄中(使用python -m pytestApteryx答案中所建議的那樣是一個很好的解決方案!)。

之后的項目目錄:

repo
├── conftest.py
├── app.py
├── settings.py
├── models.py
└── tests
     └── test_app.py

解釋

pytest在測試集合上查找conftest模塊以收集自定義鈎子和固定裝置,為了從中導入自定義對象, pytestconftest.py的父目錄添加到sys.path (在本例中為repo目錄) .

其他項目結構

如果您有其他項目結構,請將conftest.py放在包根目錄中(包含包但本身不是包的目錄,因此包含__init__.py ),例如:

repo
├── conftest.py
├── spam
│   ├── __init__.py
│   ├── bacon.py
│   └── egg.py
├── eggs
│   ├── __init__.py
│   └── sausage.py
└── tests
     ├── test_bacon.py
     └── test_egg.py

src布局

雖然這種方法可以與src布局一起使用(將conftest.py放在src目錄中):

repo
├── src
│   ├── conftest.py
│   ├── spam
│   │   ├── __init__.py
│   │   ├── bacon.py
│   │   └── egg.py
│   └── eggs 
│       ├── __init__.py
│       └── sausage.py
└── tests
     ├── test_bacon.py
     └── test_egg.py

請注意,將src添加到PYTHONPATH會減輕src布局的意義和好處! 您最終將測試來自存儲庫的代碼,而不是已安裝的包。 如果你需要這樣做,也許你根本不需要src目錄。

從這往哪兒走

當然, conftest模塊不僅僅是一些幫助源代碼發現的文件; 它是pytest框架的所有特定於項目的增強和測試套件的定制發生的地方。 pytest有很多關於conftest模塊的信息,分散在他們的文檔中; conftest.py開始:本地每個目錄插件

此外,SO 對conftest模塊有一個很好的問題:在 py.test 中,conftest.py 文件有什么用?

我有同樣的問題。 我通過在我的tests目錄中添加一個空的__init__.py文件來修復它。

是的,如果您cd到測試目錄,則源文件夾不在 Python 的路徑中。

您有 2 個選擇:

  1. 手動將路徑添加到測試文件中,如下所示:

     import sys, os myPath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, myPath + '/../')
  2. 使用 env var PYTHONPATH=../運行測試。

pytest本身作為一個模塊運行: python -m pytest tests

您可以在項目根目錄中使用 PYTHONPATH 運行

PYTHONPATH=. py.test

或者使用 pip install 作為可編輯的導入

pip install -e .   # install package using setup.py in editable mode

我在 Flask 中遇到了同樣的問題。

當我添加:

__init__.py

到測試文件夾,問題消失了:)

可能應用程序無法將文件夾測試識別為模塊

我創建這個是為了回答你的問題和我自己的困惑。 我希望它有所幫助。 注意 py.test 命令行和 tox.ini 中的 PYTHONPATH。

https://github.com/jeffmacdonald/pytest_test

具體來說:您必須告訴 py.test 和 tox 在哪里可以找到您所包含的模塊。

使用 py.test 你可以這樣做:

PYTHONPATH=. py.test

使用 tox,將其添加到您的 tox.ini 中:

[testenv]
deps= -r{toxinidir}/requirements.txt
commands=py.test
setenv =
    PYTHONPATH = {toxinidir}

我通過刪除源文件的父文件夾中的頂級__init__.py來修復它。

我開始變得奇怪ConftestImportFailure: ImportError('No module named ...錯誤當我不小心將__init__.py文件添加到我的 src 目錄時(它不應該是 Python 包,只是所有源的容器)。

我在學習 Flask 教程時遇到了同樣的問題,我在 Pytest 官方文檔中找到了答案。這與我(我認為許多其他人)習慣做事的方式有點不同。

您必須在項目的根目錄中創建一個setup.py文件,其中至少包含以下兩行:

from setuptools import setup, find_packages
setup(name="PACKAGENAME", packages=find_packages())

其中 PACKAGENAME 是您的應用程序的名稱。 然后你必須用 pip 安裝它:

pip install -e .

-e標志告訴 pip 以可編輯或“開發”模式安裝包。 因此,下次您運行pytest時,它應該會在標准PYTHONPATH中找到您的應用程序。

這是python中的一個問題有點遺憾......但只需添加這個環境變量是IMO最舒服的方式:

export PYTHONPATH=$PYTHONPATH:.

只需將其放入您的 .zshrc/.bashrc 中。

我有一個類似的問題。 pytest無法識別安裝在我工作環境中的模塊。

我通過將pytest安裝到同一環境中來解決它。

此外,如果您在虛擬環境中運行pytest ,請確保在您的虛擬環境中安裝pytest模塊。 激活您的虛擬環境並運行pip install pytest

對我來說,問題是 Django 生成的tests.py以及tests目錄。 刪除tests.py解決了這個問題。

我收到了這個錯誤,因為我錯誤地使用了相對導入。 在 OP 示例中,test_app.py 應該使用例如導入函數

from repo.app import *

然而 __init__.py 文件散布在文件結構周圍,這不起作用並創建了 ImportError 類型,除非文件和測試文件位於同一目錄中。

from app import *

這是我對我的一個項目所做的一個例子:

這是我的項目結構:

microbit/
microbit/activity_indicator/activity_indicator.py
microbit/tests/test_activity_indicator.py

為了能夠從 test_activity_indicator.py 訪問 activity_indicator.py,我需要:

  • 使用正確的相對導入啟動 test_activity_indicatory.py:
    from microbit.activity_indicator.activity_indicator import *
  • 將 __init__.py 文件放在整個項目結構中:
    microbit/
    microbit/__init__.py
    microbit/activity_indicator/__init__.py
    microbit/activity_indicator/activity_indicator.py
    microbit/tests/__init__.py
    microbit/tests/test_activity_indicator.py

由於更簡單的事情(你甚至可以說微不足道),我得到了這個錯誤。 我沒有安裝pytest模塊。 所以一個簡單的apt install python-pytest為我修復了它。

'pytest' 將作為測試依賴項列在 setup.py 中。 確保您也安裝了測試要求。

由於沒有人建議,您也可以在pytest.ini文件中傳遞測試路徑:

[pytest]
...
testpaths = repo/tests

請參閱文檔: https ://docs.pytest.org/en/6.2.x/customize.html#pytest-ini

VScode 的副作用:它應該在 UI 中進行單元測試。

根據Dirk Avery 在 Medium 上的一篇文章(並得到我個人經驗的支持),如果您在項目中使用虛擬環境,那么您不能使用系統范圍的 pytest 安裝; 您必須在虛擬環境中安裝它並使用該安裝。

特別是,如果您在兩個地方都安裝了它,那么簡單地運行pytest命令將不起作用,因為它將使用系統安裝。 正如其他答案所描述的,一個簡單的解決方案是運行python -m pytest而不是pytest 這是有效的,因為它使用環境的 pytest 版本。 或者,您可以只卸載系統版本的 pytest; 重新激活虛擬環境后, pytest命令應該可以工作。

正如Luiz Lezcano Arialdi所指出的,正確的解決方案是將您的包安裝為可編輯的包。

由於我使用的是 pipenv,我考慮在他的答案中逐步添加如何使用 pipenv 將當前路徑安裝為可食用的,從而允許運行 pytest 而無需任何修改代碼或松散文件。

您將需要具有以下最小文件夾結構(文檔):

package/
    package/
        __init__.py
        module.py
    tests/
        module_test.py
    setup.py

setup.py 大多數具有以下最小代碼( 文檔):

import setuptools


setuptools.setup(name='package', # Change to your package name
                 packages=setuptools.find_packages())

然后你只需要運行pipenv install --dev -e . 並且 pipenv 會將當前路徑安裝為可編輯的包( --dev 標志是可選的)( 文檔)。

現在你應該可以毫無問題地運行pytest了。

我們通過添加以下環境變量解決了這個問題。

PYTHONPATH=${PYTHONPATH}:${PWD}/src:${PWD}/test

如果這個pytest錯誤出現的不是你自己的包,而是你包的requirements.txt中一個git安裝的包,解決方法是切換到可編輯安裝模式。

例如,假設您的包的 requirements.txt 有以下行:

git+https://github.com/foo/bar.git

您可以將其替換為以下內容:

-e git+https://github.com/foo/bar.git#egg=bar

很多時候由於模塊無法導入而中斷測試,經過研究,我發現系統在錯誤的位置查看文件,我們可以通過復制包含模塊的文件輕松解決問題,在與所述相同的文件夾,以便正確導入。 另一個解決方案建議是更改導入的聲明並向 MutPy 顯示單元的正確路徑。 然而,由於多個單元可以具有這種依賴關系,這意味着我們還需要在它們的聲明中提交更改,我們更喜歡簡單地將單元移動到文件夾中。

我的解決方案:

test目錄中創建conftest.py文件,其中包含:

import os
import sys
sys.path.insert(0,os.path.dirname(os.path.realpath(__file__)) + "/relative/path/to/code/")

這會將感興趣的文件夾添加到 python 路徑中,而無需修改每個測試文件、設置環境變量或弄亂絕對/相對路徑。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM