Skip to content

Commit 200422d

Browse files
committed
use setup.cfg rather than setup.py
1 parent 11ad6e1 commit 200422d

5 files changed

Lines changed: 343 additions & 66 deletions

File tree

Makefile.venv

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
#
2+
# SEAMLESSLY MANAGE PYTHON VIRTUAL ENVIRONMENT WITH A MAKEFILE
3+
#
4+
# https://github.com/sio/Makefile.venv v2023.04.17
5+
#
6+
#
7+
# Insert `include Makefile.venv` at the bottom of your Makefile to enable these
8+
# rules.
9+
#
10+
# When writing your Makefile use '$(VENV)/python' to refer to the Python
11+
# interpreter within virtual environment and '$(VENV)/executablename' for any
12+
# other executable in venv.
13+
#
14+
# This Makefile provides the following targets:
15+
# venv
16+
# Use this as a dependency for any target that requires virtual
17+
# environment to be created and configured
18+
# python, ipython
19+
# Use these to launch interactive Python shell within virtual environment
20+
# shell, bash, zsh
21+
# Launch interactive command line shell. "shell" target launches the
22+
# default shell Makefile executes its rules in (usually /bin/sh).
23+
# "bash" and "zsh" can be used to refer to the specific desired shell.
24+
# show-venv
25+
# Show versions of Python and pip, and the path to the virtual environment
26+
# clean-venv
27+
# Remove virtual environment
28+
# $(VENV)/executable_name
29+
# Install `executable_name` with pip. Only packages with names matching
30+
# the name of the corresponding executable are supported.
31+
# Use this as a lightweight mechanism for development dependencies
32+
# tracking. E.g. for one-off tools that are not required in every
33+
# developer's environment, therefore are not included into
34+
# requirements.txt or setup.py.
35+
# Note:
36+
# Rules using such target or dependency MUST be defined below
37+
# `include` directive to make use of correct $(VENV) value.
38+
# Example:
39+
# codestyle: $(VENV)/pyflakes
40+
# $(VENV)/pyflakes .
41+
# See `ipython` target below for another example.
42+
#
43+
# This Makefile can be configured via following variables:
44+
# PY
45+
# Command name for system Python interpreter. It is used only initially to
46+
# create the virtual environment
47+
# Default: python3
48+
# REQUIREMENTS_TXT
49+
# Space separated list of paths to requirements.txt files.
50+
# Paths are resolved relative to current working directory.
51+
# Default: requirements.txt
52+
#
53+
# Non-existent files are treated as hard dependencies,
54+
# recipes for creating such files must be provided by the main Makefile.
55+
# Providing empty value (REQUIREMENTS_TXT=) turns off processing of
56+
# requirements.txt even when the file exists.
57+
# SETUP_PY, SETUP_CFG, PYPROJECT_TOML, VENV_LOCAL_PACKAGE
58+
# Space separated list of paths to files that contain build instructions
59+
# for local Python packages. Corresponding packages will be installed
60+
# into venv in editable mode along with all their dependencies.
61+
# Default: setup.py setup.cfg pyproject.toml (whichever present)
62+
#
63+
# Non-existent and empty values are treated in the same way as for REQUIREMENTS_TXT.
64+
# WORKDIR
65+
# Parent directory for the virtual environment.
66+
# Default: current working directory.
67+
# VENVDIR
68+
# Python virtual environment directory.
69+
# Default: $(WORKDIR)/.venv
70+
#
71+
# This Makefile was written for GNU Make and may not work with other make
72+
# implementations.
73+
#
74+
#
75+
# Copyright (c) 2019-2023 Vitaly Potyarkin
76+
#
77+
# Licensed under the Apache License, Version 2.0
78+
# <http://www.apache.org/licenses/LICENSE-2.0>
79+
#
80+
81+
82+
#
83+
# Configuration variables
84+
#
85+
86+
WORKDIR?=.
87+
VENVDIR?=$(WORKDIR)/.venv
88+
REQUIREMENTS_TXT?=$(wildcard requirements.txt) # Multiple paths are supported (space separated)
89+
SETUP_PY?=$(wildcard setup.py) # Multiple paths are supported (space separated)
90+
SETUP_CFG?=$(foreach s,$(SETUP_PY),$(wildcard $(patsubst %setup.py,%setup.cfg,$(s))))
91+
PYPROJECT_TOML?=$(wildcard pyproject.toml)
92+
VENV_LOCAL_PACKAGE?=$(SETUP_PY) $(SETUP_CFG) $(PYPROJECT_TOML)
93+
MARKER=.initialized-with-Makefile.venv
94+
95+
96+
#
97+
# Python interpreter detection
98+
#
99+
100+
_PY_AUTODETECT_MSG=Detected Python interpreter: $(PY). Use PY environment variable to override
101+
102+
ifeq (ok,$(shell test -e /dev/null 2>&1 && echo ok))
103+
NULL_STDERR=2>/dev/null
104+
else
105+
NULL_STDERR=2>NUL
106+
endif
107+
108+
ifndef PY
109+
_PY_OPTION:=python3
110+
ifeq (ok,$(shell $(_PY_OPTION) -c "print('ok')" $(NULL_STDERR)))
111+
PY=$(_PY_OPTION)
112+
endif
113+
endif
114+
115+
ifndef PY
116+
_PY_OPTION:=$(VENVDIR)/bin/python
117+
ifeq (ok,$(shell $(_PY_OPTION) -c "print('ok')" $(NULL_STDERR)))
118+
PY=$(_PY_OPTION)
119+
$(info $(_PY_AUTODETECT_MSG))
120+
endif
121+
endif
122+
123+
ifndef PY
124+
_PY_OPTION:=$(subst /,\,$(VENVDIR)/Scripts/python)
125+
ifeq (ok,$(shell $(_PY_OPTION) -c "print('ok')" $(NULL_STDERR)))
126+
PY=$(_PY_OPTION)
127+
$(info $(_PY_AUTODETECT_MSG))
128+
endif
129+
endif
130+
131+
ifndef PY
132+
_PY_OPTION:=py -3
133+
ifeq (ok,$(shell $(_PY_OPTION) -c "print('ok')" $(NULL_STDERR)))
134+
PY=$(_PY_OPTION)
135+
$(info $(_PY_AUTODETECT_MSG))
136+
endif
137+
endif
138+
139+
ifndef PY
140+
_PY_OPTION:=python
141+
ifeq (ok,$(shell $(_PY_OPTION) -c "print('ok')" $(NULL_STDERR)))
142+
PY=$(_PY_OPTION)
143+
$(info $(_PY_AUTODETECT_MSG))
144+
endif
145+
endif
146+
147+
ifndef PY
148+
define _PY_AUTODETECT_ERR
149+
Could not detect Python interpreter automatically.
150+
Please specify path to interpreter via PY environment variable.
151+
endef
152+
$(error $(_PY_AUTODETECT_ERR))
153+
endif
154+
155+
156+
#
157+
# Internal variable resolution
158+
#
159+
160+
VENV=$(VENVDIR)/bin
161+
EXE=
162+
# Detect windows
163+
ifeq (win32,$(shell $(PY) -c "import __future__, sys; print(sys.platform)"))
164+
EXE=.exe
165+
endif
166+
167+
touch=touch $(1)
168+
ifeq (,$(shell command -v touch $(NULL_STDERR)))
169+
# https://ss64.com/nt/touch.html
170+
touch=type nul >> $(subst /,\,$(1)) && copy /y /b $(subst /,\,$(1))+,, $(subst /,\,$(1))
171+
endif
172+
173+
RM?=rm -f
174+
ifeq (,$(shell command -v $(firstword $(RM)) $(NULL_STDERR)))
175+
RMDIR:=rd /s /q
176+
else
177+
RMDIR:=$(RM) -r
178+
endif
179+
180+
181+
#
182+
# Virtual environment
183+
#
184+
185+
.PHONY: venv
186+
venv: $(VENV)/$(MARKER)
187+
188+
.PHONY: clean-venv
189+
clean-venv:
190+
-$(RMDIR) "$(VENVDIR)"
191+
192+
.PHONY: show-venv
193+
show-venv: venv
194+
@$(VENV)/python -c "import sys; print('Python ' + sys.version.replace('\n',''))"
195+
@$(VENV)/pip --version
196+
@echo venv: $(VENVDIR)
197+
198+
.PHONY: debug-venv
199+
debug-venv:
200+
@echo "PATH (Shell)=$$PATH"
201+
@$(MAKE) --version
202+
$(info PATH (GNU Make)="$(PATH)")
203+
$(info SHELL="$(SHELL)")
204+
$(info PY="$(PY)")
205+
$(info REQUIREMENTS_TXT="$(REQUIREMENTS_TXT)")
206+
$(info VENV_LOCAL_PACKAGE="$(VENV_LOCAL_PACKAGE)")
207+
$(info VENVDIR="$(VENVDIR)")
208+
$(info VENVDEPENDS="$(VENVDEPENDS)")
209+
$(info WORKDIR="$(WORKDIR)")
210+
211+
212+
#
213+
# Dependencies
214+
#
215+
216+
ifneq ($(strip $(REQUIREMENTS_TXT)),)
217+
VENVDEPENDS+=$(REQUIREMENTS_TXT)
218+
endif
219+
220+
ifneq ($(strip $(VENV_LOCAL_PACKAGE)),)
221+
VENVDEPENDS+=$(VENV_LOCAL_PACKAGE)
222+
endif
223+
224+
$(VENV):
225+
$(PY) -m venv $(VENVDIR)
226+
$(VENV)/python -m pip install --upgrade pip setuptools wheel
227+
228+
$(VENV)/$(MARKER): $(VENVDEPENDS) | $(VENV)
229+
ifneq ($(strip $(REQUIREMENTS_TXT)),)
230+
$(VENV)/pip install $(foreach path,$(REQUIREMENTS_TXT),-r $(path))
231+
endif
232+
ifneq ($(strip $(VENV_LOCAL_PACKAGE)),)
233+
$(VENV)/pip install $(foreach path,$(sort $(VENV_LOCAL_PACKAGE)),-e $(dir $(path)))
234+
endif
235+
$(call touch,$(VENV)/$(MARKER))
236+
237+
238+
#
239+
# Interactive shells
240+
#
241+
242+
.PHONY: python
243+
python: venv
244+
exec $(VENV)/python
245+
246+
.PHONY: ipython
247+
ipython: $(VENV)/ipython
248+
exec $(VENV)/ipython
249+
250+
.PHONY: shell
251+
shell: venv
252+
. $(VENV)/activate && exec $(notdir $(SHELL))
253+
254+
.PHONY: bash zsh
255+
bash zsh: venv
256+
. $(VENV)/activate && exec $@
257+
258+
259+
#
260+
# Commandline tools (wildcard rule, executable name must match package name)
261+
#
262+
263+
ifneq ($(EXE),)
264+
$(VENV)/%: $(VENV)/%$(EXE) ;
265+
.PHONY: $(VENV)/%
266+
.PRECIOUS: $(VENV)/%$(EXE)
267+
endif
268+
269+
$(VENV)/%$(EXE): $(VENV)/$(MARKER)
270+
$(VENV)/pip install --upgrade $*
271+
$(call touch,$@)

makefile

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,50 @@
11
.PHONY: upload release release-test release-tag upload
22

3-
VERSION_FILE?=setup.py
4-
53
version:
6-
python setup.py --version
7-
8-
version-%: OLDVERSION:=$(shell python setup.py --version)
9-
version-%: NEWVERSION=$(subst -,.,$*)
10-
version-%:
11-
sed -i '' -e s/$(OLDVERSION)/$(NEWVERSION)/ $(VERSION_FILE)
12-
git ci setup.py -m"bump version to $*"
13-
14-
lint:
15-
flake8 --count --statistics redbeat tests
4+
ifdef VERSION
5+
sed -i -e 's|version = .*|version = $(VERSION)|' setup.cfg
6+
#git ci setup.py -m"bump version to $*"
7+
else
8+
echo "usage: make version VERSION='M.m.p'"
9+
endif
1610

11+
lint: venv
12+
$(VENV)/flake8 --count --statistics redbeat tests
1713

18-
release: release-check release-tag upload
14+
build:
15+
$(VENV)/python -m build
1916

17+
release: release-check build release-tag upload
2018
release-check:
19+
# ensure latest code
2120
git pull
22-
make test
21+
# ensure no local changes
22+
test -z "`git status --porcelain`"
23+
$(MAKE) test
2324

24-
release-tag: VERSION:=$(shell python setup.py --version)
25+
release-tag: VERSION:=$(shell grep 'version = ' setup.cfg | cut -d '=' -f 2 | sed 's/ //')
2526
release-tag: TODAY:=$(shell date '+%Y-%m-%d')
2627
release-tag:
2728
sed -i -e "s/unreleased/$(TODAY)/" CHANGES.txt
2829
git ci -m"update release date for $(VERSION) in CHANGES.txt" CHANGES.txt
2930
git tag -a v$(VERSION) -m"release version $(VERSION)"
3031
git push --tags
3132

32-
upload: VERSION:=$(shell python setup.py --version)
33-
upload:
34-
python setup.py sdist bdist_wheel
35-
twine upload $(wildcard dist/celery-*$(VERSION)*) $(wildcard dist/celery_*$(VERSION)*)
33+
upload: venv
34+
$(VENV)/twine check --strict dist/*
35+
$(VENV)/twine upload dist/*
3636

3737
docs:
38-
$(MAKE) -C docs/ html
38+
$(MAKE) -C docs/ html
3939

4040
test: unittests
41-
42-
unittests:
43-
python -m unittest discover tests
41+
unittests: venv
42+
$(VENV)/python -m unittest discover tests
4443

4544
clean:
4645
rm -f dist/*
4746
rm -rf docs/_build docs/_static docs/_templates
47+
48+
veryclean: clean clean-venv
49+
50+
include Makefile.venv

requirements-dev.txt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1-
black
1+
# Packages dependencies
22
celery>=5.0
33
fakeredis>=1.0.3
44
python-dateutil
55
redis>=3.2
66
tenacity
7-
twine
8-
wheel
97
backports.zoneinfo>=0.2.1; python_version < "3.9.0"
108
pytz
9+
10+
# Linting
11+
black
12+
flake8
13+
flake8-black
14+
flake8-isort
15+
16+
17+
# Releasing
18+
build
19+
twine
20+
wheel

0 commit comments

Comments
 (0)