python-utils-r1.eclass (41926B)
1 # Copyright 1999-2022 Gentoo Authors 2 # Distributed under the terms of the GNU General Public License v2 3 4 # @ECLASS: python-utils-r1.eclass 5 # @MAINTAINER: 6 # Python team <python@gentoo.org> 7 # @AUTHOR: 8 # Author: Michał Górny <mgorny@gentoo.org> 9 # Based on work of: Krzysztof Pawlik <nelchael@gentoo.org> 10 # @SUPPORTED_EAPIS: 6 7 8 11 # @BLURB: Utility functions for packages with Python parts. 12 # @DESCRIPTION: 13 # A utility eclass providing functions to query Python implementations, 14 # install Python modules and scripts. 15 # 16 # This eclass does not set any metadata variables nor export any phase 17 # functions. It can be inherited safely. 18 # 19 # For more information, please see the Python Guide: 20 # https://projects.gentoo.org/python/guide/ 21 22 # NOTE: When dropping support for EAPIs here, we need to update 23 # metadata/install-qa-check.d/60python-pyc 24 # See bug #704286, bug #781878 25 case "${EAPI:-0}" in 26 [0-5]) die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}" ;; 27 [6-8]) ;; 28 *) die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" ;; 29 esac 30 31 if [[ ${_PYTHON_ECLASS_INHERITED} ]]; then 32 die 'python-r1 suite eclasses can not be used with python.eclass.' 33 fi 34 35 if [[ ! ${_PYTHON_UTILS_R1} ]]; then 36 37 [[ ${EAPI} == [67] ]] && inherit eapi8-dosym 38 [[ ${EAPI} == 6 ]] && inherit eqawarn 39 inherit multiprocessing toolchain-funcs 40 41 # @ECLASS_VARIABLE: _PYTHON_ALL_IMPLS 42 # @INTERNAL 43 # @DESCRIPTION: 44 # All supported Python implementations, most preferred last. 45 _PYTHON_ALL_IMPLS=( 46 pypy3 47 python3_{8..11} 48 ) 49 readonly _PYTHON_ALL_IMPLS 50 51 # @ECLASS_VARIABLE: _PYTHON_HISTORICAL_IMPLS 52 # @INTERNAL 53 # @DESCRIPTION: 54 # All historical Python implementations that are no longer supported. 55 _PYTHON_HISTORICAL_IMPLS=( 56 jython2_7 57 pypy pypy1_{8,9} pypy2_0 58 python2_{5..7} 59 python3_{1..7} 60 ) 61 readonly _PYTHON_HISTORICAL_IMPLS 62 63 # @ECLASS_VARIABLE: PYTHON_COMPAT_NO_STRICT 64 # @INTERNAL 65 # @DESCRIPTION: 66 # Set to a non-empty value in order to make eclass tolerate (ignore) 67 # unknown implementations in PYTHON_COMPAT. 68 # 69 # This is intended to be set by the user when using ebuilds that may 70 # have unknown (newer) implementations in PYTHON_COMPAT. The assumption 71 # is that the ebuilds are intended to be used within multiple contexts 72 # which can involve revisions of this eclass that support a different 73 # set of Python implementations. 74 75 # @FUNCTION: _python_verify_patterns 76 # @USAGE: <pattern>... 77 # @INTERNAL 78 # @DESCRIPTION: 79 # Verify whether the patterns passed to the eclass function are correct 80 # (i.e. can match any valid implementation). Dies on wrong pattern. 81 _python_verify_patterns() { 82 debug-print-function ${FUNCNAME} "${@}" 83 84 local impl pattern 85 for pattern; do 86 case ${pattern} in 87 -[23]|3.[89]|3.1[01]) 88 continue 89 ;; 90 esac 91 92 for impl in "${_PYTHON_ALL_IMPLS[@]}" "${_PYTHON_HISTORICAL_IMPLS[@]}" 93 do 94 [[ ${impl} == ${pattern/./_} ]] && continue 2 95 done 96 97 die "Invalid implementation pattern: ${pattern}" 98 done 99 } 100 101 # @FUNCTION: _python_set_impls 102 # @INTERNAL 103 # @DESCRIPTION: 104 # Check PYTHON_COMPAT for well-formedness and validity, then set 105 # two global variables: 106 # 107 # - _PYTHON_SUPPORTED_IMPLS containing valid implementations supported 108 # by the ebuild (PYTHON_COMPAT - dead implementations), 109 # 110 # - and _PYTHON_UNSUPPORTED_IMPLS containing valid implementations that 111 # are not supported by the ebuild. 112 # 113 # Implementations in both variables are ordered using the pre-defined 114 # eclass implementation ordering. 115 # 116 # This function must be called once in global scope by an eclass 117 # utilizing PYTHON_COMPAT. 118 _python_set_impls() { 119 local i 120 121 if ! declare -p PYTHON_COMPAT &>/dev/null; then 122 die 'PYTHON_COMPAT not declared.' 123 fi 124 if [[ $(declare -p PYTHON_COMPAT) != "declare -a"* ]]; then 125 die 'PYTHON_COMPAT must be an array.' 126 fi 127 128 local obsolete=() 129 if [[ ! ${PYTHON_COMPAT_NO_STRICT} ]]; then 130 for i in "${PYTHON_COMPAT[@]}"; do 131 # check for incorrect implementations 132 # we're using pattern matching as an optimization 133 # please keep them in sync with _PYTHON_ALL_IMPLS 134 # and _PYTHON_HISTORICAL_IMPLS 135 case ${i} in 136 pypy3|python2_7|python3_[89]|python3_1[01]) 137 ;; 138 jython2_7|pypy|pypy1_[89]|pypy2_0|python2_[5-6]|python3_[1-7]) 139 obsolete+=( "${i}" ) 140 ;; 141 *) 142 if has "${i}" "${_PYTHON_ALL_IMPLS[@]}" \ 143 "${_PYTHON_HISTORICAL_IMPLS[@]}" 144 then 145 die "Mis-synced patterns in _python_set_impls: missing ${i}" 146 else 147 die "Invalid implementation in PYTHON_COMPAT: ${i}" 148 fi 149 esac 150 done 151 fi 152 153 if [[ -n ${obsolete[@]} && ${EBUILD_PHASE} == setup ]]; then 154 # complain if people don't clean up old impls while touching 155 # the ebuilds recently. use the copyright year to infer last 156 # modification 157 # NB: this check doesn't have to work reliably 158 if [[ $(head -n 1 "${EBUILD}" 2>/dev/null) == *2022* ]]; then 159 eqawarn "Please clean PYTHON_COMPAT of obsolete implementations:" 160 eqawarn " ${obsolete[*]}" 161 fi 162 fi 163 164 local supp=() unsupp=() 165 166 for i in "${_PYTHON_ALL_IMPLS[@]}"; do 167 if has "${i}" "${PYTHON_COMPAT[@]}"; then 168 supp+=( "${i}" ) 169 else 170 unsupp+=( "${i}" ) 171 fi 172 done 173 174 if [[ ! ${supp[@]} ]]; then 175 # special-case python2_7 for python-any-r1 176 if [[ ${_PYTHON_ALLOW_PY27} ]] && has python2_7 "${PYTHON_COMPAT[@]}" 177 then 178 supp+=( python2_7 ) 179 else 180 die "No supported implementation in PYTHON_COMPAT." 181 fi 182 fi 183 184 if [[ ${_PYTHON_SUPPORTED_IMPLS[@]} ]]; then 185 # set once already, verify integrity 186 if [[ ${_PYTHON_SUPPORTED_IMPLS[@]} != ${supp[@]} ]]; then 187 eerror "Supported impls (PYTHON_COMPAT) changed between inherits!" 188 eerror "Before: ${_PYTHON_SUPPORTED_IMPLS[*]}" 189 eerror "Now : ${supp[*]}" 190 die "_PYTHON_SUPPORTED_IMPLS integrity check failed" 191 fi 192 if [[ ${_PYTHON_UNSUPPORTED_IMPLS[@]} != ${unsupp[@]} ]]; then 193 eerror "Unsupported impls changed between inherits!" 194 eerror "Before: ${_PYTHON_UNSUPPORTED_IMPLS[*]}" 195 eerror "Now : ${unsupp[*]}" 196 die "_PYTHON_UNSUPPORTED_IMPLS integrity check failed" 197 fi 198 else 199 _PYTHON_SUPPORTED_IMPLS=( "${supp[@]}" ) 200 _PYTHON_UNSUPPORTED_IMPLS=( "${unsupp[@]}" ) 201 readonly _PYTHON_SUPPORTED_IMPLS _PYTHON_UNSUPPORTED_IMPLS 202 fi 203 } 204 205 # @FUNCTION: _python_impl_matches 206 # @USAGE: <impl> [<pattern>...] 207 # @INTERNAL 208 # @DESCRIPTION: 209 # Check whether the specified <impl> matches at least one 210 # of the patterns following it. Return 0 if it does, 1 otherwise. 211 # Matches if no patterns are provided. 212 # 213 # <impl> can be in PYTHON_COMPAT or EPYTHON form. The patterns 214 # can either be fnmatch-style or stdlib versions, e.g. "3.8", "3.9". 215 # In the latter case, pypy3 will match if there is at least one pypy3 216 # version matching the stdlib version. 217 _python_impl_matches() { 218 [[ ${#} -ge 1 ]] || die "${FUNCNAME}: takes at least 1 parameter" 219 [[ ${#} -eq 1 ]] && return 0 220 221 local impl=${1/./_} pattern 222 shift 223 224 for pattern; do 225 case ${pattern} in 226 -2|python2*|pypy) 227 if [[ ${EAPI} != [67] ]]; then 228 eerror 229 eerror "Python 2 is no longer supported in Gentoo, please remove Python 2" 230 eerror "${FUNCNAME[1]} calls." 231 die "Passing ${pattern} to ${FUNCNAME[1]} is banned in EAPI ${EAPI}" 232 fi 233 ;; 234 -3) 235 # NB: "python3*" is fine, as "not pypy3" 236 if [[ ${EAPI} != [67] ]]; then 237 eerror 238 eerror "Python 2 is no longer supported in Gentoo, please remove Python 2" 239 eerror "${FUNCNAME[1]} calls." 240 die "Passing ${pattern} to ${FUNCNAME[1]} is banned in EAPI ${EAPI}" 241 fi 242 return 0 243 ;; 244 3.9) 245 # the only unmasked pypy3 version is pypy3.9 atm 246 [[ ${impl} == python${pattern/./_} || ${impl} == pypy3 ]] && 247 return 0 248 ;; 249 3.8|3.1[01]) 250 [[ ${impl} == python${pattern/./_} ]] && return 0 251 ;; 252 *) 253 # unify value style to allow lax matching 254 [[ ${impl} == ${pattern/./_} ]] && return 0 255 ;; 256 esac 257 done 258 259 return 1 260 } 261 262 # @ECLASS_VARIABLE: PYTHON 263 # @DEFAULT_UNSET 264 # @DESCRIPTION: 265 # The absolute path to the current Python interpreter. 266 # 267 # This variable is set automatically in the following contexts: 268 # 269 # python-r1: Set in functions called by python_foreach_impl() or after 270 # calling python_setup(). 271 # 272 # python-single-r1: Set after calling python-single-r1_pkg_setup(). 273 # 274 # distutils-r1: Set within any of the python sub-phase functions. 275 # 276 # Example value: 277 # @CODE 278 # /usr/bin/python2.7 279 # @CODE 280 281 # @ECLASS_VARIABLE: EPYTHON 282 # @DEFAULT_UNSET 283 # @DESCRIPTION: 284 # The executable name of the current Python interpreter. 285 # 286 # This variable is set automatically in the following contexts: 287 # 288 # python-r1: Set in functions called by python_foreach_impl() or after 289 # calling python_setup(). 290 # 291 # python-single-r1: Set after calling python-single-r1_pkg_setup(). 292 # 293 # distutils-r1: Set within any of the python sub-phase functions. 294 # 295 # Example value: 296 # @CODE 297 # python2.7 298 # @CODE 299 300 # @FUNCTION: _python_export 301 # @USAGE: [<impl>] <variables>... 302 # @INTERNAL 303 # @DESCRIPTION: 304 # Set and export the Python implementation-relevant variables passed 305 # as parameters. 306 # 307 # The optional first parameter may specify the requested Python 308 # implementation (either as PYTHON_TARGETS value, e.g. python2_7, 309 # or an EPYTHON one, e.g. python2.7). If no implementation passed, 310 # the current one will be obtained from ${EPYTHON}. 311 # 312 # The variables which can be exported are: PYTHON, EPYTHON, 313 # PYTHON_SITEDIR. They are described more completely in the eclass 314 # variable documentation. 315 _python_export() { 316 debug-print-function ${FUNCNAME} "${@}" 317 318 local impl var 319 320 case "${1}" in 321 python*|jython*) 322 impl=${1/_/.} 323 shift 324 ;; 325 pypy|pypy3) 326 impl=${1} 327 shift 328 ;; 329 *) 330 impl=${EPYTHON} 331 if [[ -z ${impl} ]]; then 332 die "_python_export called without a python implementation and EPYTHON is unset" 333 fi 334 ;; 335 esac 336 debug-print "${FUNCNAME}: implementation: ${impl}" 337 338 for var; do 339 case "${var}" in 340 EPYTHON) 341 export EPYTHON=${impl} 342 debug-print "${FUNCNAME}: EPYTHON = ${EPYTHON}" 343 ;; 344 PYTHON) 345 export PYTHON=${EPREFIX}/usr/bin/${impl} 346 debug-print "${FUNCNAME}: PYTHON = ${PYTHON}" 347 ;; 348 PYTHON_SITEDIR) 349 [[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it" 350 PYTHON_SITEDIR=$( 351 "${PYTHON}" - <<-EOF || die 352 import sysconfig 353 print(sysconfig.get_path("purelib")) 354 EOF 355 ) 356 export PYTHON_SITEDIR 357 debug-print "${FUNCNAME}: PYTHON_SITEDIR = ${PYTHON_SITEDIR}" 358 ;; 359 PYTHON_INCLUDEDIR) 360 [[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it" 361 PYTHON_INCLUDEDIR=$( 362 "${PYTHON}" - <<-EOF || die 363 import sysconfig 364 print(sysconfig.get_path("platinclude")) 365 EOF 366 ) 367 export PYTHON_INCLUDEDIR 368 debug-print "${FUNCNAME}: PYTHON_INCLUDEDIR = ${PYTHON_INCLUDEDIR}" 369 370 # Jython gives a non-existing directory 371 if [[ ! -d ${PYTHON_INCLUDEDIR} ]]; then 372 die "${impl} does not install any header files!" 373 fi 374 ;; 375 PYTHON_LIBPATH) 376 [[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it" 377 PYTHON_LIBPATH=$( 378 "${PYTHON}" - <<-EOF || die 379 import os.path, sysconfig 380 print( 381 os.path.join( 382 sysconfig.get_config_var("LIBDIR"), 383 sysconfig.get_config_var("LDLIBRARY")) 384 if sysconfig.get_config_var("LDLIBRARY") 385 else "") 386 EOF 387 ) 388 export PYTHON_LIBPATH 389 debug-print "${FUNCNAME}: PYTHON_LIBPATH = ${PYTHON_LIBPATH}" 390 391 if [[ ! ${PYTHON_LIBPATH} ]]; then 392 die "${impl} lacks a (usable) dynamic library" 393 fi 394 ;; 395 PYTHON_CFLAGS) 396 local val 397 398 case "${impl}" in 399 python*) 400 # python-2.7, python-3.2, etc. 401 val=$($(tc-getPKG_CONFIG) --cflags ${impl/n/n-}) || die 402 ;; 403 *) 404 die "${impl}: obtaining ${var} not supported" 405 ;; 406 esac 407 408 export PYTHON_CFLAGS=${val} 409 debug-print "${FUNCNAME}: PYTHON_CFLAGS = ${PYTHON_CFLAGS}" 410 ;; 411 PYTHON_LIBS) 412 local val 413 414 case "${impl}" in 415 python2*|python3.6|python3.7*) 416 # python* up to 3.7 417 val=$($(tc-getPKG_CONFIG) --libs ${impl/n/n-}) || die 418 ;; 419 python*) 420 # python3.8+ 421 val=$($(tc-getPKG_CONFIG) --libs ${impl/n/n-}-embed) || die 422 ;; 423 *) 424 die "${impl}: obtaining ${var} not supported" 425 ;; 426 esac 427 428 export PYTHON_LIBS=${val} 429 debug-print "${FUNCNAME}: PYTHON_LIBS = ${PYTHON_LIBS}" 430 ;; 431 PYTHON_CONFIG) 432 local flags val 433 434 case "${impl}" in 435 python*) 436 [[ -n ${PYTHON} ]] || die "PYTHON needs to be set for ${var} to be exported, or requested before it" 437 flags=$( 438 "${PYTHON}" - <<-EOF || die 439 import sysconfig 440 print(sysconfig.get_config_var("ABIFLAGS") 441 or "") 442 EOF 443 ) 444 val=${PYTHON}${flags}-config 445 ;; 446 *) 447 die "${impl}: obtaining ${var} not supported" 448 ;; 449 esac 450 451 export PYTHON_CONFIG=${val} 452 debug-print "${FUNCNAME}: PYTHON_CONFIG = ${PYTHON_CONFIG}" 453 ;; 454 PYTHON_PKG_DEP) 455 local d 456 case ${impl} in 457 python2.7) 458 PYTHON_PKG_DEP='>=dev-lang/python-2.7.10_p16:2.7';; 459 python3.8) 460 PYTHON_PKG_DEP=">=dev-lang/python-3.8.15_p3:3.8";; 461 python3.9) 462 PYTHON_PKG_DEP=">=dev-lang/python-3.9.15_p3:3.9";; 463 python3.10) 464 PYTHON_PKG_DEP=">=dev-lang/python-3.10.8_p3:3.10";; 465 python3.11) 466 PYTHON_PKG_DEP=">=dev-lang/python-3.11.0_p2:3.11";; 467 python*) 468 PYTHON_PKG_DEP="dev-lang/python:${impl#python}";; 469 pypy) 470 PYTHON_PKG_DEP='>=dev-python/pypy-7.3.9-r2:0=';; 471 pypy3) 472 PYTHON_PKG_DEP='>=dev-python/pypy3-7.3.9_p9:0=';; 473 *) 474 die "Invalid implementation: ${impl}" 475 esac 476 477 # use-dep 478 if [[ ${PYTHON_REQ_USE} ]]; then 479 PYTHON_PKG_DEP+=[${PYTHON_REQ_USE}] 480 fi 481 482 export PYTHON_PKG_DEP 483 debug-print "${FUNCNAME}: PYTHON_PKG_DEP = ${PYTHON_PKG_DEP}" 484 ;; 485 PYTHON_SCRIPTDIR) 486 local dir 487 export PYTHON_SCRIPTDIR=${EPREFIX}/usr/lib/python-exec/${impl} 488 debug-print "${FUNCNAME}: PYTHON_SCRIPTDIR = ${PYTHON_SCRIPTDIR}" 489 ;; 490 *) 491 die "_python_export: unknown variable ${var}" 492 esac 493 done 494 } 495 496 # @FUNCTION: python_get_sitedir 497 # @USAGE: [<impl>] 498 # @DESCRIPTION: 499 # Obtain and print the 'site-packages' path for the given 500 # implementation. If no implementation is provided, ${EPYTHON} will 501 # be used. 502 python_get_sitedir() { 503 debug-print-function ${FUNCNAME} "${@}" 504 505 _python_export "${@}" PYTHON_SITEDIR 506 echo "${PYTHON_SITEDIR}" 507 } 508 509 # @FUNCTION: python_get_includedir 510 # @USAGE: [<impl>] 511 # @DESCRIPTION: 512 # Obtain and print the include path for the given implementation. If no 513 # implementation is provided, ${EPYTHON} will be used. 514 python_get_includedir() { 515 debug-print-function ${FUNCNAME} "${@}" 516 517 _python_export "${@}" PYTHON_INCLUDEDIR 518 echo "${PYTHON_INCLUDEDIR}" 519 } 520 521 # @FUNCTION: python_get_library_path 522 # @USAGE: [<impl>] 523 # @DESCRIPTION: 524 # Obtain and print the Python library path for the given implementation. 525 # If no implementation is provided, ${EPYTHON} will be used. 526 # 527 # Please note that this function can be used with CPython only. Use 528 # in another implementation will result in a fatal failure. 529 python_get_library_path() { 530 debug-print-function ${FUNCNAME} "${@}" 531 532 _python_export "${@}" PYTHON_LIBPATH 533 echo "${PYTHON_LIBPATH}" 534 } 535 536 # @FUNCTION: python_get_CFLAGS 537 # @USAGE: [<impl>] 538 # @DESCRIPTION: 539 # Obtain and print the compiler flags for building against Python, 540 # for the given implementation. If no implementation is provided, 541 # ${EPYTHON} will be used. 542 # 543 # Please note that this function can be used with CPython only. 544 # It requires Python and pkg-config installed, and therefore proper 545 # build-time dependencies need be added to the ebuild. 546 python_get_CFLAGS() { 547 debug-print-function ${FUNCNAME} "${@}" 548 549 _python_export "${@}" PYTHON_CFLAGS 550 echo "${PYTHON_CFLAGS}" 551 } 552 553 # @FUNCTION: python_get_LIBS 554 # @USAGE: [<impl>] 555 # @DESCRIPTION: 556 # Obtain and print the compiler flags for linking against Python, 557 # for the given implementation. If no implementation is provided, 558 # ${EPYTHON} will be used. 559 # 560 # Please note that this function can be used with CPython only. 561 # It requires Python and pkg-config installed, and therefore proper 562 # build-time dependencies need be added to the ebuild. 563 python_get_LIBS() { 564 debug-print-function ${FUNCNAME} "${@}" 565 566 _python_export "${@}" PYTHON_LIBS 567 echo "${PYTHON_LIBS}" 568 } 569 570 # @FUNCTION: python_get_PYTHON_CONFIG 571 # @USAGE: [<impl>] 572 # @DESCRIPTION: 573 # Obtain and print the PYTHON_CONFIG location for the given 574 # implementation. If no implementation is provided, ${EPYTHON} will be 575 # used. 576 # 577 # Please note that this function can be used with CPython only. 578 # It requires Python installed, and therefore proper build-time 579 # dependencies need be added to the ebuild. 580 python_get_PYTHON_CONFIG() { 581 debug-print-function ${FUNCNAME} "${@}" 582 583 _python_export "${@}" PYTHON_CONFIG 584 echo "${PYTHON_CONFIG}" 585 } 586 587 # @FUNCTION: python_get_scriptdir 588 # @USAGE: [<impl>] 589 # @DESCRIPTION: 590 # Obtain and print the script install path for the given 591 # implementation. If no implementation is provided, ${EPYTHON} will 592 # be used. 593 python_get_scriptdir() { 594 debug-print-function ${FUNCNAME} "${@}" 595 596 _python_export "${@}" PYTHON_SCRIPTDIR 597 echo "${PYTHON_SCRIPTDIR}" 598 } 599 600 # @FUNCTION: python_optimize 601 # @USAGE: [<directory>...] 602 # @DESCRIPTION: 603 # Compile and optimize Python modules in specified directories (absolute 604 # paths). If no directories are provided, the default system paths 605 # are used (prepended with ${D}). 606 python_optimize() { 607 debug-print-function ${FUNCNAME} "${@}" 608 609 [[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).' 610 611 local PYTHON=${PYTHON} 612 [[ ${PYTHON} ]] || _python_export PYTHON 613 [[ -x ${PYTHON} ]] || die "PYTHON (${PYTHON}) is not executable" 614 615 # default to sys.path 616 if [[ ${#} -eq 0 ]]; then 617 local f 618 while IFS= read -r -d '' f; do 619 # 1) accept only absolute paths 620 # (i.e. skip '', '.' or anything like that) 621 # 2) skip paths which do not exist 622 # (python2.6 complains about them verbosely) 623 624 if [[ ${f} == /* && -d ${D%/}${f} ]]; then 625 set -- "${D%/}${f}" "${@}" 626 fi 627 done < <( 628 "${PYTHON}" - <<-EOF || die 629 import sys 630 print("".join(x + "\0" for x in sys.path)) 631 EOF 632 ) 633 634 debug-print "${FUNCNAME}: using sys.path: ${*/%/;}" 635 fi 636 637 local jobs=$(makeopts_jobs) 638 local d 639 for d; do 640 # make sure to get a nice path without // 641 local instpath=${d#${D%/}} 642 instpath=/${instpath##/} 643 644 einfo "Optimize Python modules for ${instpath}" 645 case "${EPYTHON}" in 646 python2.7|python3.[34]) 647 "${PYTHON}" -m compileall -q -f -d "${instpath}" "${d}" 648 "${PYTHON}" -OO -m compileall -q -f -d "${instpath}" "${d}" 649 ;; 650 python3.[5678]|pypy3) 651 # both levels of optimization are separate since 3.5 652 "${PYTHON}" -m compileall -j "${jobs}" -q -f -d "${instpath}" "${d}" 653 "${PYTHON}" -O -m compileall -j "${jobs}" -q -f -d "${instpath}" "${d}" 654 "${PYTHON}" -OO -m compileall -j "${jobs}" -q -f -d "${instpath}" "${d}" 655 ;; 656 python*) 657 "${PYTHON}" -m compileall -j "${jobs}" -o 0 -o 1 -o 2 --hardlink-dupes -q -f -d "${instpath}" "${d}" 658 ;; 659 *) 660 "${PYTHON}" -m compileall -q -f -d "${instpath}" "${d}" 661 ;; 662 esac 663 done 664 } 665 666 # @FUNCTION: python_scriptinto 667 # @USAGE: <new-path> 668 # @DESCRIPTION: 669 # Set the directory to which files passed to python_doexe(), 670 # python_doscript(), python_newexe() and python_newscript() 671 # are going to be installed. The new value needs to be relative 672 # to the installation root (${ED}). 673 # 674 # If not set explicitly, the directory defaults to /usr/bin. 675 # 676 # Example: 677 # @CODE 678 # src_install() { 679 # python_scriptinto /usr/sbin 680 # python_foreach_impl python_doscript foo 681 # } 682 # @CODE 683 python_scriptinto() { 684 debug-print-function ${FUNCNAME} "${@}" 685 686 _PYTHON_SCRIPTROOT=${1} 687 } 688 689 # @FUNCTION: python_doexe 690 # @USAGE: <files>... 691 # @DESCRIPTION: 692 # Install the given executables into the executable install directory, 693 # for the current Python implementation (${EPYTHON}). 694 # 695 # The executable will be wrapped properly for the Python implementation, 696 # though no shebang mangling will be performed. 697 python_doexe() { 698 debug-print-function ${FUNCNAME} "${@}" 699 700 [[ ${EBUILD_PHASE} != install ]] && 701 die "${FUNCNAME} can only be used in src_install" 702 703 local f 704 for f; do 705 python_newexe "${f}" "${f##*/}" 706 done 707 } 708 709 # @FUNCTION: python_newexe 710 # @USAGE: <path> <new-name> 711 # @DESCRIPTION: 712 # Install the given executable into the executable install directory, 713 # for the current Python implementation (${EPYTHON}). 714 # 715 # The executable will be wrapped properly for the Python implementation, 716 # though no shebang mangling will be performed. It will be renamed 717 # to <new-name>. 718 python_newexe() { 719 debug-print-function ${FUNCNAME} "${@}" 720 721 [[ ${EBUILD_PHASE} != install ]] && 722 die "${FUNCNAME} can only be used in src_install" 723 [[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).' 724 [[ ${#} -eq 2 ]] || die "Usage: ${FUNCNAME} <path> <new-name>" 725 726 local wrapd=${_PYTHON_SCRIPTROOT:-/usr/bin} 727 728 local f=${1} 729 local newfn=${2} 730 731 local scriptdir=$(python_get_scriptdir) 732 local d=${scriptdir#${EPREFIX}} 733 734 ( 735 dodir "${wrapd}" 736 exeopts -m 0755 737 exeinto "${d}" 738 newexe "${f}" "${newfn}" || return ${?} 739 ) 740 741 # install the wrapper 742 local dosym=dosym 743 [[ ${EAPI} == [67] ]] && dosym=dosym8 744 "${dosym}" -r /usr/lib/python-exec/python-exec2 "${wrapd}/${newfn}" 745 746 # don't use this at home, just call python_doscript() instead 747 if [[ ${_PYTHON_REWRITE_SHEBANG} ]]; then 748 python_fix_shebang -q "${ED%/}/${d}/${newfn}" 749 fi 750 } 751 752 # @FUNCTION: python_doscript 753 # @USAGE: <files>... 754 # @DESCRIPTION: 755 # Install the given scripts into the executable install directory, 756 # for the current Python implementation (${EPYTHON}). 757 # 758 # All specified files must start with a 'python' shebang. The shebang 759 # will be converted, and the files will be wrapped properly 760 # for the Python implementation. 761 # 762 # Example: 763 # @CODE 764 # src_install() { 765 # python_foreach_impl python_doscript ${PN} 766 # } 767 # @CODE 768 python_doscript() { 769 debug-print-function ${FUNCNAME} "${@}" 770 771 [[ ${EBUILD_PHASE} != install ]] && 772 die "${FUNCNAME} can only be used in src_install" 773 774 local _PYTHON_REWRITE_SHEBANG=1 775 python_doexe "${@}" 776 } 777 778 # @FUNCTION: python_newscript 779 # @USAGE: <path> <new-name> 780 # @DESCRIPTION: 781 # Install the given script into the executable install directory 782 # for the current Python implementation (${EPYTHON}), and name it 783 # <new-name>. 784 # 785 # The file must start with a 'python' shebang. The shebang will be 786 # converted, and the file will be wrapped properly for the Python 787 # implementation. It will be renamed to <new-name>. 788 # 789 # Example: 790 # @CODE 791 # src_install() { 792 # python_foreach_impl python_newscript foo.py foo 793 # } 794 # @CODE 795 python_newscript() { 796 debug-print-function ${FUNCNAME} "${@}" 797 798 [[ ${EBUILD_PHASE} != install ]] && 799 die "${FUNCNAME} can only be used in src_install" 800 801 local _PYTHON_REWRITE_SHEBANG=1 802 python_newexe "${@}" 803 } 804 805 # @FUNCTION: python_moduleinto 806 # @USAGE: <new-path> 807 # @DESCRIPTION: 808 # Set the Python module install directory for python_domodule(). 809 # The <new-path> can either be an absolute target system path (in which 810 # case it needs to start with a slash, and ${ED} will be prepended to 811 # it) or relative to the implementation's site-packages directory 812 # (then it must not start with a slash). The relative path can be 813 # specified either using the Python package notation (separated by dots) 814 # or the directory notation (using slashes). 815 # 816 # When not set explicitly, the modules are installed to the top 817 # site-packages directory. 818 # 819 # In the relative case, the exact path is determined directly 820 # by each python_domodule invocation. Therefore, python_moduleinto 821 # can be safely called before establishing the Python interpreter and/or 822 # a single call can be used to set the path correctly for multiple 823 # implementations, as can be seen in the following example. 824 # 825 # Example: 826 # @CODE 827 # src_install() { 828 # python_moduleinto bar 829 # # installs ${PYTHON_SITEDIR}/bar/baz.py 830 # python_foreach_impl python_domodule baz.py 831 # } 832 # @CODE 833 python_moduleinto() { 834 debug-print-function ${FUNCNAME} "${@}" 835 836 _PYTHON_MODULEROOT=${1} 837 } 838 839 # @FUNCTION: python_domodule 840 # @USAGE: <files>... 841 # @DESCRIPTION: 842 # Install the given modules (or packages) into the current Python module 843 # installation directory. The list can mention both modules (files) 844 # and packages (directories). All listed files will be installed 845 # for all enabled implementations, and compiled afterwards. 846 # 847 # The files are installed into ${D} when run in src_install() phase. 848 # Otherwise, they are installed into ${BUILD_DIR}/install location 849 # that is suitable for picking up by distutils-r1 in PEP517 mode. 850 # 851 # Example: 852 # @CODE 853 # src_install() { 854 # # (${PN} being a directory) 855 # python_foreach_impl python_domodule ${PN} 856 # } 857 # @CODE 858 python_domodule() { 859 debug-print-function ${FUNCNAME} "${@}" 860 861 [[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).' 862 863 local d 864 if [[ ${_PYTHON_MODULEROOT} == /* ]]; then 865 # absolute path 866 d=${_PYTHON_MODULEROOT} 867 else 868 # relative to site-packages 869 local sitedir=$(python_get_sitedir) 870 d=${sitedir#${EPREFIX}}/${_PYTHON_MODULEROOT//.//} 871 fi 872 873 if [[ ${EBUILD_PHASE} == install ]]; then 874 ( 875 insopts -m 0644 876 insinto "${d}" 877 doins -r "${@}" || return ${?} 878 ) 879 python_optimize "${ED%/}/${d}" 880 elif [[ -n ${BUILD_DIR} ]]; then 881 local dest=${BUILD_DIR}/install${EPREFIX}/${d} 882 mkdir -p "${dest}" || die 883 cp -pR "${@}" "${dest}/" || die 884 ( 885 cd "${dest}" && 886 chmod -R a+rX "${@##*/}" 887 ) || die 888 else 889 die "${FUNCNAME} can only be used in src_install or with BUILD_DIR set" 890 fi 891 } 892 893 # @FUNCTION: python_doheader 894 # @USAGE: <files>... 895 # @DESCRIPTION: 896 # Install the given headers into the implementation-specific include 897 # directory. This function is unconditionally recursive, i.e. you can 898 # pass directories instead of files. 899 # 900 # Example: 901 # @CODE 902 # src_install() { 903 # python_foreach_impl python_doheader foo.h bar.h 904 # } 905 # @CODE 906 python_doheader() { 907 debug-print-function ${FUNCNAME} "${@}" 908 909 [[ ${EBUILD_PHASE} != install ]] && 910 die "${FUNCNAME} can only be used in src_install" 911 [[ ${EPYTHON} ]] || die 'No Python implementation set (EPYTHON is null).' 912 913 local includedir=$(python_get_includedir) 914 local d=${includedir#${EPREFIX}} 915 916 ( 917 insopts -m 0644 918 insinto "${d}" 919 doins -r "${@}" || return ${?} 920 ) 921 } 922 923 # @FUNCTION: _python_wrapper_setup 924 # @USAGE: [<path> [<impl>]] 925 # @INTERNAL 926 # @DESCRIPTION: 927 # Create proper 'python' executable and pkg-config wrappers 928 # (if available) in the directory named by <path>. Set up PATH 929 # and PKG_CONFIG_PATH appropriately. <path> defaults to ${T}/${EPYTHON}. 930 # 931 # The wrappers will be created for implementation named by <impl>, 932 # or for one named by ${EPYTHON} if no <impl> passed. 933 # 934 # If the named directory contains a python symlink already, it will 935 # be assumed to contain proper wrappers already and only environment 936 # setup will be done. If wrapper update is requested, the directory 937 # shall be removed first. 938 _python_wrapper_setup() { 939 debug-print-function ${FUNCNAME} "${@}" 940 941 local workdir=${1:-${T}/${EPYTHON}} 942 local impl=${2:-${EPYTHON}} 943 944 [[ ${workdir} ]] || die "${FUNCNAME}: no workdir specified." 945 [[ ${impl} ]] || die "${FUNCNAME}: no impl nor EPYTHON specified." 946 947 if [[ ! -x ${workdir}/bin/python ]]; then 948 mkdir -p "${workdir}"/{bin,pkgconfig} || die 949 950 # Clean up, in case we were supposed to do a cheap update. 951 rm -f "${workdir}"/bin/python{,2,3}{,-config} || die 952 rm -f "${workdir}"/bin/2to3 || die 953 rm -f "${workdir}"/pkgconfig/python{2,3}{,-embed}.pc || die 954 955 local EPYTHON PYTHON 956 _python_export "${impl}" EPYTHON PYTHON 957 958 local pyver pyother 959 if [[ ${EPYTHON} != python2* ]]; then 960 pyver=3 961 pyother=2 962 else 963 pyver=2 964 pyother=3 965 fi 966 967 # Python interpreter 968 # note: we don't use symlinks because python likes to do some 969 # symlink reading magic that breaks stuff 970 # https://bugs.gentoo.org/show_bug.cgi?id=555752 971 cat > "${workdir}/bin/python" <<-_EOF_ || die 972 #!/bin/sh 973 exec "${PYTHON}" "\${@}" 974 _EOF_ 975 cp "${workdir}/bin/python" "${workdir}/bin/python${pyver}" || die 976 chmod +x "${workdir}/bin/python" "${workdir}/bin/python${pyver}" || die 977 978 local nonsupp=( "python${pyother}" "python${pyother}-config" ) 979 980 # CPython-specific 981 if [[ ${EPYTHON} == python* ]]; then 982 cat > "${workdir}/bin/python-config" <<-_EOF_ || die 983 #!/bin/sh 984 exec "${PYTHON}-config" "\${@}" 985 _EOF_ 986 cp "${workdir}/bin/python-config" \ 987 "${workdir}/bin/python${pyver}-config" || die 988 chmod +x "${workdir}/bin/python-config" \ 989 "${workdir}/bin/python${pyver}-config" || die 990 991 # Python 2.6+. 992 ln -s "${PYTHON/python/2to3-}" "${workdir}"/bin/2to3 || die 993 994 # Python 2.7+. 995 ln -s "${EPREFIX}"/usr/$(get_libdir)/pkgconfig/${EPYTHON/n/n-}.pc \ 996 "${workdir}"/pkgconfig/python${pyver}.pc || die 997 998 # Python 3.8+. 999 if [[ ${EPYTHON} != python[23].[67] ]]; then 1000 ln -s "${EPREFIX}"/usr/$(get_libdir)/pkgconfig/${EPYTHON/n/n-}-embed.pc \ 1001 "${workdir}"/pkgconfig/python${pyver}-embed.pc || die 1002 fi 1003 else 1004 nonsupp+=( 2to3 python-config "python${pyver}-config" ) 1005 fi 1006 1007 local x 1008 for x in "${nonsupp[@]}"; do 1009 cat >"${workdir}"/bin/${x} <<-_EOF_ || die 1010 #!/bin/sh 1011 echo "${ECLASS}: ${FUNCNAME}: ${x} is not supported by ${EPYTHON} (PYTHON_COMPAT)" >&2 1012 exit 127 1013 _EOF_ 1014 chmod +x "${workdir}"/bin/${x} || die 1015 done 1016 fi 1017 1018 # Now, set the environment. 1019 # But note that ${workdir} may be shared with something else, 1020 # and thus already on top of PATH. 1021 if [[ ${PATH##:*} != ${workdir}/bin ]]; then 1022 PATH=${workdir}/bin${PATH:+:${PATH}} 1023 fi 1024 if [[ ${PKG_CONFIG_PATH##:*} != ${workdir}/pkgconfig ]]; then 1025 PKG_CONFIG_PATH=${workdir}/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} 1026 fi 1027 export PATH PKG_CONFIG_PATH 1028 } 1029 1030 # @FUNCTION: python_fix_shebang 1031 # @USAGE: [-f|--force] [-q|--quiet] <path>... 1032 # @DESCRIPTION: 1033 # Replace the shebang in Python scripts with the full path 1034 # to the current Python implementation (PYTHON, including EPREFIX). 1035 # If a directory is passed, works recursively on all Python scripts 1036 # found inside the directory tree. 1037 # 1038 # Only files having a Python shebang (a path to any known Python 1039 # interpreter, optionally preceded by env(1) invocation) will 1040 # be processed. Files with any other shebang will either be skipped 1041 # silently when a directory was passed, or an error will be reported 1042 # for any files without Python shebangs specified explicitly. 1043 # 1044 # Shebangs that are compatible with the current Python version will be 1045 # mangled unconditionally. Incompatible shebangs will cause a fatal 1046 # error, unless --force is specified. 1047 # 1048 # --force causes the function to replace shebangs with incompatible 1049 # Python version (but not non-Python shebangs). --quiet causes 1050 # the function not to list modified files verbosely. 1051 python_fix_shebang() { 1052 debug-print-function ${FUNCNAME} "${@}" 1053 1054 [[ ${EPYTHON} ]] || die "${FUNCNAME}: EPYTHON unset (pkg_setup not called?)" 1055 local PYTHON 1056 _python_export "${EPYTHON}" PYTHON 1057 1058 local force quiet 1059 while [[ ${@} ]]; do 1060 case "${1}" in 1061 -f|--force) force=1; shift;; 1062 -q|--quiet) quiet=1; shift;; 1063 --) shift; break;; 1064 *) break;; 1065 esac 1066 done 1067 1068 [[ ${1} ]] || die "${FUNCNAME}: no paths given" 1069 1070 local path f 1071 for path; do 1072 local any_fixed is_recursive 1073 1074 [[ -d ${path} ]] && is_recursive=1 1075 1076 while IFS= read -r -d '' f; do 1077 local shebang i 1078 local error= match= 1079 1080 # note: we can't ||die here since read will fail if file 1081 # has no newline characters 1082 IFS= read -r shebang <"${f}" 1083 1084 # First, check if it's shebang at all... 1085 if [[ ${shebang} == '#!'* ]]; then 1086 local split_shebang=() 1087 read -r -a split_shebang <<<${shebang#"#!"} || die 1088 1089 local in_path=${split_shebang[0]} 1090 local from='^#! *[^ ]*' 1091 # if the first component is env(1), skip it 1092 if [[ ${in_path} == */env ]]; then 1093 in_path=${split_shebang[1]} 1094 from+=' *[^ ]*' 1095 fi 1096 1097 case ${in_path##*/} in 1098 "${EPYTHON}") 1099 match=1 1100 ;; 1101 python|python[23]) 1102 match=1 1103 [[ ${in_path##*/} == python2 ]] && error=1 1104 ;; 1105 python[23].[0-9]|python3.[1-9][0-9]|pypy|pypy3|jython[23].[0-9]) 1106 # Explicit mismatch. 1107 match=1 1108 error=1 1109 ;; 1110 esac 1111 fi 1112 1113 # disregard mismatches in force mode 1114 [[ ${force} ]] && error= 1115 1116 if [[ ! ${match} ]]; then 1117 # Non-Python shebang. Allowed in recursive mode, 1118 # disallowed when specifying file explicitly. 1119 [[ ${is_recursive} ]] && continue 1120 error=1 1121 fi 1122 1123 if [[ ! ${quiet} ]]; then 1124 einfo "Fixing shebang in ${f#${D%/}}." 1125 fi 1126 1127 if [[ ! ${error} ]]; then 1128 debug-print "${FUNCNAME}: in file ${f#${D%/}}" 1129 debug-print "${FUNCNAME}: rewriting shebang: ${shebang}" 1130 sed -i -e "1s@${from}@#!${PYTHON}@" "${f}" || die 1131 any_fixed=1 1132 else 1133 eerror "The file has incompatible shebang:" 1134 eerror " file: ${f#${D%/}}" 1135 eerror " current shebang: ${shebang}" 1136 eerror " requested impl: ${EPYTHON}" 1137 die "${FUNCNAME}: conversion of incompatible shebang requested" 1138 fi 1139 done < <(find -H "${path}" -type f -print0 || die) 1140 1141 if [[ ! ${any_fixed} ]]; then 1142 eerror "QA error: ${FUNCNAME}, ${path#${D%/}} did not match any fixable files." 1143 eerror "There are no Python files in specified directory." 1144 die "${FUNCNAME} did not match any fixable files" 1145 fi 1146 done 1147 } 1148 1149 # @FUNCTION: _python_check_locale_sanity 1150 # @USAGE: <locale> 1151 # @RETURN: 0 if sane, 1 otherwise 1152 # @INTERNAL 1153 # @DESCRIPTION: 1154 # Check whether the specified locale sanely maps between lowercase 1155 # and uppercase ASCII characters. 1156 _python_check_locale_sanity() { 1157 local -x LC_ALL=${1} 1158 local IFS= 1159 1160 local lc=( {a..z} ) 1161 local uc=( {A..Z} ) 1162 local input="${lc[*]}${uc[*]}" 1163 1164 local output=$(tr '[:lower:][:upper:]' '[:upper:][:lower:]' <<<"${input}") 1165 [[ ${output} == "${uc[*]}${lc[*]}" ]] 1166 } 1167 1168 # @FUNCTION: python_export_utf8_locale 1169 # @RETURN: 0 on success, 1 on failure. 1170 # @DESCRIPTION: 1171 # Attempts to export a usable UTF-8 locale in the LC_CTYPE variable. Does 1172 # nothing if LC_ALL is defined, or if the current locale uses a UTF-8 charmap. 1173 # This may be used to work around the quirky open() behavior of python3. 1174 python_export_utf8_locale() { 1175 debug-print-function ${FUNCNAME} "${@}" 1176 1177 # If the locale program isn't available, just return. 1178 type locale &>/dev/null || return 0 1179 1180 if [[ $(locale charmap) != UTF-8 ]]; then 1181 # Try English first, then everything else. 1182 local lang locales="C.UTF-8 en_US.UTF-8 en_GB.UTF-8 $(locale -a)" 1183 1184 for lang in ${locales}; do 1185 if [[ $(LC_ALL=${lang} locale charmap 2>/dev/null) == UTF-8 ]]; then 1186 if _python_check_locale_sanity "${lang}"; then 1187 export LC_CTYPE=${lang} 1188 if [[ -n ${LC_ALL} ]]; then 1189 export LC_NUMERIC=${LC_ALL} 1190 export LC_TIME=${LC_ALL} 1191 export LC_COLLATE=${LC_ALL} 1192 export LC_MONETARY=${LC_ALL} 1193 export LC_MESSAGES=${LC_ALL} 1194 export LC_PAPER=${LC_ALL} 1195 export LC_NAME=${LC_ALL} 1196 export LC_ADDRESS=${LC_ALL} 1197 export LC_TELEPHONE=${LC_ALL} 1198 export LC_MEASUREMENT=${LC_ALL} 1199 export LC_IDENTIFICATION=${LC_ALL} 1200 export LC_ALL= 1201 fi 1202 return 0 1203 fi 1204 fi 1205 done 1206 1207 ewarn "Could not find a UTF-8 locale. This may trigger build failures in" 1208 ewarn "some python packages. Please ensure that a UTF-8 locale is listed in" 1209 ewarn "/etc/locale.gen and run locale-gen." 1210 return 1 1211 fi 1212 1213 return 0 1214 } 1215 1216 # @FUNCTION: build_sphinx 1217 # @USAGE: <directory> 1218 # @DESCRIPTION: 1219 # Build HTML documentation using dev-python/sphinx in the specified 1220 # <directory>. Takes care of disabling Intersphinx and appending 1221 # to HTML_DOCS. 1222 # 1223 # If <directory> is relative to the current directory, care needs 1224 # to be taken to run einstalldocs from the same directory 1225 # (usually ${S}). 1226 build_sphinx() { 1227 debug-print-function ${FUNCNAME} "${@}" 1228 [[ ${#} -eq 1 ]] || die "${FUNCNAME} takes 1 arg: <directory>" 1229 1230 local dir=${1} 1231 1232 sed -i -e 's:^intersphinx_mapping:disabled_&:' \ 1233 "${dir}"/conf.py || die 1234 # 1. not all packages include the Makefile in pypi tarball, 1235 # so we call sphinx-build directly 1236 # 2. if autodoc is used, we need to call sphinx via EPYTHON, 1237 # to ensure that PEP 517 venv is respected 1238 # 3. if autodoc is not used, then sphinx might not be installed 1239 # for the current impl, so we need a fallback to sphinx-build 1240 local command=( "${EPYTHON}" -m sphinx.cmd.build ) 1241 if ! "${EPYTHON}" -c "import sphinx.cmd.build" 2>/dev/null; then 1242 command=( sphinx-build ) 1243 fi 1244 command+=( 1245 -b html 1246 -d "${dir}"/_build/doctrees 1247 "${dir}" 1248 "${dir}"/_build/html 1249 ) 1250 echo "${command[@]}" >&2 1251 "${command[@]}" || die 1252 1253 HTML_DOCS+=( "${dir}/_build/html/." ) 1254 } 1255 1256 # @FUNCTION: _python_check_EPYTHON 1257 # @INTERNAL 1258 # @DESCRIPTION: 1259 # Check if EPYTHON is set, die if not. 1260 _python_check_EPYTHON() { 1261 if [[ -z ${EPYTHON} ]]; then 1262 die "EPYTHON unset, invalid call context" 1263 fi 1264 } 1265 1266 # @VARIABLE: EPYTEST_DESELECT 1267 # @DEFAULT_UNSET 1268 # @DESCRIPTION: 1269 # Specifies an array of tests to be deselected via pytest's --deselect 1270 # parameter, when calling epytest. The list can include file paths, 1271 # specific test functions or parametrized test invocations. 1272 # 1273 # Note that the listed files will still be subject to collection, 1274 # i.e. modules imported in global scope will need to be available. 1275 # If this is undesirable, EPYTEST_IGNORE can be used instead. 1276 1277 # @VARIABLE: EPYTEST_IGNORE 1278 # @DEFAULT_UNSET 1279 # @DESCRIPTION: 1280 # Specifies an array of paths to be ignored via pytest's --ignore 1281 # parameter, when calling epytest. The listed files will be entirely 1282 # skipped from test collection. 1283 1284 # @FUNCTION: epytest 1285 # @USAGE: [<args>...] 1286 # @DESCRIPTION: 1287 # Run pytest, passing the standard set of pytest options, then 1288 # --deselect and --ignore options based on EPYTEST_DESELECT 1289 # and EPYTEST_IGNORE, then user-specified options. 1290 # 1291 # This command dies on failure and respects nonfatal. 1292 epytest() { 1293 debug-print-function ${FUNCNAME} "${@}" 1294 1295 _python_check_EPYTHON 1296 1297 local color 1298 case ${NOCOLOR} in 1299 true|yes) 1300 color=no 1301 ;; 1302 *) 1303 color=yes 1304 ;; 1305 esac 1306 1307 local args=( 1308 # verbose progress reporting and tracebacks 1309 -vv 1310 # list all non-passed tests in the summary for convenience 1311 # (includes failures, skips, xfails...) 1312 -ra 1313 # print local variables in tracebacks, useful for debugging 1314 -l 1315 # override filterwarnings=error, we do not really want -Werror 1316 # for end users, as it tends to fail on new warnings from deps 1317 -Wdefault 1318 # override color output 1319 "--color=${color}" 1320 # count is more precise when we're dealing with a large number 1321 # of tests 1322 -o console_output_style=count 1323 # disable the undesirable-dependency plugins by default to 1324 # trigger missing argument strips. strip options that require 1325 # them from config files. enable them explicitly via "-p ..." 1326 # if you *really* need them. 1327 -p no:cov 1328 -p no:flake8 1329 -p no:flakes 1330 -p no:pylint 1331 # sterilize pytest-markdown as it runs code snippets from all 1332 # *.md files found without any warning 1333 -p no:markdown 1334 # pytest-sugar undoes everything that's good about pytest output 1335 # and makes it hard to read logs 1336 -p no:sugar 1337 # pytest-xvfb automatically spawns Xvfb for every test suite, 1338 # effectively forcing it even when we'd prefer the tests 1339 # not to have DISPLAY at all, causing crashes sometimes 1340 # and causing us to miss missing virtualx usage 1341 -p no:xvfb 1342 # tavern is intrusive and breaks test suites of various packages 1343 -p no:tavern 1344 ) 1345 local x 1346 for x in "${EPYTEST_DESELECT[@]}"; do 1347 args+=( --deselect "${x}" ) 1348 done 1349 for x in "${EPYTEST_IGNORE[@]}"; do 1350 args+=( --ignore "${x}" ) 1351 done 1352 set -- "${EPYTHON}" -m pytest "${args[@]}" "${@}" 1353 1354 echo "${@}" >&2 1355 "${@}" || die -n "pytest failed with ${EPYTHON}" 1356 local ret=${?} 1357 1358 # remove common temporary directories left over by pytest plugins 1359 rm -rf .hypothesis .pytest_cache || die 1360 # pytest plugins create additional .pyc files while testing 1361 # see e.g. https://bugs.gentoo.org/847235 1362 if [[ -n ${BUILD_DIR} && -d ${BUILD_DIR} ]]; then 1363 find "${BUILD_DIR}" -name '*-pytest-*.pyc' -delete || die 1364 fi 1365 1366 return ${ret} 1367 } 1368 1369 # @FUNCTION: eunittest 1370 # @USAGE: [<args>...] 1371 # @DESCRIPTION: 1372 # Run unit tests using dev-python/unittest-or-fail, passing the standard 1373 # set of options, followed by user-specified options. 1374 # 1375 # This command dies on failure and respects nonfatal. 1376 eunittest() { 1377 debug-print-function ${FUNCNAME} "${@}" 1378 1379 _python_check_EPYTHON 1380 1381 set -- "${EPYTHON}" -m unittest_or_fail discover -v "${@}" 1382 1383 echo "${@}" >&2 1384 "${@}" || die -n "Tests failed with ${EPYTHON}" 1385 return ${?} 1386 } 1387 1388 # @FUNCTION: _python_run_check_deps 1389 # @INTERNAL 1390 # @USAGE: <impl> 1391 # @DESCRIPTION: 1392 # Verify whether <impl> is an acceptable choice to run any-r1 style 1393 # code. Checks whether the interpreter is installed, runs 1394 # python_check_deps() if declared. 1395 _python_run_check_deps() { 1396 debug-print-function ${FUNCNAME} "${@}" 1397 1398 local impl=${1} 1399 local hasv_args=( -b ) 1400 [[ ${EAPI} == 6 ]] && hasv_args=( --host-root ) 1401 1402 einfo "Checking whether ${impl} is suitable ..." 1403 1404 local PYTHON_PKG_DEP 1405 _python_export "${impl}" PYTHON_PKG_DEP 1406 ebegin " ${PYTHON_PKG_DEP}" 1407 has_version "${hasv_args[@]}" "${PYTHON_PKG_DEP}" 1408 eend ${?} || return 1 1409 declare -f python_check_deps >/dev/null || return 0 1410 1411 local PYTHON_USEDEP="python_targets_${impl}(-)" 1412 local PYTHON_SINGLE_USEDEP="python_single_target_${impl}(-)" 1413 ebegin " python_check_deps" 1414 python_check_deps 1415 eend ${?} 1416 } 1417 1418 # @FUNCTION: python_has_version 1419 # @USAGE: [-b|-d|-r] <atom>... 1420 # @DESCRIPTION: 1421 # A convenience wrapper for has_version() with verbose output and better 1422 # defaults for use in python_check_deps(). 1423 # 1424 # The wrapper accepts EAPI 7+-style -b/-d/-r options to indicate 1425 # the root to perform the lookup on. Unlike has_version, the default 1426 # is -b. In EAPI 6, -b and -d are translated to --host-root 1427 # for compatibility. 1428 # 1429 # The wrapper accepts multiple package specifications. For the check 1430 # to succeed, *all* specified atoms must match. 1431 python_has_version() { 1432 debug-print-function ${FUNCNAME} "${@}" 1433 1434 local root_arg=( -b ) 1435 case ${1} in 1436 -b|-d|-r) 1437 root_arg=( "${1}" ) 1438 shift 1439 ;; 1440 esac 1441 1442 if [[ ${EAPI} == 6 ]]; then 1443 if [[ ${root_arg} == -r ]]; then 1444 root_arg=() 1445 else 1446 root_arg=( --host-root ) 1447 fi 1448 fi 1449 1450 local pkg 1451 for pkg; do 1452 ebegin " ${pkg}" 1453 has_version "${root_arg[@]}" "${pkg}" 1454 eend ${?} || return 1455 done 1456 1457 return 0 1458 } 1459 1460 _PYTHON_UTILS_R1=1 1461 fi