python.mk 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. # The following python-related tools and processes are supported:
  2. # * black
  3. # * coverage (requires ".coveragerc")
  4. # * flake8
  5. # * pypi upload (requires "~/.pypirc")
  6. # * tox / unittests (requires "tox.ini")
  7. #
  8. PYTHON_BIN ?= python3
  9. DIR_PYTHON_BUILD ?= $(DIR_BUILD)/python-lib
  10. PYTHON_BDIST_ARGS = --dist-dir $(DIR_BUILD)/python-packages
  11. PYTHON_BUILD_ARGS = --build-base "$(DIR_PYTHON_BUILD)"
  12. PYTHON_INSTALL_ARGS = --root "$(abspath $(DESTDIR))"
  13. DISABLE_PYTHON_TESTS ?= 0
  14. DISABLE_PYTHON_LINT_FLAKE8 ?= 0
  15. ENABLE_PYTHON_LINT_BLACK ?= 0
  16. PYPI_UPLOAD_TARGET ?= https://pypi.python.org/pypi
  17. DIR_PYTHON_COVERAGE_HTML = $(DIR_BUILD)/coverage-html
  18. # detect if flake8 is available as an executable (e.g. Arch) or as a python module (e.g. Debian)
  19. FLAKE8_BIN ?= $(shell hash flake8 2>/dev/null && echo "flake8" || echo "$(PYTHON_BIN) -m flake8")
  20. FLAKE8_FILES ?= $(DIR_PYTHON_SETUP)
  21. RUN_PYTHON = $(PYTHON_BIN)
  22. BLACK_BIN ?= black
  23. # projects may want to override this with something like "--target-version=py39"
  24. BLACK_ARGS ?=
  25. BLACK_FILES ?= $(DIR_PYTHON_SETUP)
  26. PYTHON_TOX_FILE ?= $(DIR_PYTHON_SETUP)/tox.ini
  27. PYTHON_TEST_POETRY_COMMAND ?= pytest
  28. PYTHON_BUILD_SYSTEM ?= $(shell \
  29. if grep -q "^build-backend.*hatch" "$(PYTHON_PYPROJECT_FILE)" 2>/dev/null; then echo "hatchling"; \
  30. elif grep -q "^build-backend.*poetry" "$(PYTHON_PYPROJECT_FILE)" 2>/dev/null; then echo "poetry"; \
  31. elif [ -e "$(PYTHON_SETUP_FILE)" ]; then echo "setuptools"; \
  32. fi)
  33. PYTHON_TEST_RUNNER ?= $(shell \
  34. if [ -e "$(PYTHON_TOX_FILE)" ]; then echo "tox"; \
  35. elif [ -e manage.py ]; then echo "django"; \
  36. elif [ "$(PYTHON_BUILD_SYSTEM)" = "hatchling" ]; then echo "hatch"; \
  37. elif [ "$(PYTHON_BUILD_SYSTEM)" = "poetry" ]; then echo "poetry"; \
  38. else echo "generic"; \
  39. fi)
  40. PYTHON_LINT_RUNNER ?= $(shell \
  41. if [ "$(PYTHON_BUILD_SYSTEM)" = "hatchling" ]; then echo "hatch"; \
  42. else echo "generic"; \
  43. fi)
  44. PYTHON_STYLE_RUNNER ?= $(shell \
  45. if [ "$(PYTHON_BUILD_SYSTEM)" = "hatchling" ]; then echo "hatch"; \
  46. else echo "generic"; \
  47. fi)
  48. .PHONY: help
  49. help: help-python
  50. .PHONY: help-python
  51. help-python:
  52. @echo "Python-specific packaging targets:"
  53. @echo " clean-python"
  54. @echo " dist-python"
  55. @echo " lint-python"
  56. @echo " report-python"
  57. @echo " style-python"
  58. @echo " test-python"
  59. @echo " upload-python"
  60. @echo
  61. .PHONY: dist
  62. dist: dist-python
  63. .PHONY: install
  64. install: install-python
  65. .PHONY: lint
  66. lint: lint-python
  67. .PHONY: style
  68. style: style-python
  69. ifneq ($(DISABLE_PYTHON_TESTS),1)
  70. .PHONY: test
  71. test: test-python
  72. endif
  73. .PHONY: install-python
  74. install-python:
  75. cd "$(DIR_PYTHON_SETUP)" && $(RUN_PYTHON) setup.py install $(PYTHON_INSTALL_ARGS)
  76. .PHONY: dist-python
  77. dist-python: clean-python
  78. cd "$(DIR_PYTHON_SETUP)" \
  79. && $(RUN_PYTHON) setup.py build $(PYTHON_BUILD_ARGS) bdist $(PYTHON_BDIST_ARGS)
  80. .PHONY: upload
  81. upload: upload-python
  82. .PHONY: upload-python
  83. upload-python:
  84. cd "$(DIR_PYTHON_SETUP)" && $(RUN_PYTHON) setup.py sdist upload -r "$(PYPI_UPLOAD_TARGET)"
  85. .PHONY: lint-python
  86. ifeq ($(PYTHON_LINT_RUNNER),hatch)
  87. lint-python: lint-python-hatch
  88. else ifeq ($(PYTHON_LINT_RUNNER),generic)
  89. ifeq ($(ENABLE_PYTHON_LINT_BLACK),1)
  90. lint-python: lint-python-black
  91. endif
  92. ifneq ($(DISABLE_PYTHON_LINT_FLAKE8),1)
  93. lint-python: lint-python-flake8
  94. endif
  95. endif
  96. .PHONY: lint-python-black
  97. lint-python-black:
  98. $(BLACK_BIN) --check $(BLACK_ARGS) $(BLACK_FILES)
  99. .PHONY: lint-python-flake8
  100. lint-python-flake8:
  101. $(FLAKE8_BIN) $(FLAKE8_FILES)
  102. .PHONY: lint-python-hatch
  103. lint-python-hatch:
  104. hatch run lint:all
  105. .PHONY: style-python
  106. ifeq ($(PYTHON_STYLE_RUNNER),hatch)
  107. style-python: style-python-hatch
  108. else ifeq ($(PYTHON_STYLE_RUNNER),generic)
  109. style-python: style-python-black
  110. endif
  111. .PHONY: style-python-black
  112. style-python-black:
  113. $(BLACK_BIN) $(BLACK_ARGS) $(BLACK_FILES)
  114. .PHONY: style-python-hatch
  115. style-python-hatch:
  116. hatch run lint:fmt
  117. .PHONY: test-python
  118. ifeq ($(PYTHON_TEST_RUNNER),tox)
  119. test-python: test-python-tox
  120. else ifeq ($(PYTHON_TEST_RUNNER),django)
  121. test-python: test-python-django
  122. else ifeq ($(PYTHON_TEST_RUNNER),hatch)
  123. test-python: test-python-hatch
  124. else ifeq ($(PYTHON_TEST_RUNNER),poetry)
  125. test-python: test-python-poetry
  126. else ifeq ($(PYTHON_TEST_RUNNER),generic)
  127. test-python: test-python-generic
  128. endif
  129. .PHONY: test-python-tox
  130. test-python-tox:
  131. tox
  132. .PHONY: test-python-django
  133. test-python-django:
  134. $(RUN_PYTHON) manage.py test
  135. .PHONY: test-python-hatch
  136. test-python-hatch:
  137. hatch run test
  138. .PHONY: test-python-poetry
  139. test-python-poetry:
  140. poetry run $(PYTHON_TEST_POETRY_COMMAND)
  141. .PHONY: test-python-generic
  142. test-python-generic:
  143. $(RUN_PYTHON) $(PYTHON_TEST_ARGS)
  144. .PHONY: report
  145. report: report-python
  146. .PHONY: report-python
  147. report-python:
  148. if [ -e .coveragerc ]; then $(MAKE) report-python-coverage; fi
  149. .PHONY: report-python-coverage
  150. report-python-coverage:
  151. @# run tests for coverage analysis
  152. $(RUN_PYTHON) -m coverage run $(PYTHON_TEST_ARGS)
  153. @# provide textual report
  154. $(RUN_PYTHON) -m coverage report
  155. $(RUN_PYTHON) -m coverage html --directory "$(DIR_PYTHON_COVERAGE_HTML)"
  156. @printf "Browse the coverage report:\n\tfile://%s/index.html\n" \
  157. "$(abspath $(DIR_PYTHON_COVERAGE_HTML))"
  158. @# run a visual browser if the DISPLAY variable is set
  159. @if [ -n "$$DISPLAY" ] && [ -n "$(COVERAGE_BROWSER_BIN)" ]; then \
  160. "$(COVERAGE_BROWSER_BIN)" "$(DIR_PYTHON_COVERAGE_HTML)/index.html"; fi
  161. .PHONY: clean-python
  162. clean-python:
  163. cd "$(DIR_PYTHON_SETUP)" && python3 setup.py clean || true
  164. @# datafile for python3-coverage
  165. $(RM) .coverage
  166. @# workaround for https://github.com/pypa/setuptools/issues/436
  167. $(RM) "$(DIR_PYTHON_SETUP)"/*.egg-info/SOURCES.txt
  168. clean: clean-python