4 # The contents of this file are subject to the terms of the
5 # Common Development and Distribution License (the "License").
6 # You may not use this file except in compliance with the License.
8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 # or http://www.opensolaris.org/os/licensing.
10 # See the License for the specific language governing permissions
11 # and limitations under the License.
13 # When distributing Covered Code, include this CDDL HEADER in each
14 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 # If applicable, add the following below this CDDL HEADER, with the
16 # fields enclosed by brackets "[]" replaced with your own identifying
17 # information: Portions Copyright [yyyy] [name of copyright owner]
21 # Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
25 # The Python build infrastructure in setup.py.mk and pyproject.mk files uses
26 # several Python projects to work properly. Since we cannot use these projects
27 # until they are actually built and installed we need to bootstrap.
29 # We do have several sequential bootstrap checkpoints during the process:
31 # (0) Nothing works yet.
33 # Just core Python runtime is available (with no additional projects).
34 # While here almost nothing works. We cannot do following tasks with
35 # regular Python projects:
36 # - detect their requirements,
37 # - build and publish them,
40 # (1) The bootstrapper is ready.
42 # The bootstrapper is special tool that requires just core Python with no
43 # dependency on other Python projects and it is able to build and publish
44 # itself and other Python projects.
46 # For projects using the 'setup.py' build style we do not need any
47 # special bootstrapper because such projects are built using their own
48 # 'setup.py' script. The only issue with the 'setup.py' build style
49 # projects is that their 'setup.py' script usually depends on some other
50 # projects (typically setuptools) to get successfully built.
52 # For 'pyproject'-style projects we use pyproject_installer as the
55 # To achieve this checkpoint we just need to build pyproject_installer
56 # using pyproject_installer without detecting its requirements (they are
57 # none anyway) and without testing it (since no testing infrastructure is
60 # (2) The python-requires script works.
62 # Once the python-requires script works we can start to detect runtime
63 # dependencie of other Python projects automatically.
65 # To achieve this checkpoint we need to build the packaging project
66 # (directly needed by the python-requires script) and all projects
67 # required by packaging. During this all projects' dependencies needs to
68 # be manually evaluated to make sure they are correct.
70 # (3) The build infrastructure is fully working.
72 # Once we are here we can build any Python project, but we cannot test it
75 # For projects using the 'setup.py' build style we do not need any
76 # special build infrastructure. See checkpoint (1) above for detialed
77 # discussion about 'setup.py' build style projects.
79 # For 'pyproject'-style projects we need to build both 'build' and
80 # 'installer' projects and all projects they depends on.
82 # (4) The testing infrastructure is fully working.
84 # Once we are here we can finally use all features of the Python build
85 # framework. Including testing.
87 # To achieve this we need to build tox, tox-current-env, and pytest
88 # projects together with their dependencies.
90 # All projects needed to achieve checkpoints (1), (2), and (3) should set
91 # PYTHON_BOOTSTRAP to 'yes' in their Makefile to make sure the regular build
92 # infrastructure is not used for them and special set of build rules is applied
95 # All projects needed to go from checkpoint (3) to checkpoint (4) should set
96 # PYTHON_TEST_BOOTSTRAP to 'yes' in their Makefile to let the build
97 # infrastructure know that testing for such projects might not work properly.
99 # The PYTHON_BOOTSTRAP set to 'yes' implies PYTHON_TEST_BOOTSTRAP set to 'yes'
102 ifeq ($(strip $(PYTHON_BOOTSTRAP
)),yes
)
103 PYTHON_TEST_BOOTSTRAP
= yes
107 # Lists of Python projects needed to achieve particular bootstrap checkpoint.
108 # Indentation shows project dependencies (e.g. packaging requires flit_core).
110 PYTHON_BOOTSTRAP_CHECKPOINT_1
+= pyproject_installer
112 PYTHON_BOOTSTRAP_CHECKPOINT_2
+= $(PYTHON_BOOTSTRAP_CHECKPOINT_1
)
113 PYTHON_BOOTSTRAP_CHECKPOINT_2
+= packaging
114 PYTHON_BOOTSTRAP_CHECKPOINT_2
+= flit_core
116 # Particular python runtime is always required (at least to run setup.py)
117 PYTHON_REQUIRED_PACKAGES
+= runtime
/python
120 $(BUILD_DIR
)/%-$(1)/.built
: PYTHON_VERSION
=$(1)
121 $(BUILD_DIR
)/%-$(1)/.installed
: PYTHON_VERSION
=$(1)
122 $(BUILD_DIR
)/%-$(1)/.tested
: PYTHON_VERSION
=$(1)
123 $(BUILD_DIR
)/%-$(1)/.tested-and-compared
: PYTHON_VERSION
=$(1)
126 $(foreach pyver
, $(PYTHON_VERSIONS
), $(eval
$(call python-rule
,$(pyver
))))
128 $(BUILD_DIR
)/$(MACH32
)-%/.built
: BITS
=32
129 $(BUILD_DIR
)/$(MACH64
)-%/.built
: BITS
=64
130 $(BUILD_DIR
)/$(MACH32
)-%/.installed
: BITS
=32
131 $(BUILD_DIR
)/$(MACH64
)-%/.installed
: BITS
=64
132 $(BUILD_DIR
)/$(MACH32
)-%/.tested
: BITS
=32
133 $(BUILD_DIR
)/$(MACH64
)-%/.tested
: BITS
=64
134 $(BUILD_DIR
)/$(MACH32
)-%/.tested-and-compared
: BITS
=32
135 $(BUILD_DIR
)/$(MACH64
)-%/.tested-and-compared
: BITS
=64
137 PYTHON_32_VERSIONS
= $(filter-out $(PYTHON_64_ONLY_VERSIONS
), $(PYTHON_VERSIONS
))
139 BUILD_32
= $(PYTHON_32_VERSIONS
:%=$(BUILD_DIR
)/$(MACH32
)-%/.built
)
140 BUILD_64
= $(PYTHON_VERSIONS
:%=$(BUILD_DIR
)/$(MACH64
)-%/.built
)
141 BUILD_NO_ARCH
= $(PYTHON_VERSIONS
:%=$(BUILD_DIR
)/$(MACH
)-%/.built
)
143 ifeq ($(filter-out $(PYTHON_64_ONLY_VERSIONS
), $(PYTHON_VERSION
)),)
144 BUILD_32_and_64
= $(BUILD_64
)
147 INSTALL_32
= $(PYTHON_32_VERSIONS
:%=$(BUILD_DIR
)/$(MACH32
)-%/.installed
)
148 INSTALL_64
= $(PYTHON_VERSIONS
:%=$(BUILD_DIR
)/$(MACH64
)-%/.installed
)
149 INSTALL_NO_ARCH
= $(PYTHON_VERSIONS
:%=$(BUILD_DIR
)/$(MACH
)-%/.installed
)
151 PYTHON_ENV
= CC
="$(CC)"
152 PYTHON_ENV
+= CFLAGS
="$(CFLAGS)"
153 PYTHON_ENV
+= CXX
="$(CXX)"
154 PYTHON_ENV
+= CXXFLAGS
="$(CXXFLAGS)"
155 PYTHON_ENV
+= LDFLAGS
="$(LDFLAGS)"
156 PYTHON_ENV
+= PKG_CONFIG_PATH
="$(PKG_CONFIG_PATH)"
158 COMPONENT_BUILD_ENV
+= $(PYTHON_ENV
)
159 COMPONENT_INSTALL_ENV
+= $(PYTHON_ENV
)
160 COMPONENT_TEST_ENV
+= $(PYTHON_ENV
)
162 # Set CARGO_HOME to make sure projects built using rust (for example via
163 # setuptools-rust) do not pollute user's home directory with cargo bits.
164 COMPONENT_BUILD_ENV
+= CARGO_HOME
=$(@D
)/.cargo
166 # Make sure the default Python version is installed last and so is the
167 # canonical version. This is needed for components that keep PYTHON_VERSIONS
168 # set to more than single value, but deliver unversioned binaries in usr/bin or
169 # other overlapping files.
170 define python-order-rule
171 $(BUILD_DIR
)/%-$(PYTHON_VERSION
)/.installed
: $(BUILD_DIR
)/%-$(1)/.installed
173 $(foreach pyver
,$(filter-out $(PYTHON_VERSION
),$(PYTHON_VERSIONS
)),$(eval
$(call python-order-rule
,$(pyver
))))
175 # We need to copy the source dir to avoid its modification by install target
176 # where egg-info is re-generated
177 CLONEY_ARGS
= CLONEY_MODE
="copy"
179 COMPONENT_BUILD_CMD
= $(PYTHON
) setup.py
--no-user-cfg build
$(COMPONENT_BUILD_SETUP_PY_ARGS
)
181 # build the configured source
182 $(BUILD_DIR
)/%/.built
: $(SOURCE_DIR
)/.prep
183 $(RM
) -r
$(@D
) ; $(MKDIR
) $(@D
)
184 $(ENV
) $(CLONEY_ARGS
) $(CLONEY
) $(SOURCE_DIR
) $(@D
)
185 $(COMPONENT_PRE_BUILD_ACTION
)
186 (cd
$(@D
)$(COMPONENT_SUBDIR
:%=/%) ; $(ENV
) $(COMPONENT_BUILD_ENV
) \
187 $(COMPONENT_BUILD_CMD
) $(COMPONENT_BUILD_ARGS
))
188 $(COMPONENT_POST_BUILD_ACTION
)
192 COMPONENT_INSTALL_CMD
= $(PYTHON
) setup.py
--no-user-cfg
install
194 COMPONENT_INSTALL_ARGS
+= --root
$(PROTO_DIR
)
195 COMPONENT_INSTALL_ARGS
+= --install-lib
=$(PYTHON_LIB
)
196 COMPONENT_INSTALL_ARGS
+= --install-data
=$(PYTHON_DATA
)
197 COMPONENT_INSTALL_ARGS
+= --skip-build
198 COMPONENT_INSTALL_ARGS
+= --force
200 # install the built source into a prototype area
201 $(BUILD_DIR
)/%/.installed
: $(BUILD_DIR
)/%/.built
202 $(COMPONENT_PRE_INSTALL_ACTION
)
203 (cd
$(@D
)$(COMPONENT_SUBDIR
:%=/%) ; $(ENV
) $(COMPONENT_INSTALL_ENV
) \
204 $(COMPONENT_INSTALL_CMD
) $(COMPONENT_INSTALL_ARGS
))
205 $(COMPONENT_POST_INSTALL_ACTION
)
208 ifeq ($(strip $(SINGLE_PYTHON_VERSION
)),no
)
209 # Rename binaries in /usr/bin to contain version number
210 COMPONENT_POST_INSTALL_ACTION
+= \
211 for f in
$(PROTOUSRBINDIR
)/* ; do \
212 [ -f
$$f ] || continue
; \
213 for v in
$(PYTHON_VERSIONS
) ; do \
214 [ "$$f" == "$${f%%$$v}" ] || continue
2 ; \
216 $(MV
) $$f $$f-$(PYTHON_VERSION
) ; \
220 # Remove any previous dependency files
221 COMPONENT_POST_INSTALL_ACTION
+= $(RM
) $(@D
)/.depend-runtime
$(@D
)/.depend-test
;
223 # Define Python version specific filenames for tests.
224 ifeq ($(strip $(USE_COMMON_TEST_MASTER
)),no
)
225 COMPONENT_TEST_MASTER
= $(COMPONENT_TEST_RESULTS_DIR
)/results-
$(PYTHON_VERSION
).master
227 COMPONENT_TEST_BUILD_DIR
= $(BUILD_DIR
)/test-
$(PYTHON_VERSION
)
228 COMPONENT_TEST_OUTPUT
= $(COMPONENT_TEST_BUILD_DIR
)/test-
$(PYTHON_VERSION
)-results
229 COMPONENT_TEST_DIFFS
= $(COMPONENT_TEST_BUILD_DIR
)/test-
$(PYTHON_VERSION
)-diffs
230 COMPONENT_TEST_SNAPSHOT
= $(COMPONENT_TEST_BUILD_DIR
)/results-
$(PYTHON_VERSION
).snapshot
231 COMPONENT_TEST_TRANSFORM_CMD
= $(COMPONENT_TEST_BUILD_DIR
)/transform-
$(PYTHON_VERSION
)-results
233 # Generic transforms for Python test results.
234 # See below for test style specific transforms.
235 COMPONENT_TEST_TRANSFORMS
+= "-e 's|$(PYTHON_DIR)|\$$(PYTHON_DIR)|g'"
237 # Testing depends on install target because we want to test installed modules
238 COMPONENT_TEST_DEP
+= $(BUILD_DIR
)/%/.installed
239 # Point Python to the proto area so it is able to find installed modules there
240 COMPONENT_TEST_ENV
+= PYTHONPATH
=$(PROTO_DIR
)/$(PYTHON_LIB
)
241 # Make sure testing is able to find own installed executables (if any)
242 COMPONENT_TEST_ENV
+= PATH
=$(PROTOUSRBINDIR
):$(PATH
)
244 # determine the type of tests we want to run.
245 ifeq ($(strip $(wildcard $(COMPONENT_TEST_RESULTS_DIR
)/results-
*.master
)),)
246 TEST_32
= $(PYTHON_32_VERSIONS
:%=$(BUILD_DIR
)/$(MACH32
)-%/.tested
)
247 TEST_64
= $(PYTHON_VERSIONS
:%=$(BUILD_DIR
)/$(MACH64
)-%/.tested
)
248 TEST_NO_ARCH
= $(PYTHON_VERSIONS
:%=$(BUILD_DIR
)/$(MACH
)-%/.tested
)
250 TEST_32
= $(PYTHON_32_VERSIONS
:%=$(BUILD_DIR
)/$(MACH32
)-%/.tested-and-compared
)
251 TEST_64
= $(PYTHON_VERSIONS
:%=$(BUILD_DIR
)/$(MACH64
)-%/.tested-and-compared
)
252 TEST_NO_ARCH
= $(PYTHON_VERSIONS
:%=$(BUILD_DIR
)/$(MACH
)-%/.tested-and-compared
)
256 # Testing in the Python world is complex. Python projects usually do not
257 # support Makefile with common 'check' or 'test' target to get built bits
260 # De facto standard way to test Python projects these days is tox which is
261 # designed and used primarily for release testing; to make sure the released
262 # python project runs on all supported Python versions, platforms, etc. tox
263 # does so using virtualenv and creates isolated test environments where the
264 # tested package together with all its dependencies is automatically installed
265 # (using pip) and tested. This is great for Python projects developers but it
266 # is hardly usable for operating system distributions like OpenIndiana.
268 # We do not need such release testing. Instead we need something closer to
269 # integration testing: we need to test the built component in our real
270 # environment without automatic installation of any dependencies using pip. In
271 # addition, we need to run tests only for Python versions we actually support
272 # and the component is built for.
274 # To achieve that we do few things. First, to avoid isolated environments
275 # (virtualenv) we run tox with the tox-current-env plugin. Second, to test
276 # only Python versions we are interested in we use -e option for tox to select
277 # single Python version only. Since we run separate test target per Python
278 # version this will make sure we test all needed Python versions.
280 # The tox tool itself uses some other tools under the hood to run tests, for
281 # example pytest. Some projects could even support pytest testing directly
282 # without support for tox. For such projects we offer separate "pytest"-style
285 # For projects that do not support testing using neither tox nor pytest we
286 # offer either unittest or (deprecated) "setup.py test" testing too.
288 # The TEST_STYLE variable is used to select (or force) particular test style
289 # for Python projects. Valid values are:
291 # tox - "tox"-style testing
292 # pytest - "pytest"-style testing
293 # unittest - "unittest"-style testing
294 # setup.py - "setup.py test"-style testing
295 # none - no testing is supported (or desired) at all
299 ifeq ($(strip $(TEST_STYLE
)),tox
)
300 # tox needs PATH environment variable - see https://github.com/tox-dev/tox/issues/2538
301 # We already added it to the test environment - see above
302 COMPONENT_TEST_ENV
+= PYTEST_ADDOPTS
="$(PYTEST_ADDOPTS)"
303 COMPONENT_TEST_ENV
+= NOSE_VERBOSE
=2
304 COMPONENT_TEST_CMD
= $(TOX
)
305 COMPONENT_TEST_ARGS
= --current-env
--no-provision
306 COMPONENT_TEST_ARGS
+= --recreate
307 COMPONENT_TEST_ARGS
+= $(TOX_TESTENV
)
308 COMPONENT_TEST_TARGETS
= $(if
$(strip $(TOX_POSARGS
)),-- $(TOX_POSARGS
))
310 TOX_TESTENV
= -e py
$(subst .
,,$(PYTHON_VERSION
))
312 # Make sure following tools are called indirectly to properly support tox-current-env
313 TOX_CALL_INDIRECTLY
+= py.
test
314 TOX_CALL_INDIRECTLY
+= pytest
315 TOX_CALL_INDIRECTLY
+= coverage
316 TOX_CALL_INDIRECTLY
+= zope-testrunner
317 TOX_CALL_INDIRECTLY.zope-testrunner
= zope.testrunner
318 TOX_CALL_INDIRECTLY
+= sphinx-build
319 TOX_CALL_INDIRECTLY.sphinx-build
= sphinx.cmd.build
320 TOX_CALL_INDIRECTLY
+= nosetests
321 TOX_CALL_INDIRECTLY.nosetests
= nose
322 $(foreach indirectly
, $(TOX_CALL_INDIRECTLY
), $(eval TOX_CALL_INDIRECTLY.
$(indirectly
) ?
= $(indirectly
)))
323 COMPONENT_PRE_TEST_ACTION
+= COMPONENT_TEST_DIR
=$(COMPONENT_TEST_DIR
) ;
324 COMPONENT_PRE_TEST_ACTION
+= \
325 $(foreach indirectly
, $(TOX_CALL_INDIRECTLY
), \
326 [ -f
$$COMPONENT_TEST_DIR/tox.ini
] && \
327 $(GSED
) -i
-e
'/^commands *=/,/^$$/{ \
328 s/^\(\(commands *=\)\{0,1\}[ \t]*\)'$(indirectly
)'\([ \t]\{1,\}.*\)\{0,1\}$$/\1python -m '$(TOX_CALL_INDIRECTLY.
$(indirectly
))'\3/ \
329 }' $$COMPONENT_TEST_DIR/tox.ini
; \
331 COMPONENT_PRE_TEST_ACTION
+= true
;
333 # Normalize tox test results.
334 COMPONENT_TEST_TRANSFORMS
+= "-e 's/py$(subst .,,$(PYTHON_VERSION))/py\$$(PYV)/g'" # normalize PYV
335 COMPONENT_TEST_TRANSFORMS
+= "-e '/^py\$$(PYV) installed:/d'" # depends on set of installed packages
336 COMPONENT_TEST_TRANSFORMS
+= "-e '/PYTHONHASHSEED/d'" # this is random
338 # Normalize zope.testrunner test results
339 COMPONENT_TEST_TRANSFORMS
+= \
340 "-e 's/ in \([0-9]\{1,\} minutes \)\{0,1\}[0-9]\{1,\}\.[0-9]\{3\} seconds//'" # timing
342 # Remove timing for tox 4 test results
343 COMPONENT_TEST_TRANSFORMS
+= "-e 's/^\( py\$$(PYV): OK\) (.* seconds)$$/\1/'"
344 COMPONENT_TEST_TRANSFORMS
+= "-e 's/^\( congratulations :)\) (.* seconds)$$/\1/'"
346 # Remove useless lines from the "coverage combine" output
347 COMPONENT_TEST_TRANSFORMS
+= "-e '/^Combined data file .*\.coverage/d'"
348 COMPONENT_TEST_TRANSFORMS
+= "-e '/^Skipping duplicate data .*\.coverage/d'"
350 # sort list of Sphinx doctest results
351 COMPONENT_TEST_TRANSFORMS
+= \
353 $(GSED) -u -e '/^running tests\.\.\.$$/q' ; \
354 $(GSED) -u -e '/^Doctest summary/Q' \
355 | $(NAWK) '/^$$/{\$$0=\"\\\\n\"}1' ORS='|' \
356 | $(GNU_GREP) -v '^|$$' \
358 | tr -d '\\\\n' | tr '|' '\\\\n' \
359 | $(NAWK) '{print}END{if(NR>0)printf(\"\\\\nDoctest summary\\\\n\")}' ; \
361 ) | $(COMPONENT_TEST_TRANSFORMER)"
363 # tox package together with the tox-current-env plugin is needed
364 USERLAND_TEST_REQUIRED_PACKAGES
+= library
/python
/tox
365 USERLAND_TEST_REQUIRED_PACKAGES
+= library
/python
/tox-current-env
367 # Generate raw lists of test dependencies per Python version
368 # Please note we set PATH below four times for $(COMPONENT_TEST_CMD) (aka tox)
369 # to workaround https://github.com/tox-dev/tox/issues/2538
370 COMPONENT_POST_INSTALL_ACTION
+= \
371 if
[ -x
"$(COMPONENT_TEST_CMD)" ] ; then \
372 cd
$(@D
)$(COMPONENT_SUBDIR
:%=/%) ; \
373 echo
"Testing dependencies:" ; \
374 PATH
=$(PATH
) $(COMPONENT_TEST_CMD
) -qq
--no-provision
--print-deps-to
=- $(TOX_TESTENV
) || exit
1 ; \
375 echo
"Testing extras:" ; \
376 PATH
=$(PATH
) $(COMPONENT_TEST_CMD
) -qq
--no-provision
--print-extras-to
=- $(TOX_TESTENV
) || exit
1 ; \
377 ( PATH
=$(PATH
) $(COMPONENT_TEST_CMD
) -qq
--no-provision
--print-deps-to
=- $(TOX_TESTENV
) \
378 |
$(WS_TOOLS
)/python-resolve-deps \
379 PYTHONPATH
=$(PROTO_DIR
)/$(PYTHON_DIR
)/site-packages
:$(PROTO_DIR
)/$(PYTHON_LIB
) \
380 $(PYTHON
) $(WS_TOOLS
)/python-requires
$(COMPONENT_NAME
) \
381 |
$(PYTHON
) $(WS_TOOLS
)/python-requires
- ; \
382 for e in
$$(PATH
=$(PATH
) $(COMPONENT_TEST_CMD
) -qq
--no-provision
--print-extras-to
=- $(TOX_TESTENV
)) ; do \
383 PYTHONPATH
=$(PROTO_DIR
)/$(PYTHON_DIR
)/site-packages
:$(PROTO_DIR
)/$(PYTHON_LIB
) \
384 $(PYTHON
) $(WS_TOOLS
)/python-requires
$(COMPONENT_NAME
) $$e ; \
385 done
) |
$(GSED
) -e
'/^tox\(-current-env\)\?$$/d' >> $(@D
)/.depend-test
; \
387 else ifeq ($(strip $(TEST_STYLE
)),pytest
)
388 COMPONENT_TEST_CMD
= $(PYTHON
) -m pytest
389 COMPONENT_TEST_ARGS
= $(PYTEST_ADDOPTS
)
390 COMPONENT_TEST_TARGETS
=
392 USERLAND_TEST_REQUIRED_PACKAGES
+= library
/python
/pytest
393 else ifeq ($(strip $(TEST_STYLE
)),unittest
)
394 COMPONENT_TEST_CMD
= $(PYTHON
) -m unittest
395 COMPONENT_TEST_ARGS
=
396 COMPONENT_TEST_ARGS
+= --verbose
397 COMPONENT_TEST_TARGETS
=
398 else ifeq ($(strip $(TEST_STYLE
)),setup.py
)
399 # Old and deprecated "setup.py test"-style testing
400 COMPONENT_TEST_CMD
= $(PYTHON
) setup.py
401 COMPONENT_TEST_ARGS
= --no-user-cfg
402 COMPONENT_TEST_TARGETS
= test
403 else ifeq ($(strip $(TEST_STYLE
)),none
)
404 TEST_TARGET
= $(NO_TESTS
)
407 # Run pytest verbose to get separate line per test in results output
408 PYTEST_ADDOPTS
+= --verbose
410 # Force pytest to not use colored output so the results normalization is unaffected
411 PYTEST_ADDOPTS
+= --color
=no
413 # Create list of required pytest plugins.
415 PYTEST_PLUGINS
+= $$(if
$$(filter library
/python
/$(1)-$$(subst .
,,$$(PYTHON_VERSION
)), $$(REQUIRED_PACKAGES
) $$(TEST_REQUIRED_PACKAGES
) $$(COMPONENT_FMRI
)-$$(subst .
,,$$(PYTHON_VERSION
))),$(2))
417 $(eval
$(call pytest-plugin
,anyio
,anyio
))
418 $(eval
$(call pytest-plugin
,betamax
,pytest-betamax
))
419 $(eval
$(call pytest-plugin
,faker
,faker
))
420 $(eval
$(call pytest-plugin
,flaky
,flaky
))
421 $(eval
$(call pytest-plugin
,hypothesis
,hypothesispytest
))
422 $(eval
$(call pytest-plugin
,jaraco-test
,jaraco.
test.http
))
423 $(eval
$(call pytest-plugin
,kgb
,kgb
))
424 $(eval
$(call pytest-plugin
,pyfakefs
,pytest_fakefs
))
425 $(eval
$(call pytest-plugin
,pytest-asyncio
,asyncio
))
426 $(eval
$(call pytest-plugin
,pytest-benchmark
,benchmark
))
427 $(eval
$(call pytest-plugin
,pytest-black
,black
))
428 $(eval
$(call pytest-plugin
,pytest-check
,check))
429 $(eval
$(call pytest-plugin
,pytest-checkdocs
,checkdocs
))
430 $(eval
$(call pytest-plugin
,pytest-console-scripts
,console-scripts
))
431 $(eval
$(call pytest-plugin
,pytest-cov
,pytest_cov
))
432 $(eval
$(call pytest-plugin
,pytest-custom-exit-code
,custom_exit_code
))
433 $(eval
$(call pytest-plugin
,pytest-datadir
,pytest-datadir
))
434 $(eval
$(call pytest-plugin
,pytest-enabler
,enabler
))
435 $(eval
$(call pytest-plugin
,pytest-env
,env
))
436 $(eval
$(call pytest-plugin
,pytest-expect
,pytest_expect
))
437 $(eval
$(call pytest-plugin
,pytest-flake8
,flake8
))
438 $(eval
$(call pytest-plugin
,pytest-forked
,pytest_forked
))
439 $(eval
$(call pytest-plugin
,pytest-freezer
,freezer
))
440 $(eval
$(call pytest-plugin
,pytest-helpers-namespace
,helpers_namespace
))
441 # https://github.com/jaraco/pytest-home/issues/5
442 $(eval
$(call pytest-plugin
,pytest-home
,pytest_home.fixtures
))
443 $(eval
$(call pytest-plugin
,pytest-httpserver
,pytest_httpserver
))
444 $(eval
$(call pytest-plugin
,pytest-ignore-flaky
,pytest_ignore_flaky
))
445 $(eval
$(call pytest-plugin
,pytest-lazy-fixtures
,pytest_lazyfixture
))
446 $(eval
$(call pytest-plugin
,pytest-metadata
,metadata
))
447 $(eval
$(call pytest-plugin
,pytest-mock
,pytest_mock
))
448 $(eval
$(call pytest-plugin
,pytest-mypy
,mypy
))
449 $(eval
$(call pytest-plugin
,pytest-mypy-plugins
,pytest-mypy-plugins
))
450 $(eval
$(call pytest-plugin
,pytest-perf
,perf
))
451 $(eval
$(call pytest-plugin
,pytest-randomly
,randomly
))
452 $(eval
$(call pytest-plugin
,pytest-regressions
,regressions
))
453 $(eval
$(call pytest-plugin
,pytest-relaxed
,relaxed
))
454 $(eval
$(call pytest-plugin
,pytest-reporter
,reporter
))
455 $(eval
$(call pytest-plugin
,pytest-rerunfailures
,rerunfailures
))
456 $(eval
$(call pytest-plugin
,pytest-salt-factories
,salt-factories
))
457 $(eval
$(call pytest-plugin
,pytest-salt-factories
,salt-factories-event-listener
))
458 $(eval
$(call pytest-plugin
,pytest-salt-factories
,salt-factories-factories
))
459 $(eval
$(call pytest-plugin
,pytest-salt-factories
,salt-factories-loader-mock
))
460 $(eval
$(call pytest-plugin
,pytest-salt-factories
,salt-factories-log-server
))
461 $(eval
$(call pytest-plugin
,pytest-salt-factories
,salt-factories-markers
))
462 $(eval
$(call pytest-plugin
,pytest-salt-factories
,salt-factories-sysinfo
))
463 $(eval
$(call pytest-plugin
,pytest-shell-utilities
,shell-utilities
))
464 $(eval
$(call pytest-plugin
,pytest-skip-markers
,skip-markers
))
465 $(eval
$(call pytest-plugin
,pytest-socket
,socket
))
466 $(eval
$(call pytest-plugin
,pytest-subprocess
,pytest-subprocess
))
467 $(eval
$(call pytest-plugin
,pytest-subtests
,subtests
))
468 $(eval
$(call pytest-plugin
,pytest-system-statistics
,system-statistics
))
469 $(eval
$(call pytest-plugin
,pytest-timeout
,timeout
))
470 $(eval
$(call pytest-plugin
,pytest-travis-fold
,travis-fold
))
471 $(eval
$(call pytest-plugin
,pytest-xdist
,xdist
))
472 $(eval
$(call pytest-plugin
,pytest-xdist
,xdist.looponfail
))
473 $(eval
$(call pytest-plugin
,pytest-xprocess
,xprocess
))
474 $(eval
$(call pytest-plugin
,teamcity-messages
,pytest-teamcity
))
475 $(eval
$(call pytest-plugin
,time-machine
,time_machine
))
476 $(eval
$(call pytest-plugin
,typeguard
,typeguard
))
478 # Transitional (indirect) runtime dependencies of pytest plugins.
480 # Note: The list is not exhaustive and contians only entries that proved to be
483 # pytest-datadir is required by pytest-regressions and pytest-regressions is required by coincidence
484 $(eval
$(call pytest-plugin
,coincidence
,regressions
))
485 $(eval
$(call pytest-plugin
,coincidence
,pytest-datadir
))
487 # By default disable all pytest plugins ...
488 COMPONENT_TEST_ENV
+= PYTEST_DISABLE_PLUGIN_AUTOLOAD
=1
489 # ... and load those in the PYTEST_PLUGINS list only.
490 # $(sort) is used to avoid duplicates and to strip spaces.
491 COMPONENT_TEST_ENV
+= PYTEST_PLUGINS
="$(subst $(space),$(comma),$(sort $(PYTEST_PLUGINS)))"
493 # By default we are not interested in full list of test failures so exit on
494 # first failure to save time. This could be easily overridden from environment
495 # if needed (for example to debug test failures) or in per-component Makefile.
497 PYTEST_ADDOPTS
+= $(PYTEST_FASTFAIL
)
499 # By default we are not interested to see the default long tracebacks.
500 # Detailed tracebacks are shown either for failures or xfails. We aim to see
501 # testing passed so there should be no failures. Since xfails are expected
502 # failures we are not interested in detailed tracebacks here at all since they
503 # could contain random data, like pointers, temporary file names, etc.
504 PYTEST_TRACEBACK
= --tb
=line
505 PYTEST_ADDOPTS
+= $(PYTEST_TRACEBACK
)
507 # Normalize pytest test results. The pytest framework could be used either
508 # directly or via tox or setup.py so add these transforms for all test styles
510 COMPONENT_TEST_TRANSFORMS
+= \
511 "-e 's/^\(platform sunos5 -- Python \)$(shell echo $(PYTHON_VERSION) | $(GSED) -e 's/\./\\./g')\.[0-9]\{1,\}.*\( -- .*\)/\1\$$(PYTHON_VERSION).X\2/'"
512 COMPONENT_TEST_TRANSFORMS
+= "-e '/^plugins: /d'" # order of listed plugins could vary
513 COMPONENT_TEST_TRANSFORMS
+= "-e '/^-\{1,\} coverage: /,/^$$/d'" # remove coverage report
514 COMPONENT_TEST_TRANSFORMS
+= "-e 's/ \{1,\}\[...%\]\$$//'" # drop percentage
515 COMPONENT_TEST_TRANSFORMS
+= \
516 "-e 's/^=\{1,\} \(.*\) in [0-9]\{1,\}\.[0-9]\{1,\}s \(([^)]*) \)\?=\{1,\}$$/======== \1 ========/'" # remove timing
517 # Remove slowest durations report for projects that run pytest with --durations option
518 COMPONENT_TEST_TRANSFORMS
+= "-e '/^=\{1,\} slowest [0-9 ]*durations =\{1,\}$$/,/^=/{/^=/!d}'"
519 # Remove short test summary info for projects that run pytest with -r option
520 COMPONENT_TEST_TRANSFORMS
+= "-e '/^=\{1,\} short test summary info =\{1,\}$$/,/^=/{/^=/!d}'"
522 # Normalize test results produced by pytest-benchmark
523 COMPONENT_TEST_TRANSFORMS
+= \
524 $(if
$(filter library
/python
/pytest-benchmark-
$(subst .
,,$(PYTHON_VERSION
)), $(REQUIRED_PACKAGES
) $(TEST_REQUIRED_PACKAGES
)),"| ( \
525 $(GSED) -e '/^-\{1,\} benchmark/,/^=/{/^=/!d}' \
526 ) | $(COMPONENT_TEST_TRANSFORMER) -e ''")
528 # Normalize test results produced by pytest-randomly
529 USE_PYTEST_RANDOMLY
= $(filter library
/python
/pytest-randomly-
$(subst .
,,$(PYTHON_VERSION
)), $(REQUIRED_PACKAGES
) $(TEST_REQUIRED_PACKAGES
))
530 PYTEST_SORT_TESTS
= $(USE_PYTEST_RANDOMLY
)
531 COMPONENT_TEST_TRANSFORMS
+= $(if
$(strip $(USE_PYTEST_RANDOMLY
)),"-e '/^Using --randomly-seed=[0-9]\{1$(comma)\}\$$/d'")
532 COMPONENT_TEST_TRANSFORMS
+= \
533 $(if
$(strip $(PYTEST_SORT_TESTS
)),"| ( \
534 $(GSED) -u -e '/^=\{1$(comma)\} test session starts /q' ; \
535 $(GSED) -u -e '/^\$$/q' ; \
536 $(GSED) -u -e '/^\$$/Q' | $(SORT) | $(GSED) -e '\$$a\'\$$'\\\n\\\n' ; \
538 ) | $(COMPONENT_TEST_TRANSFORMER) -e ''")
540 # Normalize test results produced by pytest-xdist
541 COMPONENT_TEST_TRANSFORMS
+= \
542 $(if
$(filter library
/python
/pytest-xdist-
$(subst .
,,$(PYTHON_VERSION
)), $(REQUIRED_PACKAGES
) $(TEST_REQUIRED_PACKAGES
)),"| ( \
544 -e '/^created: .* workers$$/d' \
545 -e 's/^[0-9]\{1,\}\( workers \[[0-9]\{1,\} items\]\)$$/X\1/' \
546 -e '/^scheduling tests via /q' ; \
547 $(GSED) -u -e '/^$$/q' ; \
548 $(GSED) -u -n -e '/^\[gw/p' -e '/^$$/Q' | ( $(GSED) \
549 -e 's/^\[gw[0-9]\{1,\}\] \[...%\] //' \
551 -e 's/\([^ ]\{1,\}\) \(.*\)$$/\2 \1/' \
552 | $(SORT) | $(NAWK) '{print}END{if(NR>0)printf(\"\\\\n\")}' ; \
555 ) | $(COMPONENT_TEST_TRANSFORMER) -e ''")
557 # Normalize stestr test results
558 USE_STESTR
= $(filter library
/python
/stestr-
$(subst .
,,$(PYTHON_VERSION
)), $(REQUIRED_PACKAGES
) $(TEST_REQUIRED_PACKAGES
))
559 COMPONENT_TEST_TRANSFORMS
+= \
560 $(if
$(strip $(USE_STESTR
)),"| ( \
561 $(GSED) -e '0,/^{[0-9]\{1,\}}/{//i\'\$$'\\\n{0}\\\n}' \
562 -e 's/^\(Ran: [0-9]\{1,\} tests\{0,1\}\) in .*\$$/\1/' \
563 -e '/^Sum of execute time for each test/d' \
564 -e '/^ - Worker /d' \
566 $(GSED) -u -e '/^{0}\$$/Q' ; \
567 $(GSED) -u -e 's/^{[0-9]\{1,\}} //' \
568 -e 's/\[[.0-9]\{1,\}s\] \.\.\./.../' \
569 -e '/^\$$/Q' | $(SORT) | $(GSED) -e '\$$a\'\$$'\\\n\\\n' ; \
571 ) | $(COMPONENT_TEST_TRANSFORMER) -e ''")
573 # Remove timestamp produced by coincidence
574 USE_COINCIDENCE
= $(filter library
/python
/coincidence-
$(subst .
,,$(PYTHON_VERSION
)), $(REQUIRED_PACKAGES
) $(TEST_REQUIRED_PACKAGES
))
575 COMPONENT_TEST_TRANSFORMS
+= $(if
$(strip $(USE_COINCIDENCE
)),"-e '/^Test session started at/d'")
577 # Normalize setup.py test results. The setup.py testing could be used either
578 # directly or via tox so add these transforms for all test styles
580 COMPONENT_TEST_TRANSFORMS
+= "-e '/SetuptoolsDeprecationWarning:/,+1d'" # depends on Python version and is useless
581 COMPONENT_TEST_TRANSFORMS
+= "-e 's/^\(Ran [0-9]\{1,\} tests\{0,1\}\) in .*$$/\1/'" # delete timing from test results
583 COMPONENT_TEST_DIR
= $(@D
)$(COMPONENT_SUBDIR
:%=/%)
585 # test the built source
586 $(BUILD_DIR
)/%/.tested-and-compared
: $(COMPONENT_TEST_DEP
)
587 $(RM
) -rf
$(COMPONENT_TEST_BUILD_DIR
)
588 $(MKDIR
) $(COMPONENT_TEST_BUILD_DIR
)
589 $(COMPONENT_PRE_TEST_ACTION
)
590 -(cd
$(COMPONENT_TEST_DIR
) ; \
591 $(COMPONENT_TEST_ENV_CMD
) $(COMPONENT_TEST_ENV
) \
592 $(COMPONENT_TEST_CMD
) \
593 $(COMPONENT_TEST_ARGS
) $(COMPONENT_TEST_TARGETS
)) \
594 &> $(COMPONENT_TEST_OUTPUT
)
595 $(COMPONENT_POST_TEST_ACTION
)
596 $(COMPONENT_TEST_CREATE_TRANSFORMS
)
597 $(COMPONENT_TEST_PERFORM_TRANSFORM
)
598 $(COMPONENT_TEST_COMPARE
)
599 $(COMPONENT_TEST_CLEANUP
)
602 $(BUILD_DIR
)/%/.tested
: SHELLOPTS
=pipefail
603 $(BUILD_DIR
)/%/.tested
: $(COMPONENT_TEST_DEP
)
604 $(RM
) -rf
$(COMPONENT_TEST_BUILD_DIR
)
605 $(MKDIR
) $(COMPONENT_TEST_BUILD_DIR
)
606 $(COMPONENT_PRE_TEST_ACTION
)
607 (cd
$(COMPONENT_TEST_DIR
) ; \
608 $(COMPONENT_TEST_ENV_CMD
) $(COMPONENT_TEST_ENV
) \
609 $(COMPONENT_TEST_CMD
) \
610 $(COMPONENT_TEST_ARGS
) $(COMPONENT_TEST_TARGETS
)) \
611 |
& $(TEE
) $(COMPONENT_TEST_OUTPUT
)
612 $(COMPONENT_POST_TEST_ACTION
)
613 $(COMPONENT_TEST_CREATE_TRANSFORMS
)
614 $(COMPONENT_TEST_PERFORM_TRANSFORM
)
615 $(COMPONENT_TEST_CLEANUP
)
618 ifeq ($(strip $(SINGLE_PYTHON_VERSION
)),no
)
619 # Temporarily create symlinks for renamed binaries
620 COMPONENT_PRE_TEST_ACTION
+= \
621 for f in
$(PROTOUSRBINDIR
)/*-$(PYTHON_VERSION
) ; do \
622 [ -f
$$f ] || continue
; \
623 [ -L
$${f
%%-$(PYTHON_VERSION
)} ] && $(RM
) $${f
%%-$(PYTHON_VERSION
)} ; \
624 [ -e
$${f
%%-$(PYTHON_VERSION
)} ] && continue
; \
625 $(SYMLINK
) $$(basename $$f) $${f
%%-$(PYTHON_VERSION
)} ; \
628 # Cleanup of temporary symlinks
629 COMPONENT_POST_TEST_ACTION
+= \
630 for f in
$(PROTOUSRBINDIR
)/*-$(PYTHON_VERSION
) ; do \
631 [ -f
$$f ] || continue
; \
632 [ ! -L
$${f
%%-$(PYTHON_VERSION
)} ] ||
$(RM
) $${f
%%-$(PYTHON_VERSION
)} ; \
637 ifeq ($(strip $(SINGLE_PYTHON_VERSION
)),no
)
638 # We need to add -$(PYV) to package fmri
639 GENERATE_EXTRA_CMD
+= | \
640 $(GSED
) -e
's/^\(set name=pkg.fmri [^@]*\)\(.*\)$$/\1-$$(PYV)\2/'
643 # Add runtime dependencies from project metadata to generated manifest
644 GENERATE_EXTRA_DEPS
+= $(BUILD_DIR
)/META.depend-runtime.res
645 GENERATE_EXTRA_CMD
+= | \
648 echo
"\# python modules are unusable without python runtime binary" ; \
649 echo
"depend type=require fmri=__TBD pkg.debug.depend.file=python\$$(PYVER) \\" ; \
650 echo
" pkg.debug.depend.path=usr/bin" ; \
652 echo
"\# Automatically generated dependencies based on distribution metadata" ; \
653 $(CAT
) $(BUILD_DIR
)/META.depend-runtime.res \
656 # Add runtime dependencies from project metadata to REQUIRED_PACKAGES
657 REQUIRED_PACKAGES_RESOLVED
+= $(BUILD_DIR
)/META.depend-runtime.res
660 # Generate raw lists of runtime dependencies per Python version
661 COMPONENT_POST_INSTALL_ACTION
+= \
662 PYTHONPATH
=$(PROTO_DIR
)/$(PYTHON_DIR
)/site-packages
:$(PROTO_DIR
)/$(PYTHON_LIB
) \
663 $(PYTHON
) $(WS_TOOLS
)/python-requires
$(COMPONENT_NAME
) >> $(@D
)/.depend-runtime
;
665 # Convert raw per version lists of runtime dependencies to single resolved
666 # runtime dependency list. The dependency on META.depend-test.required here is
667 # purely to get the file created as a side effect of this target.
668 $(BUILD_DIR
)/META.depend-runtime.res
: $(INSTALL_
$(MK_BITS
)) $(BUILD_DIR
)/META.depend-test.required
669 $(CAT
) $(INSTALL_
$(MK_BITS
):%.installed
=%.depend-runtime
) |
$(SORT
) -u \
670 |
$(GSED
) -e
's/.*/depend type=require fmri=pkg:\/library\/python\/&-$$(PYV)/' > $@
672 # Generate raw lists of test dependencies per Python version
673 COMPONENT_POST_INSTALL_ACTION
+= \
674 cd
$(@D
)$(COMPONENT_SUBDIR
:%=/%) ; \
675 ( for f in
$(TEST_REQUIREMENTS
) ; do \
676 $(CAT
) $$f |
$(DOS2UNIX
) -ascii
; \
678 for e in
$(TEST_REQUIREMENTS_EXTRAS
) ; do \
679 PYTHONPATH
=$(PROTO_DIR
)/$(PYTHON_DIR
)/site-packages
:$(PROTO_DIR
)/$(PYTHON_LIB
) \
680 $(PYTHON
) $(WS_TOOLS
)/python-requires
$(COMPONENT_NAME
) $$e ; \
681 done
) |
$(WS_TOOLS
)/python-resolve-deps \
682 PYTHONPATH
=$(PROTO_DIR
)/$(PYTHON_DIR
)/site-packages
:$(PROTO_DIR
)/$(PYTHON_LIB
) \
683 $(PYTHON
) $(WS_TOOLS
)/python-requires
$(COMPONENT_NAME
) \
684 |
$(PYTHON
) $(WS_TOOLS
)/python-requires
- >> $(@D
)/.depend-test
;
686 # Convert raw per version lists of test dependencies to single list of
687 # TEST_REQUIRED_PACKAGES entries. Some Python projects lists their own project
688 # as a test dependency so filter this out here too.
689 $(BUILD_DIR
)/META.depend-test.required
: $(INSTALL_
$(MK_BITS
))
690 $(CAT
) $(INSTALL_
$(MK_BITS
):%.installed
=%.depend-test
) |
$(SORT
) -u \
691 |
$(GSED
) -e
's/.*/TEST_REQUIRED_PACKAGES.python += library\/python\/&/' \
692 |
( $(GNU_GREP
) -v
' $(COMPONENT_FMRI)$$' || true
) \
695 # Add META.depend-test.required to the generated list of REQUIRED_PACKAGES
696 REQUIRED_PACKAGES_TRANSFORM
+= -e
'$$r $(BUILD_DIR)/META.depend-test.required'
698 # The python-requires script requires packaging to provide useful output but
699 # packaging might be unavailable during bootstrap until we reach bootstrap
700 # checkpoint 2. So require it conditionally.
701 ifeq ($(filter $(strip $(COMPONENT_NAME
)),$(PYTHON_BOOTSTRAP_CHECKPOINT_2
)),)
702 USERLAND_REQUIRED_PACKAGES.python
+= library
/python
/packaging
707 $(RM
) -r
$(SOURCE_DIR
) $(BUILD_DIR
)
709 # Make it easy to construct a URL for a pypi source download.
710 pypi_url_multi
= pypi
:///$(COMPONENT_NAME_
$(1))==$(COMPONENT_VERSION_
$(1))
711 pypi_url_single
= pypi
:///$(COMPONENT_NAME
)==$(COMPONENT_VERSION
)
712 pypi_url
= $(if
$(COMPONENT_NAME_
$(1)),$(pypi_url_multi
),$(pypi_url_single
))