在conda虛擬環境下使用py.test會調用主環境的Python

前言

這是筆者在撰寫Dockerfile時所碰到的錯誤。
以下是筆者撰寫的Dockerfile,這個Dockerfile的作用是建立rushter/MLAlgorithms這個項目所需的測試環境。
Dockerfile中使用conda建立Python 2.7的虛擬環境,並且需要pytest這個包。

FROM ubuntu:14.04

RUN apt-get -y update

RUN apt-get install -y wget bzip2 git build-essential

RUN apt-get install -y wget && if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then \
        wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh -O miniconda.sh; \
    else \
        wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; \
    fi

ENV HOME=/root

RUN bash miniconda.sh -b -p $HOME/miniconda

ENV PATH="${HOME}/miniconda/bin:${PATH}"

RUN hash -r

RUN $HOME/miniconda/bin/conda config --set always_yes yes --set changeps1 no

RUN $HOME/miniconda/bin/conda update -q conda

RUN $HOME/miniconda/bin/conda info -a

ENV TRAVIS_PYTHON_VERSION 2.7

RUN $HOME/miniconda/bin/conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy scipy scikit-learn

RUN $HOME/miniconda/bin/pip install pytest

RUN git clone https://github.com/rushter/MLAlgorithms.git $HOME/MLAlgorithms

WORKDIR $HOME/MLAlgorithms

RUN $HOME/miniconda/bin/pip install -r requirements.txt

docker鏡像建構完成後,使用docker run啟動。

docker run -it --rm ml_travis

接著啟動Python 2.7虛擬環境test-environment:

source activate test-environment

然後在MLAlgorithms的目錄下執行py.testpytest

py.test

或:

pytest

卻發現py.test使用的Python版本不是虛擬環境中的Python 2.7版而是主環境中的Python 3.7版。

執行結果

================================================= test session starts =================================================
platform linux – Python 3.7.1, pytest-4.1.0, py-1.7.0, pluggy-0.8.0
rootdir: /MLAlgorithms, inifile:
collected 28 items

mla/metrics/tests/test_metrics.py … [ 39%]
mla/neuralnet/tests/test_activations.py . [ 42%]
mla/neuralnet/tests/test_optimizers.py … [ 60%]
mla/tests/test_classification_accuracy.py … [ 85%]
mla/tests/test_reduction.py F [ 89%]
mla/tests/test_regression_accuracy.py … [100%]
=================================================== FAILURES ===================================================
______________________________________________________ test_PCA _______________________________________________________

def test_PCA():
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25,
random_state=1111)
p = PCA(100, solver=‘eigen’)
# fit PCA with training data, not the entire dataset
p.fit(X_train)
X_train_reduced = p.transform(X_train)
X_test_reduced = p.transform(X_test)
model = RandomForestClassifier(n_estimators=10, max_depth=4)
model.fit(X_train_reduced, y_train)
predictions = model.predict(X_test_reduced)[:, 1]
print(roc_auc_score(y_test, predictions))
assert roc_auc_score(y_test, predictions) >= 0.70
E assert 0.5713142564496512 >= 0.7
E + where 0.5713142564496512 = roc_auc_score(array([0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0,\n 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0,…1, 0, 0, 0, 1,\n 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,\n 0, 0, 1, 0, 1, 0, 0, 0]), array([0.48549337, 0.53610872, 0.57108251, 0.57108251, 0.48578407,\n 0.53178407, 0.49798327, 0.53578407, 0.634128…07, 0.56138926, 0.53578407, 0.48549337, 0.53578407,\n 0.48549337, 0.57350393, 0.45074634, 0.45074634, 0.48549337]))

mla/tests/test_reduction.py:31: AssertionError
-------------------------------------------------------- Captured stdout call ---------------------------------------------------------
0.5713142564496512

錯誤排查

使用How do I use pytest with virtualenv?這則問答中Icarus的方法:

python -m pytest

得到的結果是:

/root/miniconda/envs/test-environment/bin/python: No module named pytest

這說明在test-environment這個虛擬環境下並沒有安裝過pytest
回頭查看原始的Dockerfile,原來是在安裝pytest(及requirements.txt裡的包)時使用的是主環境下的pip,並非虛擬環境test-environment下的pip
所以pytest當然不存在於test-environment中。

解決辦法

1. 在虛擬環境下安裝pytest及requirements.txt裡的包

source activate test-environment
pip install pytest
pip install -r requirements.txt
python -m pytest #使用py.test還是會調用主環境裡的Python

執行結果:

================================================= test session starts =================================================
platform linux2 – Python 2.7.15, pytest-4.1.0, py-1.7.0, pluggy-0.8.0
rootdir: /root/MLAlgorithms, inifile:
collected 28 items

mla/metrics/tests/test_metrics.py … [ 39%]
mla/neuralnet/tests/test_activations.py . [ 42%]
mla/neuralnet/tests/test_optimizers.py … [ 60%]
mla/tests/test_classification_accuracy.py … [ 85%]
mla/tests/test_reduction.py . [ 89%]
mla/tests/test_regression_accuracy.py … [100%]

======================================= 28 passed, 137 warnings in 58.16 seconds=======================================

可以看到Python版本己經由3.7.1變成2.7.15,正是我們想要的結果!

2. 修改Dockerfile

原來的Dockerfile裡使用的是主環境下的pip,但那些包應該是要被安裝在test-environment底下才對。
以下是修正版的Dockerfile,改用虛擬環境下的pip

FROM ubuntu:14.04

RUN apt-get -y update

RUN apt-get install -y wget bzip2 git build-essential

RUN apt-get install -y wget && if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then \
        wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh -O miniconda.sh; \
    else \
        wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; \
    fi

ENV HOME=/root

RUN bash miniconda.sh -b -p $HOME/miniconda

ENV PATH="${HOME}/miniconda/bin:${PATH}"

RUN hash -r

RUN $HOME/miniconda/bin/conda config --set always_yes yes --set changeps1 no

RUN $HOME/miniconda/bin/conda update -q conda

RUN $HOME/miniconda/bin/conda info -a

ENV TRAVIS_PYTHON_VERSION 2.7

RUN $HOME/miniconda/bin/conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy scipy scikit-learn

RUN $HOME/miniconda/envs/test-environment/bin/pip install pytest

RUN git clone https://github.com/rushter/MLAlgorithms.git $HOME/MLAlgorithms

WORKDIR $HOME/MLAlgorithms

RUN $HOME/miniconda/envs/test-environment/bin/pip install -r requirements.txt

Lesson learned

經過實驗發現:
如果在虛擬環境中使用py.test這個指令,那麼不管虛擬環境裡有沒有安裝pytest,py.test都會調用主環境裡的Python。

在虛擬環境中使用pytest這個指令,如果虛擬環境裡己安裝pytest,那麼它會正確地調用虛擬環境裡的Python。
如果虛擬環境裡還沒安裝pytest,則會正常報錯:

bash: /root/miniconda/envs/test-environment/bin/pytest: No such file or directory

看起來,比起py.testpytest的表現符合我們的預期多了。
所以結論就是:用pytest,不要用py.test!

參考連結

How do I use pytest with virtualenv?

猜你喜欢

转载自blog.csdn.net/keineahnung2345/article/details/86080914