[英]How to use virtualenv in makefile
我想在指定的 virtualenv 上执行多个操作。
例如命令
make install
相当于
source path/to/virtualenv/bin/activate
pip install -r requirements.txt
是否可以?
我喜欢使用仅在requirements.txt
更改时运行的东西:
这假定源文件正在project
在项目的根目录下,并且测试是在project/test
。 (您应该更改project
以匹配您的实际项目名称。)
venv: venv/touchfile
venv/touchfile: requirements.txt
test -d venv || virtualenv venv
. venv/bin/activate; pip install -Ur requirements.txt
touch venv/touchfile
test: venv
. venv/bin/activate; nosetests project/test
clean:
rm -rf venv
find -iname "*.pyc" -delete
make
在requirements.txt
安装包。make test
来运行您的测试(如果您的测试在其他地方,您可以更新此命令)。make clean
以删除所有工件。在 make 中,您可以将 shell 作为命令运行。 在这个 shell 中,您可以执行在从命令行启动的 shell 中可以执行的所有操作。 例子:
install:
( \
source path/to/virtualenv/bin/activate; \
pip install -r requirements.txt; \
)
必须注意;
和\\
。
开括号和闭括号之间的所有内容都将在外壳的单个实例中完成。
通常make
在不同的子 shell 中运行配方中的每个命令。 但是,设置.ONESHELL:
将在同一.ONESHELL:
运行配方中的所有命令,允许您激活 virtualenv,然后在其中运行命令。
请注意.ONESHELL:
适用于整个 Makefile,而不仅仅是单个配方。 它可能会改变现有命令的行为,完整文档中可能出现的错误的详细信息。 这不会让你激活一个 virtualenv 以在 Makefile 之外使用,因为命令仍然在子 shell 内运行。
参考文档: https : //www.gnu.org/software/make/manual/html_node/One-Shell.html
例子:
.ONESHELL:
.PHONY: install
install:
source path/to/virtualenv/bin/activate
pip install -r requirements.txt
我很幸运。
install:
source ./path/to/bin/activate; \
pip install -r requirements.txt; \
这是运行您想要在 virtualenv 中运行的东西的另一种方法。
BIN=venv/bin/
install:
$(BIN)pip install -r requirements.txt
run:
$(BIN)python main.py
PS:这不会激活 virtualenv,但会完成任务。 希望你觉得它干净而且有用。
基于上面的答案(感谢@Saurabh 和@oneself!)我编写了一个可重用的 Makefile,负责创建虚拟环境并保持更新: https : //github.com/sio/Makefile.venv
它通过在 virtualenv 中引用正确的可执行文件来工作,并且不依赖于“激活”shell 脚本。 下面是一个例子:
test: venv
$(VENV)/python -m unittest
include Makefile.venv
考虑到 Windows 和其他操作系统之间的差异,Makefile.venv 应该可以在任何提供 Python 和 make 的操作系统上正常工作。
您还可以使用名为“VIRTUALENVWRAPPER_SCRIPT”的环境变量。 像这样:
install:
( \
source $$VIRTUALENVWRAPPER_SCRIPT; \
pip install -r requirements.txt; \
)
我喜欢设置我的 Makefile 以便它使用venv
目录(如果存在),但默认使用 PATH。
对于本地开发,我喜欢使用venv
,所以我运行:
make venv # /usr/bin/python3 -m venv venv
make deps # .venv/bin/python -m pip install -r requirements.txt
make test # .venv/bin/python -m tox
如果我安装到容器中,或者安装到我的机器中,我可能会绕过虚拟环境:
make deps # /usr/bin/python3 -m pip install -r requirements.txt
make test # /usr/bin/python3 -m tox
make build # /usr/bin/python3 -m build --wheel
make install # /usr/bin/python3 -m pip install dist/*.whl
在 Makefile 的顶部,定义这两个变量:
# If `venv/bin/python` exists, it is used. If not, use PATH to find python.
SYSTEM_PYTHON = $(or $(shell which python3), $(shell which python))
PYTHON = $(or $(wildcard venv/bin/python), $(SYSTEM_PYTHON))
其中评估为:
# If "venv" dir exists:
SYSTEM_PYTHON = /usr/bin/python3
PYTHON = .venv/bin/python
# If "venv" dir does not exist:
SYSTEM_PYTHON = /usr/bin/python3
PYTHON = /usr/bin/python3
注意: /usr/bin/python3
可能是您系统上的其他内容,具体取决于您的PATH
。
在您的 makefile 中,像这样运行可执行文件(包括 pip):
$(PYTHON) -m tox
您可能想要创建一个venv
目标来创建venv
目录:
venv:
rm -rf $(VENV)
$(SYSTEM_PYTHON) -m venv $(VENV)
还有一个deps
目标来安装依赖项:
deps:
$(PYTHON) -m pip install -r requirements.txt
这是我的 Makefile:
MAKEFLAGS = --no-print-directory --no-builtin-rules
.DEFAULT_GOAL = all
# Variables
PACKAGE = mypackage
# If virtualenv exists, use it. If not, use PATH to find
SYSTEM_PYTHON = $(or $(shell which python3), $(shell which python))
PYTHON = $(or $(wildcard venv/bin/python), $(SYSTEM_PYTHON))
all: test build
.PHONY: all
## Environment
venv:
rm -rf venv
$(SYSTEM_PYTHON) -m venv venv
deps:
$(PYTHON) -m pip install --upgrade pip -r requirements.txt -r requirements_dev.txt
.PHONY: venv deps
## Lint, test
test:
$(PYTHON) -m tox
dev/test:
$(PYTHON) -m tox -e py38
dev/lint:
$(PYTHON) -m tox -e lint
dev/lintfix:
$(PYTHON) -m black $(PACKAGE) tests setup.py
.PHONY: test dev/test dev/lint dev/lintfix
## Build, install
build:
$(PYTHON) -m build --sdist
$(PYTHON) -m build --wheel
install:
$(PYTHON) -m pip install dist/$(PACKAGE)-*.whl
.PHONY: build install
## Clean
clean:
rm -rf .out .pytest_cache .tox *.egg-info dist build
.PHONY: clean
聚会有点晚了,但这是我通常的设置:
# system python interpreter. used only to create virtual environment
PY = python3
VENV = venv
BIN=$(VENV)/bin
# make it work on windows too
ifeq ($(OS), Windows_NT)
BIN=$(VENV)/Scripts
PY=python
endif
all: lint test
$(VENV): requirements.txt requirements-dev.txt setup.py
$(PY) -m venv $(VENV)
$(BIN)/pip install --upgrade -r requirements.txt
$(BIN)/pip install --upgrade -r requirements-dev.txt
$(BIN)/pip install -e .
touch $(VENV)
.PHONY: test
test: $(VENV)
$(BIN)/pytest
.PHONY: lint
lint: $(VENV)
$(BIN)/flake8
.PHONY: release
release: $(VENV)
$(BIN)/python setup.py sdist bdist_wheel upload
clean:
rm -rf $(VENV)
find . -type f -name *.pyc -delete
find . -type d -name __pycache__ -delete
我对此做了一些更详细的文章,但基本上这个想法是你使用系统的Python来创建虚拟环境,而对于其他目标,只需在你的命令前面加上指向bin
或Scripts
目录的$(BIN)
变量你的venv。 这相当于activate
function。
我发现在$PATH
之前添加$VIRTUAL_ENV
是最好的方法:
activate
和约束自己来混淆食谱;
链接
python
,它将返回到系统 Python
bash
)和 POSIX# SYSTEM_PYTHON defaults to Python on the local machine
SYSTEM_PYTHON = $(shell which python)
REPO_ROOT = $(shell pwd)
# Specify with REPO_ROOT so recipes can safely change directories
export VIRTUAL_ENV := ${REPO_ROOT}/venv
# bin = POSIX, Scripts = Windows
export PATH := ${VIRTUAL_ENV}/bin:${VIRTUAL_ENV}/Scripts:${PATH}
对于那些对示例用法感兴趣的人:
# SEE: http://redsymbol.net/articles/unofficial-bash-strict-mode/
SHELL=/bin/bash -euo pipefail
.DEFAULT_GOAL := fresh-install
show-python: ## Show path to python and version.
@echo -n "python location: "
@python -c "import sys; print(sys.executable, end='')"
@echo -n ", version: "
@python -c "import platform; print(platform.python_version())"
show-venv: show-python
show-venv: ## Show output of python -m pip list.
python -m pip list
install: show-python
install: ## Install all dev dependencies into a local virtual environment.
python -m pip install -r requirements-dev.txt --progress-bar off
fresh-install: ## Run a fresh install into a local virtual environment.
-rm -rf venv
$(SYSTEM_PYTHON) -m venv venv
@$(MAKE) install
你应该使用这个,它现在对我有用。
report.ipynb : merged.ipynb
( bash -c "source ${HOME}/anaconda3/bin/activate py27; which -a python; \
jupyter nbconvert \
--to notebook \
--ExecutePreprocessor.kernel_name=python2 \
--ExecutePreprocessor.timeout=3000 \
--execute merged.ipynb \
--output=$< $<" )
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.