Compare commits
57 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8847b3750a | ||
|
4abed5f105 | ||
|
4d31ea8034 | ||
|
4085ef49f2 | ||
|
b8b5cb92da | ||
|
d174f03f62 | ||
|
546e9a3544 | ||
|
cfa45dfdf3 | ||
|
9102e29afc | ||
|
e250f28d09 | ||
|
99e7d8694c | ||
|
2ebee9d4cb | ||
|
5547a87f0b | ||
|
5d7727c2aa | ||
|
a8b26546eb | ||
|
b55e6151bd | ||
|
9eae0ccaf1 | ||
|
9d81ad40e7 | ||
|
824ef3d4af | ||
|
b20d8aa23a | ||
|
2d0673afb1 | ||
|
9b797df44d | ||
|
7b546cae36 | ||
|
5b578a851f | ||
|
77cc1a43a2 | ||
|
0044db1e8a | ||
|
dd8caa5aa3 | ||
|
37bf640f37 | ||
|
76209d7bf3 | ||
|
b1488aa40c | ||
|
fd3dc4c5dc | ||
|
c2305ea368 | ||
|
bc2b51d6d3 | ||
|
d905710a8d | ||
|
c487f82ef7 | ||
|
9dff7fbf6a | ||
|
370b825e45 | ||
|
3a654e3bed | ||
|
2b43f896af | ||
|
14e4c04a42 | ||
|
03a1e3ba65 | ||
|
cad73c2159 | ||
|
187e049d6c | ||
|
39166a7b4b | ||
|
9d2fcef337 | ||
|
4805d44fa0 | ||
|
a27bc6cc24 | ||
|
71c410dfa9 | ||
|
b983c2118b | ||
|
8e9c3d8bbe | ||
|
437166cca7 | ||
|
f77cb3e9dd | ||
|
229fd899ac | ||
|
fa7d708e3c | ||
|
8f6bc2fd6c | ||
|
e64ffd7f26 | ||
|
e1bd214d25 |
20
brp-fix-pyc-reproducibility
Normal file
20
brp-fix-pyc-reproducibility
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash -e
|
||||||
|
|
||||||
|
# If using normal root, avoid changing anything.
|
||||||
|
if [ -z "$RPM_BUILD_ROOT" -o "$RPM_BUILD_ROOT" = "/" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Defined as %py_reproducible_pyc_path macro and passed here as
|
||||||
|
# the first command-line argument
|
||||||
|
path_to_fix=$1
|
||||||
|
|
||||||
|
# First, check that the parser is available:
|
||||||
|
if [ ! -x /usr/bin/marshalparser ]; then
|
||||||
|
echo "ERROR: If %py_reproducible_pyc_path is defined, you have to also BuildRequire: /usr/bin/marshalparser !"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set pipefail so if $path_to_fix does not exist, the build fails
|
||||||
|
set -o pipefail
|
||||||
|
find "$path_to_fix" -type f -name "*.pyc" | xargs /usr/bin/marshalparser --fix --overwrite
|
130
brp-python-bytecompile
Normal file
130
brp-python-bytecompile
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
errors_terminate=$2
|
||||||
|
|
||||||
|
# Usage of %_python_bytecompile_extra is not allowed anymore
|
||||||
|
# See: https://fedoraproject.org/wiki/Changes/No_more_automagic_Python_bytecompilation_phase_3
|
||||||
|
# Therefore $1 ($default_python) is not needed and is invoked with "" by default.
|
||||||
|
# $default_python stays in the arguments for backward compatibility and $extra for the following check:
|
||||||
|
extra=$3
|
||||||
|
if [ 0$extra -eq 1 ]; then
|
||||||
|
echo -e "%_python_bytecompile_extra is discontinued, use %py_byte_compile instead.\nSee: https://fedoraproject.org/wiki/Changes/No_more_automagic_Python_bytecompilation_phase_3" >/dev/stderr
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If using normal root, avoid changing anything.
|
||||||
|
if [ -z "$RPM_BUILD_ROOT" -o "$RPM_BUILD_ROOT" = "/" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# This function now implements Python byte-compilation in three different ways:
|
||||||
|
# Python >= 3.4 and < 3.9 uses a new module compileall2 - https://github.com/fedora-python/compileall2
|
||||||
|
# In Python >= 3.9, compileall2 was merged back to standard library (compileall) so we can use it directly again.
|
||||||
|
# Python < 3.4 (inc. Python 2) uses compileall module from stdlib with some hacks
|
||||||
|
function python_bytecompile()
|
||||||
|
{
|
||||||
|
local options=$1
|
||||||
|
local python_binary=$2
|
||||||
|
local exclude=$3
|
||||||
|
local python_libdir="$4"
|
||||||
|
|
||||||
|
python_version=$($python_binary -c "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
|
||||||
|
|
||||||
|
#
|
||||||
|
# Python 3.4 and higher
|
||||||
|
#
|
||||||
|
if [ "$python_version" -ge 34 ]; then
|
||||||
|
|
||||||
|
# We compile all opt levels in one go: only when $options is empty.
|
||||||
|
if [ -n "$options" ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$python_version" -ge 39 ]; then
|
||||||
|
# For Pyhon 3.9+, use the standard library
|
||||||
|
compileall_module=compileall
|
||||||
|
else
|
||||||
|
# For older Pythons, use compileall2
|
||||||
|
compileall_module=compileall2
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ ! -z $exclude ] && exclude="-x '$exclude'"
|
||||||
|
|
||||||
|
# PYTHONPATH is needed for compileall2, but doesn't hurt for the stdlib
|
||||||
|
# -o 0 -o 1 are the optimization levels
|
||||||
|
# -q disables verbose output
|
||||||
|
# -f forces the process to overwrite existing compiled files
|
||||||
|
# -x excludes paths defined by regex
|
||||||
|
# -e excludes symbolic links pointing outside the build root
|
||||||
|
# -x and -e together implements the same functionality as the Filter class below
|
||||||
|
# -s strips $RPM_BUILD_ROOT from the path
|
||||||
|
# -p prepends the leading slash to the path to make it absolute
|
||||||
|
PYTHONPATH=/usr/lib/rpm/redhat/ $python_binary -B -m $compileall_module -o 0 -o 1 -q -f $exclude -s "$RPM_BUILD_ROOT" -p / --hardlink-dupes -e "$RPM_BUILD_ROOT" "$python_libdir"
|
||||||
|
|
||||||
|
else
|
||||||
|
#
|
||||||
|
# Python 3.3 and lower (incl. Python 2)
|
||||||
|
#
|
||||||
|
|
||||||
|
local real_libdir=${python_libdir/$RPM_BUILD_ROOT/}
|
||||||
|
|
||||||
|
cat << EOF | $python_binary $options
|
||||||
|
import compileall, sys, os, re
|
||||||
|
|
||||||
|
python_libdir = "$python_libdir"
|
||||||
|
depth = sys.getrecursionlimit()
|
||||||
|
real_libdir = "$real_libdir"
|
||||||
|
build_root = "$RPM_BUILD_ROOT"
|
||||||
|
exclude = r"$exclude"
|
||||||
|
|
||||||
|
class Filter:
|
||||||
|
def search(self, path):
|
||||||
|
ret = not os.path.realpath(path).startswith(build_root)
|
||||||
|
if exclude:
|
||||||
|
ret = ret or re.search(exclude, path)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
sys.exit(not compileall.compile_dir(python_libdir, depth, real_libdir, force=1, rx=Filter(), quiet=1))
|
||||||
|
EOF
|
||||||
|
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# .pyc/.pyo files embed a "magic" value, identifying the ABI version of Python
|
||||||
|
# bytecode that they are for.
|
||||||
|
#
|
||||||
|
# The files below RPM_BUILD_ROOT could be targeting multiple versions of
|
||||||
|
# python (e.g. a single build that emits several subpackages e.g. a
|
||||||
|
# python26-foo subpackage, a python31-foo subpackage etc)
|
||||||
|
#
|
||||||
|
# Support this by assuming that below each /usr/lib/python$VERSION/, all
|
||||||
|
# .pyc/.pyo files are to be compiled for /usr/bin/python$VERSION.
|
||||||
|
#
|
||||||
|
# For example, below /usr/lib/python2.6/, we're targeting /usr/bin/python2.6
|
||||||
|
# and below /usr/lib/python3.1/, we're targeting /usr/bin/python3.1
|
||||||
|
|
||||||
|
# Disable Python hash seed randomization
|
||||||
|
# This should help with byte-compilation reproducibility: https://bugzilla.redhat.com/show_bug.cgi?id=1686078
|
||||||
|
# Python 3.11+ no longer needs this: https://github.com/python/cpython/pull/27926 (but we support older Pythons as well)
|
||||||
|
export PYTHONHASHSEED=0
|
||||||
|
|
||||||
|
shopt -s nullglob
|
||||||
|
find "$RPM_BUILD_ROOT" -type d -print0|grep -z -E "/(usr|app)/lib(64)?/python[0-9]\.[0-9]+$" | while read -d "" python_libdir;
|
||||||
|
do
|
||||||
|
python_binary=$(basename "$python_libdir")
|
||||||
|
echo "Bytecompiling .py files below $python_libdir using $python_binary"
|
||||||
|
|
||||||
|
# Generate normal (.pyc) byte-compiled files.
|
||||||
|
python_bytecompile "" "$python_binary" "" "$python_libdir"
|
||||||
|
if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then
|
||||||
|
# One or more of the files had a syntax error
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate optimized (.pyo) byte-compiled files.
|
||||||
|
# N.B. For Python 3.4+, this call does nothing
|
||||||
|
python_bytecompile "-O" "$python_binary" "" "$python_libdir"
|
||||||
|
if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then
|
||||||
|
# One or more of the files had a syntax error
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
25
brp-python-hardlink
Normal file
25
brp-python-hardlink
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# If using normal root, avoid changing anything.
|
||||||
|
if [ -z "$RPM_BUILD_ROOT" ] || [ "$RPM_BUILD_ROOT" = "/" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
hardlink_if_same() {
|
||||||
|
if cmp -s "$1" "$2" ; then
|
||||||
|
ln -f "$1" "$2"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Hardlink identical *.pyc, *.pyo, and *.opt-[12].pyc.
|
||||||
|
# Originally from PLD's rpm-build-macros
|
||||||
|
find "$RPM_BUILD_ROOT" -type f -name "*.pyc" -not -name "*.opt-[12].pyc" | while read pyc ; do
|
||||||
|
hardlink_if_same "$pyc" "${pyc%c}o"
|
||||||
|
o1pyc="${pyc%pyc}opt-1.pyc"
|
||||||
|
hardlink_if_same "$pyc" "$o1pyc"
|
||||||
|
o2pyc="${pyc%pyc}opt-2.pyc"
|
||||||
|
hardlink_if_same "$pyc" "$o2pyc" || hardlink_if_same "$o1pyc" "$o2pyc"
|
||||||
|
done
|
||||||
|
exit 0
|
171
import_all_modules.py
Normal file
171
import_all_modules.py
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
'''Script to perform import of each module given to %%py_check_import
|
||||||
|
'''
|
||||||
|
import argparse
|
||||||
|
import importlib
|
||||||
|
import fnmatch
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import site
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from contextlib import contextmanager
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def read_modules_files(file_paths):
|
||||||
|
'''Read module names from the files (modules must be newline separated).
|
||||||
|
|
||||||
|
Return the module names list or, if no files were provided, an empty list.
|
||||||
|
'''
|
||||||
|
|
||||||
|
if not file_paths:
|
||||||
|
return []
|
||||||
|
|
||||||
|
modules = []
|
||||||
|
for file in file_paths:
|
||||||
|
file_contents = file.read_text()
|
||||||
|
modules.extend(file_contents.split())
|
||||||
|
return modules
|
||||||
|
|
||||||
|
|
||||||
|
def read_modules_from_cli(argv):
|
||||||
|
'''Read module names from command-line arguments (space or comma separated).
|
||||||
|
|
||||||
|
Return the module names list.
|
||||||
|
'''
|
||||||
|
|
||||||
|
if not argv:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# %%py3_check_import allows to separate module list with comma or whitespace,
|
||||||
|
# we need to unify the output to a list of particular elements
|
||||||
|
modules_as_str = ' '.join(argv)
|
||||||
|
modules = re.split(r'[\s,]+', modules_as_str)
|
||||||
|
# Because of shell expansion in some less typical cases it may happen
|
||||||
|
# that a trailing space will occur at the end of the list.
|
||||||
|
# Remove the empty items from the list before passing it further
|
||||||
|
modules = [m for m in modules if m]
|
||||||
|
return modules
|
||||||
|
|
||||||
|
|
||||||
|
def filter_top_level_modules_only(modules):
|
||||||
|
'''Filter out entries with nested modules (containing dot) ie. 'foo.bar'.
|
||||||
|
|
||||||
|
Return the list of top-level modules.
|
||||||
|
'''
|
||||||
|
|
||||||
|
return [module for module in modules if '.' not in module]
|
||||||
|
|
||||||
|
|
||||||
|
def any_match(text, globs):
|
||||||
|
'''Return True if any of given globs fnmatchcase's the given text.'''
|
||||||
|
|
||||||
|
return any(fnmatch.fnmatchcase(text, g) for g in globs)
|
||||||
|
|
||||||
|
|
||||||
|
def exclude_unwanted_module_globs(globs, modules):
|
||||||
|
'''Filter out entries which match the either of the globs given as argv.
|
||||||
|
|
||||||
|
Return the list of filtered modules.
|
||||||
|
'''
|
||||||
|
|
||||||
|
return [m for m in modules if not any_match(m, globs)]
|
||||||
|
|
||||||
|
|
||||||
|
def read_modules_from_all_args(args):
|
||||||
|
'''Return a joined list of modules from all given command-line arguments.
|
||||||
|
'''
|
||||||
|
|
||||||
|
modules = read_modules_files(args.filename)
|
||||||
|
modules.extend(read_modules_from_cli(args.modules))
|
||||||
|
if args.exclude:
|
||||||
|
modules = exclude_unwanted_module_globs(args.exclude, modules)
|
||||||
|
|
||||||
|
if args.top_level:
|
||||||
|
modules = filter_top_level_modules_only(modules)
|
||||||
|
|
||||||
|
# Error when someone accidentally managed to filter out everything
|
||||||
|
if len(modules) == 0:
|
||||||
|
raise ValueError('No modules to check were left')
|
||||||
|
|
||||||
|
return modules
|
||||||
|
|
||||||
|
|
||||||
|
def import_modules(modules):
|
||||||
|
'''Procedure to perform import check for each module name from the given list of modules.
|
||||||
|
'''
|
||||||
|
|
||||||
|
for module in modules:
|
||||||
|
print('Check import:', module, file=sys.stderr)
|
||||||
|
importlib.import_module(module)
|
||||||
|
|
||||||
|
|
||||||
|
def argparser():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='Generate list of all importable modules for import check.'
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'modules', nargs='*',
|
||||||
|
help=('Add modules to check the import (space or comma separated).'),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-f', '--filename', action='append', type=Path,
|
||||||
|
help='Add importable module names list from file.',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-t', '--top-level', action='store_true',
|
||||||
|
help='Check only top-level modules.',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-e', '--exclude', action='append',
|
||||||
|
help='Provide modules globs to be excluded from the check.',
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def remove_unwanteds_from_sys_path():
|
||||||
|
'''Remove cwd and this script's parent from sys.path for the import test.
|
||||||
|
Bring the original contents back after import is done (or failed)
|
||||||
|
'''
|
||||||
|
|
||||||
|
cwd_absolute = Path.cwd().absolute()
|
||||||
|
this_file_parent = Path(__file__).parent.absolute()
|
||||||
|
old_sys_path = list(sys.path)
|
||||||
|
for path in old_sys_path:
|
||||||
|
if Path(path).absolute() in (cwd_absolute, this_file_parent):
|
||||||
|
sys.path.remove(path)
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
sys.path = old_sys_path
|
||||||
|
|
||||||
|
|
||||||
|
def addsitedirs_from_environ():
|
||||||
|
'''Load directories from the _PYTHONSITE environment variable (separated by :)
|
||||||
|
and load the ones already present in sys.path via site.addsitedir()
|
||||||
|
to handle .pth files in them.
|
||||||
|
|
||||||
|
This is needed to properly import old-style namespace packages with nspkg.pth files.
|
||||||
|
See https://bugzilla.redhat.com/2018551 for a more detailed rationale.'''
|
||||||
|
for path in os.getenv('_PYTHONSITE', '').split(':'):
|
||||||
|
if path in sys.path:
|
||||||
|
site.addsitedir(path)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv=None):
|
||||||
|
|
||||||
|
cli_args = argparser().parse_args(argv)
|
||||||
|
|
||||||
|
if not cli_args.modules and not cli_args.filename:
|
||||||
|
raise ValueError('No modules to check were provided')
|
||||||
|
|
||||||
|
modules = read_modules_from_all_args(cli_args)
|
||||||
|
|
||||||
|
with remove_unwanteds_from_sys_path():
|
||||||
|
addsitedirs_from_environ()
|
||||||
|
import_modules(modules)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -4,16 +4,17 @@
|
|||||||
# Which unfortunately makes the definition more complicated than it should be
|
# Which unfortunately makes the definition more complicated than it should be
|
||||||
|
|
||||||
# Usage:
|
# Usage:
|
||||||
# %py_byte_compile <interpereter> <path>
|
# %%py_byte_compile <interpereter> <path>
|
||||||
# Example:
|
# Example:
|
||||||
# %py_byte_compile %{__python3} %{buildroot}%{_datadir}/spam/plugins/
|
# %%py_byte_compile %%{__python3} %%{buildroot}%%{_datadir}/spam/plugins/
|
||||||
|
|
||||||
# This will terminate build on SyntaxErrors, if you want to avoid that,
|
# This will terminate build on SyntaxErrors, if you want to avoid that,
|
||||||
# use it in a subshell like this:
|
# use it in a subshell like this:
|
||||||
# (%{py_byte_compile <interpereter> <path>}) || :
|
# (%%{py_byte_compile <interpereter> <path>}) || :
|
||||||
|
|
||||||
# Setting PYTHONHASHSEED=0 disables Python hash seed randomization
|
# Setting PYTHONHASHSEED=0 disables Python hash seed randomization
|
||||||
# This should help with byte-compilation reproducibility: https://bugzilla.redhat.com/show_bug.cgi?id=1686078
|
# This should help with byte-compilation reproducibility: https://bugzilla.redhat.com/show_bug.cgi?id=1686078
|
||||||
|
# Python 3.11+ no longer needs this: https://github.com/python/cpython/pull/27926 (but we support older Pythons as well)
|
||||||
|
|
||||||
%py_byte_compile()\
|
%py_byte_compile()\
|
||||||
py2_byte_compile () {\
|
py2_byte_compile () {\
|
||||||
@ -28,13 +29,13 @@ py2_byte_compile () {\
|
|||||||
py3_byte_compile () {\
|
py3_byte_compile () {\
|
||||||
python_binary="env PYTHONHASHSEED=0 %1"\
|
python_binary="env PYTHONHASHSEED=0 %1"\
|
||||||
bytecode_compilation_path="%2"\
|
bytecode_compilation_path="%2"\
|
||||||
PYTHONPATH="%{_rpmconfigdir}/redhat" $python_binary -s -B -m compileall2 -o 0 -o 1 -s $RPM_BUILD_ROOT -p / $bytecode_compilation_path \
|
PYTHONPATH="%{_rpmconfigdir}/redhat" $python_binary -s -B -m compileall2 -o 0 -o 1 -s $RPM_BUILD_ROOT -p / --hardlink-dupes $bytecode_compilation_path \
|
||||||
}\
|
}\
|
||||||
\
|
\
|
||||||
py39_byte_compile () {\
|
py39_byte_compile () {\
|
||||||
python_binary="env PYTHONHASHSEED=0 %1"\
|
python_binary="env PYTHONHASHSEED=0 %1"\
|
||||||
bytecode_compilation_path="%2"\
|
bytecode_compilation_path="%2"\
|
||||||
$python_binary -s -B -m compileall -o 0 -o 1 -s $RPM_BUILD_ROOT -p / $bytecode_compilation_path \
|
$python_binary -s -B -m compileall -o 0 -o 1 -s $RPM_BUILD_ROOT -p / --hardlink-dupes $bytecode_compilation_path \
|
||||||
}\
|
}\
|
||||||
\
|
\
|
||||||
# Path to intepreter should not contain any arguments \
|
# Path to intepreter should not contain any arguments \
|
||||||
|
@ -1,15 +1,21 @@
|
|||||||
# unversioned macros: used with user defined __python, no longer part of rpm >= 4.15
|
# unversioned macros: used with user defined __python, no longer part of rpm >= 4.15
|
||||||
# __python is defined to error by default in the srpm macros
|
# __python is defined to error by default in the srpm macros
|
||||||
%python_sitelib %(%{__python} -Esc "from distutils.sysconfig import get_python_lib; print(get_python_lib())")
|
# nb: $RPM_BUILD_ROOT is not set when the macros are expanded (at spec parse time)
|
||||||
%python_sitearch %(%{__python} -Esc "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")
|
# so we set it manually (to empty string), making our Python prefer the correct install scheme location
|
||||||
%python_version %(%{__python} -Esc "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
|
# platbase/base is explicitly set to %%{_prefix} to support custom values, such as /app for flatpaks
|
||||||
%python_version_nodots %(%{__python} -Esc "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
|
%python_sitelib %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_path('purelib', vars={'platbase': '%{_prefix}', 'base': '%{_prefix}'}))")
|
||||||
%python_platform %(%{__python} -Esc "import sysconfig; print(sysconfig.get_platform())")
|
%python_sitearch %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_path('platlib', vars={'platbase': '%{_prefix}', 'base': '%{_prefix}'}))")
|
||||||
%python_platform_triplet %(%{__python} -Esc "import sysconfig; print(sysconfig.get_config_var('MULTIARCH'))")
|
%python_version %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
|
||||||
%python_ext_suffix %(%{__python} -Esc "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
|
%python_version_nodots %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
|
||||||
|
%python_platform %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_platform())")
|
||||||
|
%python_platform_triplet %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_config_var('MULTIARCH'))")
|
||||||
|
%python_ext_suffix %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
|
||||||
|
%python_cache_tag %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; print(sys.implementation.cache_tag)")
|
||||||
|
|
||||||
%py_setup setup.py
|
%py_setup setup.py
|
||||||
%py_shbang_opts -s
|
%_py_shebang_s s
|
||||||
|
%_py_shebang_P %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; print('P' if hasattr(sys.flags, 'safe_path') else '')")
|
||||||
|
%py_shbang_opts -%{?_py_shebang_s}%{?_py_shebang_P}
|
||||||
%py_shbang_opts_nodash %(opts=%{py_shbang_opts}; echo ${opts#-})
|
%py_shbang_opts_nodash %(opts=%{py_shbang_opts}; echo ${opts#-})
|
||||||
%py_shebang_flags %(opts=%{py_shbang_opts}; echo ${opts#-})
|
%py_shebang_flags %(opts=%{py_shbang_opts}; echo ${opts#-})
|
||||||
%py_shebang_fix %{expand:\\\
|
%py_shebang_fix %{expand:\\\
|
||||||
@ -45,7 +51,7 @@
|
|||||||
|
|
||||||
%py_install() %{expand:\\\
|
%py_install() %{expand:\\\
|
||||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||||
%{__python} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*}
|
%{__python} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} --prefix %{_prefix} %{?*}
|
||||||
rm -rfv %{buildroot}%{_bindir}/__pycache__
|
rm -rfv %{buildroot}%{_bindir}/__pycache__
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +62,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
%py_install_wheel() %{expand:\\\
|
%py_install_wheel() %{expand:\\\
|
||||||
%{__python} -m pip install -I dist/%{1} --root %{buildroot} --no-deps --no-index --no-warn-script-location
|
%{__python} -m pip install -I dist/%{1} --root %{buildroot} --prefix %{_prefix} --no-deps --no-index --no-warn-script-location
|
||||||
rm -rfv %{buildroot}%{_bindir}/__pycache__
|
rm -rfv %{buildroot}%{_bindir}/__pycache__
|
||||||
for distinfo in %{buildroot}%{python_sitelib}/*.dist-info %{buildroot}%{python_sitearch}/*.dist-info; do
|
for distinfo in %{buildroot}%{python_sitelib}/*.dist-info %{buildroot}%{python_sitearch}/*.dist-info; do
|
||||||
if [ -f ${distinfo}/direct_url.json ]; then
|
if [ -f ${distinfo}/direct_url.json ]; then
|
||||||
@ -66,6 +72,31 @@
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# With $PATH and $PYTHONPATH set to the %%buildroot,
|
||||||
|
# try to import the Python module(s) given as command-line args or read from file (-f).
|
||||||
|
# Respect the custom values of %%py_shebang_flags or set nothing if it's undefined.
|
||||||
|
# Filter and check import on only top-level modules using -t flag.
|
||||||
|
# Exclude unwanted modules by passing their globs to -e option.
|
||||||
|
# Useful as a smoke test in %%check when running tests is not feasible.
|
||||||
|
# Use spaces or commas as separators if providing list directly.
|
||||||
|
# Use newlines as separators if providing list in a file.
|
||||||
|
%py_check_import(e:tf:) %{expand:\\\
|
||||||
|
PATH="%{buildroot}%{_bindir}:$PATH"\\\
|
||||||
|
PYTHONPATH="${PYTHONPATH:-%{buildroot}%{python_sitearch}:%{buildroot}%{python_sitelib}}"\\\
|
||||||
|
_PYTHONSITE="%{buildroot}%{python_sitearch}:%{buildroot}%{python_sitelib}"\\\
|
||||||
|
PYTHONDONTWRITEBYTECODE=1\\\
|
||||||
|
%{lua:
|
||||||
|
local command = "%{__python} "
|
||||||
|
if rpm.expand("%{?py_shebang_flags}") ~= "" then
|
||||||
|
command = command .. "-%{py_shebang_flags}"
|
||||||
|
end
|
||||||
|
command = command .. " %{_rpmconfigdir}/redhat/import_all_modules.py "
|
||||||
|
-- handle multiline arguments correctly, see https://bugzilla.redhat.com/2018809
|
||||||
|
local args=rpm.expand('%{?**}'):gsub("[%s\\\\]*%s+", " ")
|
||||||
|
print(command .. args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
%python_provide() %{lua:
|
%python_provide() %{lua:
|
||||||
local python = require "fedora.srpm.python"
|
local python = require "fedora.srpm.python"
|
||||||
function string.starts(String,Start)
|
function string.starts(String,Start)
|
||||||
@ -74,6 +105,7 @@
|
|||||||
local package = rpm.expand("%{?1}")
|
local package = rpm.expand("%{?1}")
|
||||||
local vr = rpm.expand("%{?epoch:%{epoch}:}%{version}-%{release}")
|
local vr = rpm.expand("%{?epoch:%{epoch}:}%{version}-%{release}")
|
||||||
local provides = python.python_altprovides(package, vr)
|
local provides = python.python_altprovides(package, vr)
|
||||||
|
local default_python3_pkgversion = rpm.expand("%{__default_python3_pkgversion}")
|
||||||
if (string.starts(package, "python3-")) then
|
if (string.starts(package, "python3-")) then
|
||||||
for i, provide in ipairs(provides) do
|
for i, provide in ipairs(provides) do
|
||||||
print("\\nProvides: " .. provide)
|
print("\\nProvides: " .. provide)
|
||||||
@ -84,14 +116,14 @@
|
|||||||
print(string.sub(package,9,string.len(package)))
|
print(string.sub(package,9,string.len(package)))
|
||||||
print(" < " .. vr)
|
print(" < " .. vr)
|
||||||
end
|
end
|
||||||
elseif (string.starts(package, "python" .. rpm.expand("%{__default_python3_pkgversion}") .. "-")) then
|
elseif (string.starts(package, "python" .. default_python3_pkgversion .. "-")) then
|
||||||
for i, provide in ipairs(provides) do
|
for i, provide in ipairs(provides) do
|
||||||
print("\\nProvides: " .. provide)
|
print("\\nProvides: " .. provide)
|
||||||
end
|
end
|
||||||
--Obsoleting the previous default python package (if it doesn't have isa)
|
--Obsoleting the previous default python package (if it doesn't have isa)
|
||||||
if (string.sub(package, "-1") ~= ")") then
|
if (string.sub(package, "-1") ~= ")") then
|
||||||
print("\\nObsoletes: python-")
|
print("\\nObsoletes: python-")
|
||||||
print(string.sub(package,11,string.len(package)))
|
print(string.sub(package,8+string.len(default_python3_pkgversion),string.len(package)))
|
||||||
print(" < " .. vr)
|
print(" < " .. vr)
|
||||||
end
|
end
|
||||||
elseif (string.starts(package, "python")) then
|
elseif (string.starts(package, "python")) then
|
||||||
|
@ -1,22 +1,3 @@
|
|||||||
# Define the Python interpreter paths in the SRPM macros so that
|
|
||||||
# - they can be used in Build/Requires
|
|
||||||
# - they can be used in non-Python packages where requiring pythonX-devel would
|
|
||||||
# be an overkill
|
|
||||||
|
|
||||||
# use the underscored macros to redefine the behavior of %%python3_version etc.
|
|
||||||
%__python2 /usr/bin/python2
|
|
||||||
%__python3 /usr/bin/python3
|
|
||||||
|
|
||||||
# use the non-underscored macros to refer to Python in spec, etc.
|
|
||||||
%python2 %__python2
|
|
||||||
%python3 %__python3
|
|
||||||
|
|
||||||
# See https://fedoraproject.org/wiki/Changes/PythonMacroError
|
|
||||||
%__python %{error:attempt to use unversioned python, define %%__python to %{__python2} or %{__python3} explicitly}
|
|
||||||
|
|
||||||
# Users can use %%python only if they redefined %%__python (e.g. to %%__python3)
|
|
||||||
%python %__python
|
|
||||||
|
|
||||||
# There are multiple Python 3 versions packaged, but only one can be the "main" version
|
# There are multiple Python 3 versions packaged, but only one can be the "main" version
|
||||||
# That means that it owns the "python3" namespace:
|
# That means that it owns the "python3" namespace:
|
||||||
# - python3 package name
|
# - python3 package name
|
||||||
@ -36,22 +17,78 @@
|
|||||||
# There are two macros:
|
# There are two macros:
|
||||||
#
|
#
|
||||||
# This always contains the major.minor version (with dots), default for %%python3_version.
|
# This always contains the major.minor version (with dots), default for %%python3_version.
|
||||||
%__default_python3_version 3.9
|
%__default_python3_version 3.11
|
||||||
#
|
#
|
||||||
# The pkgname version that determines the alternative provide name (e.g. python3.9-foo),
|
# The pkgname version that determines the alternative provide name (e.g. python3.9-foo),
|
||||||
# set to the same as above, but historically hasn't included the dot.
|
# set to the same as above, but historically hasn't included the dot.
|
||||||
# This is left intentionally a separate macro, in case the naming convention ever changes.
|
# This is left intentionally a separate macro, in case the naming convention ever changes.
|
||||||
%__default_python3_pkgversion %__default_python3_version
|
%__default_python3_pkgversion %__default_python3_version
|
||||||
|
|
||||||
# python3_pkgversion specifies the version of Python 3 in the distro. It can be
|
# python3_pkgversion specifies the version of Python 3 in the distro.
|
||||||
# a specific version (e.g. 34 in Fedora EPEL7)
|
# For Fedora, this is usually just "3".
|
||||||
|
# It can be a specific version distro-wide (e.g. "36" in EPEL7).
|
||||||
|
# Alternatively, it can be overridden in spec (e.g. to "3.8") when building for alternate Python stacks.
|
||||||
%python3_pkgversion 3
|
%python3_pkgversion 3
|
||||||
|
|
||||||
# Set to /bin/true to avoid %ifdefs and %{? in specfiles
|
# Define the Python interpreter paths in the SRPM macros so that
|
||||||
%__python3_other /bin/true
|
# - they can be used in Build/Requires
|
||||||
%py3_other_build /bin/true
|
# - they can be used in non-Python packages where requiring pythonX-devel would
|
||||||
%py3_other_install /bin/true
|
# be an overkill
|
||||||
|
|
||||||
|
# use the underscored macros to redefine the behavior of %%python3_version etc.
|
||||||
|
%__python2 /usr/bin/python2
|
||||||
|
%__python3 /usr/bin/python%{python3_pkgversion}
|
||||||
|
|
||||||
|
# use the non-underscored macros to refer to Python in spec, etc.
|
||||||
|
%python2 %__python2
|
||||||
|
%python3 %__python3
|
||||||
|
|
||||||
|
# See https://fedoraproject.org/wiki/Changes/PythonMacroError
|
||||||
|
%__python %{error:attempt to use unversioned python, define %%__python to %{__python2} or %{__python3} explicitly}
|
||||||
|
|
||||||
|
# Users can use %%python only if they redefined %%__python (e.g. to %%__python3)
|
||||||
|
%python %__python
|
||||||
|
|
||||||
|
# Define where Python wheels will be stored and the prefix of -wheel packages
|
||||||
|
# - In Fedora we want wheel subpackages named e.g. `python-pip-wheel` that
|
||||||
|
# install packages into `/usr/share/python-wheels`. Both names are not
|
||||||
|
# versioned, because they're used by all Python 3 stacks.
|
||||||
|
# - In RHEL we want wheel packages named e.g. `python3-pip-wheel` and
|
||||||
|
# `python3.11-pip-wheel` that install packages into similarly versioned
|
||||||
|
# locations. We want each Python stack in RHEL to have their own wheels,
|
||||||
|
# because the main python3 wheels (which we can't upgrade) will likely be
|
||||||
|
# quite old by the time we're adding new alternate Python stacks.
|
||||||
|
# - In ELN we want to follow Fedora, because builds for ELN and Fedora rawhide
|
||||||
|
# need to be interoperable.
|
||||||
|
%python_wheel_pkg_prefix python%{?rhel:%{!?eln:%{python3_pkgversion}}}
|
||||||
|
%python_wheel_dir %{_datadir}/%{python_wheel_pkg_prefix}-wheels
|
||||||
|
|
||||||
|
|
||||||
|
### BRP scripts (and related macros)
|
||||||
|
|
||||||
|
## Automatically compile python files
|
||||||
|
%py_auto_byte_compile 1
|
||||||
|
## Should python bytecompilation errors terminate a build?
|
||||||
|
%_python_bytecompile_errors_terminate_build 1
|
||||||
|
## Should python bytecompilation compile outside python specific directories?
|
||||||
|
## This always causes errors when enabled, see https://fedoraproject.org/wiki/Changes/No_more_automagic_Python_bytecompilation_phase_3
|
||||||
|
%_python_bytecompile_extra 0
|
||||||
|
|
||||||
|
## The individual BRP scripts
|
||||||
|
%__brp_python_bytecompile %{_rpmconfigdir}/redhat/brp-python-bytecompile "" "%{?_python_bytecompile_errors_terminate_build}" "%{?_python_bytecompile_extra}"
|
||||||
|
%__brp_fix_pyc_reproducibility %{_rpmconfigdir}/redhat/brp-fix-pyc-reproducibility
|
||||||
|
%__brp_python_hardlink %{_rpmconfigdir}/redhat/brp-python-hardlink
|
||||||
|
|
||||||
|
## This macro is included in redhat-rpm-config's %%__os_install_post
|
||||||
|
# Note that the order matters:
|
||||||
|
# 1. brp-python-bytecompile can create (or replace) pyc files
|
||||||
|
# 2. brp-fix-pyc-reproducibility can modify the pyc files from above
|
||||||
|
# 3. brp-python-hardlink de-duplicates identical pyc files
|
||||||
|
%__os_install_post_python \
|
||||||
|
%{?py_auto_byte_compile:%{?__brp_python_bytecompile}} \
|
||||||
|
%{?py_reproducible_pyc_path:%{?__brp_fix_pyc_reproducibility} "%{py_reproducible_pyc_path}"} \
|
||||||
|
%{?__brp_python_hardlink} \
|
||||||
|
%{nil}
|
||||||
|
|
||||||
|
|
||||||
# === Macros for Build/Requires tags using Python dist tags ===
|
# === Macros for Build/Requires tags using Python dist tags ===
|
||||||
@ -68,7 +105,7 @@
|
|||||||
|
|
||||||
# Creates Python 2 dist tag(s) after converting names to canonical format
|
# Creates Python 2 dist tag(s) after converting names to canonical format
|
||||||
# Needs to first put all arguments into a list, because invoking a different
|
# Needs to first put all arguments into a list, because invoking a different
|
||||||
# macro (%py_dist_name) overwrites them
|
# macro (%%py_dist_name) overwrites them
|
||||||
%py2_dist() %{lua:\
|
%py2_dist() %{lua:\
|
||||||
args = {}\
|
args = {}\
|
||||||
arg = 1\
|
arg = 1\
|
||||||
@ -88,7 +125,7 @@
|
|||||||
|
|
||||||
# Creates Python 3 dist tag(s) after converting names to canonical format
|
# Creates Python 3 dist tag(s) after converting names to canonical format
|
||||||
# Needs to first put all arguments into a list, because invoking a different
|
# Needs to first put all arguments into a list, because invoking a different
|
||||||
# macro (%py_dist_name) overwrites them
|
# macro (%%py_dist_name) overwrites them
|
||||||
%py3_dist() %{lua:\
|
%py3_dist() %{lua:\
|
||||||
python3_pkgversion = rpm.expand("%python3_pkgversion");\
|
python3_pkgversion = rpm.expand("%python3_pkgversion");\
|
||||||
args = {}\
|
args = {}\
|
||||||
@ -110,12 +147,12 @@
|
|||||||
# Macro to replace overly complicated references to PyPI source files.
|
# Macro to replace overly complicated references to PyPI source files.
|
||||||
# Expands to the pythonhosted URL for a package
|
# Expands to the pythonhosted URL for a package
|
||||||
# Accepts zero to three arguments:
|
# Accepts zero to three arguments:
|
||||||
# 1: The PyPI project name, defaulting to %srcname if it is defined, then
|
# 1: The PyPI project name, defaulting to %%srcname if it is defined, then
|
||||||
# %pypi_name if it is defined, then just %name.
|
# %%pypi_name if it is defined, then just %%name.
|
||||||
# 2: The PYPI version, defaulting to %version with tildes stripped.
|
# 2: The PYPI version, defaulting to %%version with tildes stripped.
|
||||||
# 3: The file extension, defaulting to "tar.gz". (A period will be added
|
# 3: The file extension, defaulting to "tar.gz". (A period will be added
|
||||||
# automatically.)
|
# automatically.)
|
||||||
# Requires %__pypi_url and %__pypi_default_extension to be defined.
|
# Requires %%__pypi_url and %%__pypi_default_extension to be defined.
|
||||||
%__pypi_url https://files.pythonhosted.org/packages/source/
|
%__pypi_url https://files.pythonhosted.org/packages/source/
|
||||||
%__pypi_default_extension tar.gz
|
%__pypi_default_extension tar.gz
|
||||||
|
|
||||||
@ -154,6 +191,7 @@
|
|||||||
|
|
||||||
%py_provides() %{lua:
|
%py_provides() %{lua:
|
||||||
local python = require 'fedora.srpm.python'
|
local python = require 'fedora.srpm.python'
|
||||||
|
local rhel = rpm.expand('%{?rhel}')
|
||||||
local name = rpm.expand('%1')
|
local name = rpm.expand('%1')
|
||||||
if name == '%1' then
|
if name == '%1' then
|
||||||
rpm.expand('%{error:%%py_provides requires at least 1 argument, the name to provide}')
|
rpm.expand('%{error:%%py_provides requires at least 1 argument, the name to provide}')
|
||||||
@ -167,6 +205,21 @@
|
|||||||
for i, provide in ipairs(provides) do
|
for i, provide in ipairs(provides) do
|
||||||
print('Provides: ' .. provide .. '\\n')
|
print('Provides: ' .. provide .. '\\n')
|
||||||
end
|
end
|
||||||
|
-- We only generate these Obsoletes on CentOS/RHEL to provide clean upgrade
|
||||||
|
-- path, e.g. python3-foo obsoletes python3.9-foo from previous RHEL.
|
||||||
|
-- In Fedora this is not needed as we don't ship ecosystem packages
|
||||||
|
-- for alternative Python interpreters.
|
||||||
|
if rhel ~= '' then
|
||||||
|
-- Create Obsoletes only if the name does not end in a parenthesis,
|
||||||
|
-- as Obsoletes can't include parentheses.
|
||||||
|
-- This most commonly happens when the name contains an isa.
|
||||||
|
if (string.sub(name, "-1") ~= ")") then
|
||||||
|
local obsoletes = python.python_altobsoletes(name, evr)
|
||||||
|
for i, obsolete in ipairs(obsoletes) do
|
||||||
|
print('Obsoletes: ' .. obsolete .. '\\n')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
%python_extras_subpkg(n:i:f:F) %{expand:%{lua:
|
%python_extras_subpkg(n:i:f:F) %{expand:%{lua:
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
%python3_sitelib %(%{__python3} -Ic "from distutils.sysconfig import get_python_lib; print(get_python_lib())")
|
# nb: $RPM_BUILD_ROOT is not set when the macros are expanded (at spec parse time)
|
||||||
%python3_sitearch %(%{__python3} -Ic "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")
|
# so we set it manually (to empty string), making our Python prefer the correct install scheme location
|
||||||
%python3_version %(%{__python3} -Ic "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
|
# platbase/base is explicitly set to %%{_prefix} to support custom values, such as /app for flatpaks
|
||||||
%python3_version_nodots %(%{__python3} -Ic "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
|
%python3_sitelib %(RPM_BUILD_ROOT= %{__python3} -Ic "import sysconfig; print(sysconfig.get_path('purelib', vars={'platbase': '%{_prefix}', 'base': '%{_prefix}'}))")
|
||||||
%python3_platform %(%{__python3} -Ic "import sysconfig; print(sysconfig.get_platform())")
|
%python3_sitearch %(RPM_BUILD_ROOT= %{__python3} -Ic "import sysconfig; print(sysconfig.get_path('platlib', vars={'platbase': '%{_prefix}', 'base': '%{_prefix}'}))")
|
||||||
%python3_platform_triplet %(%{__python3} -Ic "import sysconfig; print(sysconfig.get_config_var('MULTIARCH'))")
|
%python3_version %(RPM_BUILD_ROOT= %{__python3} -Ic "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
|
||||||
%python3_ext_suffix %(%{__python3} -Ic "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
|
%python3_version_nodots %(RPM_BUILD_ROOT= %{__python3} -Ic "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
|
||||||
|
%python3_platform %(RPM_BUILD_ROOT= %{__python3} -Ic "import sysconfig; print(sysconfig.get_platform())")
|
||||||
|
%python3_platform_triplet %(RPM_BUILD_ROOT= %{__python3} -Ic "import sysconfig; print(sysconfig.get_config_var('MULTIARCH'))")
|
||||||
|
%python3_ext_suffix %(RPM_BUILD_ROOT= %{__python3} -Ic "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
|
||||||
|
%python3_cache_tag %(RPM_BUILD_ROOT= %{__python3} -Ic "import sys; print(sys.implementation.cache_tag)")
|
||||||
%py3dir %{_builddir}/python3-%{name}-%{version}-%{release}
|
%py3dir %{_builddir}/python3-%{name}-%{version}-%{release}
|
||||||
|
|
||||||
%py3_shbang_opts -s
|
%_py3_shebang_s s
|
||||||
|
%_py3_shebang_P %(RPM_BUILD_ROOT= %{__python3} -Ic "import sys; print('P' if hasattr(sys.flags, 'safe_path') else '')")
|
||||||
|
%py3_shbang_opts -%{?_py3_shebang_s}%{?_py3_shebang_P}
|
||||||
%py3_shbang_opts_nodash %(opts=%{py3_shbang_opts}; echo ${opts#-})
|
%py3_shbang_opts_nodash %(opts=%{py3_shbang_opts}; echo ${opts#-})
|
||||||
%py3_shebang_flags %(opts=%{py3_shbang_opts}; echo ${opts#-})
|
%py3_shebang_flags %(opts=%{py3_shbang_opts}; echo ${opts#-})
|
||||||
%py3_shebang_fix %{expand:\\\
|
%py3_shebang_fix %{expand:\\\
|
||||||
@ -43,7 +49,7 @@
|
|||||||
|
|
||||||
%py3_install() %{expand:\\\
|
%py3_install() %{expand:\\\
|
||||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||||
%{__python3} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*}
|
%{__python3} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} --prefix %{_prefix} %{?*}
|
||||||
rm -rfv %{buildroot}%{_bindir}/__pycache__
|
rm -rfv %{buildroot}%{_bindir}/__pycache__
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +60,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
%py3_install_wheel() %{expand:\\\
|
%py3_install_wheel() %{expand:\\\
|
||||||
%{__python3} -m pip install -I dist/%{1} --root %{buildroot} --no-deps --no-index --no-warn-script-location
|
%{__python3} -m pip install -I dist/%{1} --root %{buildroot} --prefix %{_prefix} --no-deps --no-index --no-warn-script-location
|
||||||
rm -rfv %{buildroot}%{_bindir}/__pycache__
|
rm -rfv %{buildroot}%{_bindir}/__pycache__
|
||||||
for distinfo in %{buildroot}%{python3_sitelib}/*.dist-info %{buildroot}%{python3_sitearch}/*.dist-info; do
|
for distinfo in %{buildroot}%{python3_sitelib}/*.dist-info %{buildroot}%{python3_sitearch}/*.dist-info; do
|
||||||
if [ -f ${distinfo}/direct_url.json ]; then
|
if [ -f ${distinfo}/direct_url.json ]; then
|
||||||
@ -64,6 +70,31 @@
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# With $PATH and $PYTHONPATH set to the %%buildroot,
|
||||||
|
# try to import the Python 3 module(s) given as command-line args or read from file (-f).
|
||||||
|
# Respect the custom values of %%py3_shebang_flags or set nothing if it's undefined.
|
||||||
|
# Filter and check import on only top-level modules using -t flag.
|
||||||
|
# Exclude unwanted modules by passing their globs to -e option.
|
||||||
|
# Useful as a smoke test in %%check when running tests is not feasible.
|
||||||
|
# Use spaces or commas as separators if providing list directly.
|
||||||
|
# Use newlines as separators if providing list in a file.
|
||||||
|
%py3_check_import(e:tf:) %{expand:\\\
|
||||||
|
PATH="%{buildroot}%{_bindir}:$PATH"\\\
|
||||||
|
PYTHONPATH="${PYTHONPATH:-%{buildroot}%{python3_sitearch}:%{buildroot}%{python3_sitelib}}"\\\
|
||||||
|
_PYTHONSITE="%{buildroot}%{python3_sitearch}:%{buildroot}%{python3_sitelib}"\\\
|
||||||
|
PYTHONDONTWRITEBYTECODE=1\\\
|
||||||
|
%{lua:
|
||||||
|
local command = "%{__python3} "
|
||||||
|
if rpm.expand("%{?py3_shebang_flags}") ~= "" then
|
||||||
|
command = command .. "-%{py3_shebang_flags}"
|
||||||
|
end
|
||||||
|
command = command .. " %{_rpmconfigdir}/redhat/import_all_modules.py "
|
||||||
|
-- handle multiline arguments correctly, see https://bugzilla.redhat.com/2018809
|
||||||
|
local args=rpm.expand('%{?**}'):gsub("[%s\\\\]*%s+", " ")
|
||||||
|
print(command .. args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# This only supports Python 3.5+ and will never work with Python 2.
|
# This only supports Python 3.5+ and will never work with Python 2.
|
||||||
# Hence, it has no Python version in the name.
|
# Hence, it has no Python version in the name.
|
||||||
%pycached() %{lua:
|
%pycached() %{lua:
|
||||||
@ -75,6 +106,7 @@
|
|||||||
pyminor = path:match("/python3.(%d+)/") or "*"
|
pyminor = path:match("/python3.(%d+)/") or "*"
|
||||||
dirname = path:match("(.*/)")
|
dirname = path:match("(.*/)")
|
||||||
modulename = path:match(".*/([^/]+).py")
|
modulename = path:match(".*/([^/]+).py")
|
||||||
|
-- %%python3_cache_tag is not used here because this macro supports not-installed CPythons
|
||||||
print("\\n" .. dirname .. "__pycache__/" .. modulename .. ".cpython-3" .. pyminor .. "{,.opt-?}.pyc")
|
print("\\n" .. dirname .. "__pycache__/" .. modulename .. ".cpython-3" .. pyminor .. "{,.opt-?}.pyc")
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
@ -86,4 +118,5 @@
|
|||||||
PATH="%{buildroot}%{_bindir}:$PATH"\\\
|
PATH="%{buildroot}%{_bindir}:$PATH"\\\
|
||||||
PYTHONPATH="${PYTHONPATH:-%{buildroot}%{python3_sitearch}:%{buildroot}%{python3_sitelib}}"\\\
|
PYTHONPATH="${PYTHONPATH:-%{buildroot}%{python3_sitearch}:%{buildroot}%{python3_sitelib}}"\\\
|
||||||
PYTHONDONTWRITEBYTECODE=1\\\
|
PYTHONDONTWRITEBYTECODE=1\\\
|
||||||
|
%{?__pytest_addopts:PYTEST_ADDOPTS="${PYTEST_ADDOPTS:-} %{__pytest_addopts}"}\\\
|
||||||
%__pytest}
|
%__pytest}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
Name: python-rpm-macros
|
Name: python-rpm-macros
|
||||||
Summary: The common Python RPM macros
|
Summary: The common Python RPM macros
|
||||||
|
|
||||||
|
URL: https://src.fedoraproject.org/rpms/python-rpm-macros/
|
||||||
|
|
||||||
# Macros:
|
# Macros:
|
||||||
Source101: macros.python
|
Source101: macros.python
|
||||||
Source102: macros.python-srpm
|
Source102: macros.python-srpm
|
||||||
@ -13,16 +15,41 @@ Source201: python.lua
|
|||||||
# Python code
|
# Python code
|
||||||
%global compileall2_version 0.7.1
|
%global compileall2_version 0.7.1
|
||||||
Source301: https://github.com/fedora-python/compileall2/raw/v%{compileall2_version}/compileall2.py
|
Source301: https://github.com/fedora-python/compileall2/raw/v%{compileall2_version}/compileall2.py
|
||||||
|
Source302: import_all_modules.py
|
||||||
|
|
||||||
# macros and lua: MIT, compileall2.py: PSFv2
|
# BRP scripts
|
||||||
License: MIT and Python
|
# This one is from redhat-rpm-config < 190
|
||||||
|
# A new upstream is forming in https://github.com/rpm-software-management/python-rpm-packaging/blob/main/scripts/brp-python-bytecompile
|
||||||
|
# But our version is riddled with Fedora-isms
|
||||||
|
# We might eventually move to upstream source + Fedora patches, but we are not there yet
|
||||||
|
Source401: brp-python-bytecompile
|
||||||
|
# This one is from https://github.com/rpm-software-management/python-rpm-packaging/blob/main/scripts/brp-python-hardlink
|
||||||
|
# But we don't use a link in case it changes in upstream, there are no "versions" there yet
|
||||||
|
# This was removed from RPM 4.17+ so we maintain it here instead
|
||||||
|
Source402: brp-python-hardlink
|
||||||
|
# This one is from redhat-rpm-config < 190
|
||||||
|
# It has no upstream yet
|
||||||
|
Source403: brp-fix-pyc-reproducibility
|
||||||
|
|
||||||
|
# macros and lua: MIT
|
||||||
|
# import_all_modules.py: MIT
|
||||||
|
# compileall2.py: PSFv2
|
||||||
|
# brp scripts: GPLv2+
|
||||||
|
License: MIT and Python and GPLv2+
|
||||||
|
|
||||||
# The package version MUST be always the same as %%{__default_python3_version}.
|
# The package version MUST be always the same as %%{__default_python3_version}.
|
||||||
# To have only one source of truth, we load the macro and use it.
|
# To have only one source of truth, we load the macro and use it.
|
||||||
# The macro is defined in python-srpm-macros.
|
# The macro is defined in python-srpm-macros.
|
||||||
%{?load:%{SOURCE102}}
|
%{lua:
|
||||||
|
if posix.stat(rpm.expand('%{SOURCE102}')) then
|
||||||
|
rpm.load(rpm.expand('%{SOURCE102}'))
|
||||||
|
elseif posix.stat('macros.python-srpm') then
|
||||||
|
-- something is parsing the spec without _sourcedir macro properly set
|
||||||
|
rpm.load('macros.python-srpm')
|
||||||
|
end
|
||||||
|
}
|
||||||
Version: %{__default_python3_version}
|
Version: %{__default_python3_version}
|
||||||
Release: 36%{?dist}
|
Release: 4%{?dist}
|
||||||
|
|
||||||
BuildArch: noarch
|
BuildArch: noarch
|
||||||
|
|
||||||
@ -31,6 +58,12 @@ BuildArch: noarch
|
|||||||
# For compileall2.py
|
# For compileall2.py
|
||||||
Requires: python-srpm-macros = %{version}-%{release}
|
Requires: python-srpm-macros = %{version}-%{release}
|
||||||
|
|
||||||
|
# The packages are called python(3)-(s)rpm-macros
|
||||||
|
# We never want python3-rpm-macros to provide python-rpm-macros
|
||||||
|
# We opt out from all Python name-based automatic provides and obsoletes
|
||||||
|
%undefine __pythonname_provides
|
||||||
|
%undefine __pythonname_obsoletes
|
||||||
|
|
||||||
%description
|
%description
|
||||||
This package contains the unversioned Python RPM macros, that most
|
This package contains the unversioned Python RPM macros, that most
|
||||||
implementations should rely on.
|
implementations should rely on.
|
||||||
@ -43,7 +76,8 @@ python?-devel packages require it. So install a python-devel package instead.
|
|||||||
Summary: RPM macros for building Python source packages
|
Summary: RPM macros for building Python source packages
|
||||||
|
|
||||||
# For directory structure and flags macros
|
# For directory structure and flags macros
|
||||||
Requires: redhat-rpm-config
|
# Versions before 190 contained some brp scripts moved into python-srpm-macros
|
||||||
|
Requires: redhat-rpm-config >= 190
|
||||||
|
|
||||||
# We bundle our own software here :/
|
# We bundle our own software here :/
|
||||||
Provides: bundled(python3dist(compileall2)) = %{compileall2_version}
|
Provides: bundled(python3dist(compileall2)) = %{compileall2_version}
|
||||||
@ -58,7 +92,7 @@ Summary: RPM macros for building Python 3 packages
|
|||||||
# For %%__python3 and %%python3
|
# For %%__python3 and %%python3
|
||||||
Requires: python-srpm-macros = %{version}-%{release}
|
Requires: python-srpm-macros = %{version}-%{release}
|
||||||
|
|
||||||
# For %%py_setup
|
# For %%py_setup and import_all_modules.py
|
||||||
Requires: python-rpm-macros = %{version}-%{release}
|
Requires: python-rpm-macros = %{version}-%{release}
|
||||||
|
|
||||||
%description -n python3-rpm-macros
|
%description -n python3-rpm-macros
|
||||||
@ -79,15 +113,37 @@ install -p -m 644 -t %{buildroot}%{_rpmluadir}/fedora/srpm python.lua
|
|||||||
|
|
||||||
mkdir -p %{buildroot}%{_rpmconfigdir}/redhat
|
mkdir -p %{buildroot}%{_rpmconfigdir}/redhat
|
||||||
install -m 644 compileall2.py %{buildroot}%{_rpmconfigdir}/redhat/
|
install -m 644 compileall2.py %{buildroot}%{_rpmconfigdir}/redhat/
|
||||||
|
install -m 644 import_all_modules.py %{buildroot}%{_rpmconfigdir}/redhat/
|
||||||
|
|
||||||
|
install -m 755 brp-* %{buildroot}%{_rpmconfigdir}/redhat/
|
||||||
|
|
||||||
|
|
||||||
|
# We define our own BRPs here to use the ones from the %%{buildroot},
|
||||||
|
# that way, this package can be built when it includes them for the first time.
|
||||||
|
# It also ensures that:
|
||||||
|
# - our BRPs can execute
|
||||||
|
# - if our BRPs affect this package, we don't need to build it twice
|
||||||
|
%global __brp_python_bytecompile %{buildroot}%{__brp_python_bytecompile}
|
||||||
|
%global __brp_python_hardlink %{buildroot}%{__brp_python_hardlink}
|
||||||
|
%global __brp_fix_pyc_reproducibility %{buildroot}%{__brp_fix_pyc_reproducibility}
|
||||||
|
|
||||||
|
|
||||||
|
%check
|
||||||
|
# no macros in comments
|
||||||
|
grep -E '^#[^%%]*%%[^%%]' %{buildroot}%{rpmmacrodir}/macros.* && exit 1 || true
|
||||||
|
|
||||||
|
|
||||||
%files
|
%files
|
||||||
%{rpmmacrodir}/macros.python
|
%{rpmmacrodir}/macros.python
|
||||||
%{rpmmacrodir}/macros.pybytecompile
|
%{rpmmacrodir}/macros.pybytecompile
|
||||||
|
%{_rpmconfigdir}/redhat/import_all_modules.py
|
||||||
|
|
||||||
%files -n python-srpm-macros
|
%files -n python-srpm-macros
|
||||||
%{rpmmacrodir}/macros.python-srpm
|
%{rpmmacrodir}/macros.python-srpm
|
||||||
%{_rpmconfigdir}/redhat/compileall2.py
|
%{_rpmconfigdir}/redhat/compileall2.py
|
||||||
|
%{_rpmconfigdir}/redhat/brp-python-bytecompile
|
||||||
|
%{_rpmconfigdir}/redhat/brp-python-hardlink
|
||||||
|
%{_rpmconfigdir}/redhat/brp-fix-pyc-reproducibility
|
||||||
%{_rpmluadir}/fedora/srpm/python.lua
|
%{_rpmluadir}/fedora/srpm/python.lua
|
||||||
|
|
||||||
%files -n python3-rpm-macros
|
%files -n python3-rpm-macros
|
||||||
@ -95,6 +151,100 @@ install -m 644 compileall2.py %{buildroot}%{_rpmconfigdir}/redhat/
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Fri Jul 22 2022 Fedora Release Engineering <releng@fedoraproject.org> - 3.10-4
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
|
||||||
|
|
||||||
|
* Tue Jul 19 2022 Miro Hrončok <mhroncok@redhat.com> - 3.11-3
|
||||||
|
- Add "P" to %%py3_shbang_opts, %%py3_shbang_opts_nodash, %%py3_shebang_flags
|
||||||
|
and to %%py_shbang_opts, %%py_shbang_opts_nodash, %%py_shebang_flags
|
||||||
|
- https://fedoraproject.org/wiki/Changes/PythonSafePath
|
||||||
|
|
||||||
|
* Mon Jun 20 2022 Miro Hrončok <mhroncok@redhat.com> - 3.11-2
|
||||||
|
- Define %%python3_cache_tag / %%python_cache_tag, e.g. cpython-311
|
||||||
|
|
||||||
|
* Mon Jun 13 2022 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.11-1
|
||||||
|
- Update main Python to Python 3.11
|
||||||
|
- https://fedoraproject.org/wiki/Changes/Python3.11
|
||||||
|
|
||||||
|
* Thu May 26 2022 Owen Taylor <otaylor@redhat.com> - 3.10-18
|
||||||
|
- Support installing to %%{_prefix} other than /usr
|
||||||
|
|
||||||
|
* Tue Feb 08 2022 Tomas Orsava <torsava@redhat.com> - 3.10-17
|
||||||
|
- %%py_provides: Do not generate Obsoletes for names containing parentheses
|
||||||
|
|
||||||
|
* Mon Jan 31 2022 Miro Hrončok <mhroncok@redhat.com> - 3.10-16
|
||||||
|
- Explicitly opt-out from Python name-based provides and obsoletes generators
|
||||||
|
|
||||||
|
* Tue Dec 21 2021 Tomas Orsava <torsava@redhat.com> - 3.10-15
|
||||||
|
- Add lua helper functions to make it possible to automatically generate
|
||||||
|
Obsoletes tags
|
||||||
|
- Modify the %%py_provides macro to also generate Obsoletes tags on CentOS/RHEL
|
||||||
|
|
||||||
|
* Wed Dec 08 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-14
|
||||||
|
- Set %%__python3 value according to %%python3_pkgversion
|
||||||
|
I.e. when %%python3_pkgversion is 3.12, %%__python3 is /usr/bin/python3.12
|
||||||
|
|
||||||
|
* Mon Nov 01 2021 Karolina Surma <ksurma@redhat.com> - 3.10-13
|
||||||
|
- Fix multiline arguments processing for %%py_check_import
|
||||||
|
Resolves: rhbz#2018809
|
||||||
|
- Fix %%py_shebang_flags handling within %%py_check_import
|
||||||
|
Resolves: rhbz#2018615
|
||||||
|
- Process .pth files in buildroot's sitedirs in %%py_check_import
|
||||||
|
Resolves: rhbz#2018551
|
||||||
|
- Move import_all_modules.py from python-srpm-macros to python-rpm-macros
|
||||||
|
|
||||||
|
* Mon Oct 25 2021 Karolina Surma <ksurma@redhat.com> - 3.10-12
|
||||||
|
- Introduce -f (read from file) option to %%py{3}_check_import
|
||||||
|
- Introduce -t (filter top-level modules) option to %%py{3}_check_import
|
||||||
|
- Introduce -e (exclude module globs) option to %%py{3}_check_import
|
||||||
|
|
||||||
|
* Wed Oct 20 2021 Tomas Orsava <torsava@redhat.com> - 3.10-11
|
||||||
|
- Define a new macros %%python_wheel_dir and %%python_wheel_pkg_prefix
|
||||||
|
|
||||||
|
* Tue Oct 12 2021 Lumír Balhar <lbalhar@redhat.com> - 3.10-10
|
||||||
|
- Non-existing path in py_reproducible_pyc_path causes build to fail
|
||||||
|
Resolves: rhbz#2011056
|
||||||
|
|
||||||
|
* Thu Sep 09 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-9
|
||||||
|
- Set $RPM_BUILD_ROOT in %%{python3_...} macros
|
||||||
|
to allow selecting alternate sysconfig install scheme based on that variable
|
||||||
|
|
||||||
|
* Thu Sep 09 2021 Petr Viktorin <pviktori@redhat.com> - 3.10-8
|
||||||
|
- Use --hardlink-dupes in %%py_byte_compile and brp-python-bytecompile
|
||||||
|
(for Python 3)
|
||||||
|
- Resolves: rhbz#1977895
|
||||||
|
|
||||||
|
* Fri Jul 23 2021 Fedora Release Engineering <releng@fedoraproject.org> - 3.9-7
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
|
||||||
|
|
||||||
|
* Wed Jul 07 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-6
|
||||||
|
- Move Python related BuildRoot Policy scripts from redhat-rpm-config to python-srpm-macros
|
||||||
|
|
||||||
|
* Wed Jul 07 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-5
|
||||||
|
- Introduce %%py3_check_import
|
||||||
|
|
||||||
|
* Wed Jun 30 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-4
|
||||||
|
- Include brp-python-hardlink in python-srpm-macros since it is no longer in RPM 4.17+
|
||||||
|
|
||||||
|
* Mon Jun 28 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-3
|
||||||
|
- %%pytest: Set $PYTEST_ADDOPTS when %%{__pytest_addopts} is defined
|
||||||
|
- Related: rhzb#1935212
|
||||||
|
|
||||||
|
* Tue Jun 15 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-2
|
||||||
|
- Fix %%python_provide when fed python3.10-foo to obsolete python-foo instead of python--foo
|
||||||
|
|
||||||
|
* Tue Jun 01 2021 Miro Hrončok <mhroncok@redhat.com> - 3.10-1
|
||||||
|
- Update main Python to Python 3.10
|
||||||
|
- https://fedoraproject.org/wiki/Changes/Python3.10
|
||||||
|
|
||||||
|
* Tue Apr 27 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-38
|
||||||
|
- Escape %% symbols in macro files comments
|
||||||
|
- Fixes: rhbz#1953910
|
||||||
|
|
||||||
|
* Wed Apr 07 2021 Karolina Surma <ksurma@redhat.com> - 3.9-37
|
||||||
|
- Use sysconfig.get_path() to get %%python3_sitelib and %%python3_sitearch
|
||||||
|
- Fixes: rhbz#1946972
|
||||||
|
|
||||||
* Mon Mar 29 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-36
|
* Mon Mar 29 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-36
|
||||||
- Allow commas as argument separator for extras names in %%python_extras_subpkg
|
- Allow commas as argument separator for extras names in %%python_extras_subpkg
|
||||||
- Fixes: rhbz#1936486
|
- Fixes: rhbz#1936486
|
||||||
|
81
python.lua
81
python.lua
@ -2,22 +2,25 @@
|
|||||||
|
|
||||||
-- Determine alternate names provided from the given name.
|
-- Determine alternate names provided from the given name.
|
||||||
-- Used in pythonname provides generator, python_provide and py_provides.
|
-- Used in pythonname provides generator, python_provide and py_provides.
|
||||||
-- There are 2 rules:
|
-- If only_3_to_3_X is false/nil/unused there are 2 rules:
|
||||||
-- python3-foo -> python-foo, python3.X-foo
|
-- python3-foo -> python-foo, python3.X-foo
|
||||||
-- python3.X-foo -> python-foo, python3-foo
|
-- python3.X-foo -> python-foo, python3-foo
|
||||||
|
-- If only_3_to_3_X is true there is only 1 rule:
|
||||||
|
-- python3-foo -> python3.X-foo
|
||||||
-- There is no python-foo -> rule, python-foo packages are version agnostic.
|
-- There is no python-foo -> rule, python-foo packages are version agnostic.
|
||||||
-- Returns a table/array with strings. Empty when no rule matched.
|
-- Returns a table/array with strings. Empty when no rule matched.
|
||||||
local function python_altnames(name)
|
local function python_altnames(name, only_3_to_3_X)
|
||||||
local xy = rpm.expand('%{__default_python3_pkgversion}')
|
local xy = rpm.expand('%{__default_python3_pkgversion}')
|
||||||
local altnames = {}
|
local altnames = {}
|
||||||
local replaced
|
local replaced
|
||||||
-- NB: dash needs to be escaped!
|
-- NB: dash needs to be escaped!
|
||||||
if name:match('^python3%-') then
|
if name:match('^python3%-') then
|
||||||
for i, prefix in ipairs({'python-', 'python' .. xy .. '-'}) do
|
local prefixes = only_3_to_3_X and {} or {'python-'}
|
||||||
|
for i, prefix in ipairs({'python' .. xy .. '-', table.unpack(prefixes)}) do
|
||||||
replaced = name:gsub('^python3%-', prefix)
|
replaced = name:gsub('^python3%-', prefix)
|
||||||
table.insert(altnames, replaced)
|
table.insert(altnames, replaced)
|
||||||
end
|
end
|
||||||
elseif name:match('^python' .. xy .. '%-') then
|
elseif name:match('^python' .. xy .. '%-') and not only_3_to_3_X then
|
||||||
for i, prefix in ipairs({'python-', 'python3-'}) do
|
for i, prefix in ipairs({'python-', 'python3-'}) do
|
||||||
replaced = name:gsub('^python' .. xy .. '%-', prefix)
|
replaced = name:gsub('^python' .. xy .. '%-', prefix)
|
||||||
table.insert(altnames, replaced)
|
table.insert(altnames, replaced)
|
||||||
@ -27,42 +30,72 @@ local function python_altnames(name)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function __python_alttags(name, evr, tag_type)
|
||||||
|
-- for the "provides" tag_type we want also unversioned provides
|
||||||
|
local only_3_to_3_X = tag_type ~= "provides"
|
||||||
|
local operator = tag_type == "provides" and ' = ' or ' < '
|
||||||
|
|
||||||
|
-- global cache that tells what package NEVRs were already processed for the
|
||||||
|
-- given tag type
|
||||||
|
if __python_alttags_beenthere == nil then
|
||||||
|
__python_alttags_beenthere = {}
|
||||||
|
end
|
||||||
|
if __python_alttags_beenthere[tag_type] == nil then
|
||||||
|
__python_alttags_beenthere[tag_type] = {}
|
||||||
|
end
|
||||||
|
__python_alttags_beenthere[tag_type][name .. ' ' .. evr] = true
|
||||||
|
local alttags = {}
|
||||||
|
for i, altname in ipairs(python_altnames(name, only_3_to_3_X)) do
|
||||||
|
table.insert(alttags, altname .. operator .. evr)
|
||||||
|
end
|
||||||
|
return alttags
|
||||||
|
end
|
||||||
|
|
||||||
-- For any given name and epoch-version-release, return provides except self.
|
-- For any given name and epoch-version-release, return provides except self.
|
||||||
-- Uses python_altnames under the hood
|
-- Uses python_altnames under the hood
|
||||||
-- Returns a table/array with strings.
|
-- Returns a table/array with strings.
|
||||||
local function python_altprovides(name, evr)
|
local function python_altprovides(name, evr)
|
||||||
-- global cache that tells what provides were already processed
|
return __python_alttags(name, evr, "provides")
|
||||||
if __python_altnames_provides_beenthere == nil then
|
|
||||||
__python_altnames_provides_beenthere = {}
|
|
||||||
end
|
|
||||||
__python_altnames_provides_beenthere[name .. ' ' .. evr] = true
|
|
||||||
local altprovides = {}
|
|
||||||
for i, altname in ipairs(python_altnames(name)) do
|
|
||||||
table.insert(altprovides, altname .. ' = ' .. evr)
|
|
||||||
end
|
|
||||||
return altprovides
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- For any given name and epoch-version-release, return versioned obsoletes except self.
|
||||||
|
-- Uses python_altnames under the hood
|
||||||
|
-- Returns a table/array with strings.
|
||||||
|
local function python_altobsoletes(name, evr)
|
||||||
|
return __python_alttags(name, evr, "obsoletes")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function __python_alttags_once(name, evr, tag_type)
|
||||||
|
-- global cache that tells what provides were already processed
|
||||||
|
if __python_alttags_beenthere == nil
|
||||||
|
or __python_alttags_beenthere[tag_type] == nil
|
||||||
|
or __python_alttags_beenthere[tag_type][name .. ' ' .. evr] == nil then
|
||||||
|
return __python_alttags(name, evr, tag_type)
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Like python_altprovides but only return something once.
|
-- Like python_altprovides but only return something once.
|
||||||
-- For each argument can only be used once, returns nil otherwise.
|
-- For each argument can only be used once, returns nil otherwise.
|
||||||
-- Previous usage of python_altprovides counts as well.
|
-- Previous usage of python_altprovides counts as well.
|
||||||
local function python_altprovides_once(name, evr)
|
local function python_altprovides_once(name, evr)
|
||||||
-- global cache that tells what provides were already processed
|
return __python_alttags_once(name, evr, "provides")
|
||||||
if __python_altnames_provides_beenthere == nil then
|
end
|
||||||
__python_altnames_provides_beenthere = {}
|
|
||||||
end
|
-- Like python_altobsoletes but only return something once.
|
||||||
if __python_altnames_provides_beenthere[name .. ' ' .. evr] == nil then
|
-- For each argument can only be used once, returns nil otherwise.
|
||||||
__python_altnames_provides_beenthere[name .. ' ' .. evr] = true
|
-- Previous usage of python_altobsoletes counts as well.
|
||||||
return python_altprovides(name, evr)
|
local function python_altobsoletes_once(name, evr)
|
||||||
else
|
return __python_alttags_once(name, evr, "obsoletes")
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
python_altnames = python_altnames,
|
python_altnames = python_altnames,
|
||||||
python_altprovides = python_altprovides,
|
python_altprovides = python_altprovides,
|
||||||
|
python_altobsoletes = python_altobsoletes,
|
||||||
python_altprovides_once = python_altprovides_once,
|
python_altprovides_once = python_altprovides_once,
|
||||||
|
python_altobsoletes_once = python_altobsoletes_once,
|
||||||
}
|
}
|
||||||
|
7
rpminspect.yaml
Normal file
7
rpminspect.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# completely disabled inspections:
|
||||||
|
inspections:
|
||||||
|
# there is no upstream and the files are changed from time to time
|
||||||
|
addedfiles: off
|
||||||
|
changedfiles: off
|
||||||
|
filesize: off
|
||||||
|
upstream: off
|
@ -1,11 +1,18 @@
|
|||||||
%global basedir /opt/test/byte_compilation
|
%global basedir /opt/test/byte_compilation
|
||||||
|
|
||||||
|
# We have 3 different ways of bytecompiling: for 3.9+, 3.4-3.8, and 2.7
|
||||||
|
# Test with a representative of each.
|
||||||
|
%global python36_sitelib /usr/lib/python3.6/site-packages
|
||||||
|
%global python27_sitelib /usr/lib/python2.7/site-packages
|
||||||
|
|
||||||
Name: pythontest
|
Name: pythontest
|
||||||
Version: 0
|
Version: 0
|
||||||
Release: 0
|
Release: 0
|
||||||
Summary: ...
|
Summary: ...
|
||||||
License: MIT
|
License: MIT
|
||||||
BuildRequires: python3-devel
|
BuildRequires: python3-devel
|
||||||
|
BuildRequires: python3.6
|
||||||
|
BuildRequires: python2.7
|
||||||
|
|
||||||
%description
|
%description
|
||||||
...
|
...
|
||||||
@ -19,15 +26,48 @@ echo "print()" > %{buildroot}%{basedir}/directory/to/test/recursion/file_in_dir.
|
|||||||
%py_byte_compile %{python3} %{buildroot}%{basedir}/file.py
|
%py_byte_compile %{python3} %{buildroot}%{basedir}/file.py
|
||||||
%py_byte_compile %{python3} %{buildroot}%{basedir}/directory
|
%py_byte_compile %{python3} %{buildroot}%{basedir}/directory
|
||||||
|
|
||||||
|
# Files in sitelib are compiled automatically by brp-python-bytecompile
|
||||||
|
mkdir -p %{buildroot}%{python3_sitelib}/directory/
|
||||||
|
echo "print()" > %{buildroot}%{python3_sitelib}/directory/file.py
|
||||||
|
|
||||||
|
mkdir -p %{buildroot}%{python36_sitelib}/directory/
|
||||||
|
echo "print()" > %{buildroot}%{python36_sitelib}/directory/file.py
|
||||||
|
|
||||||
|
mkdir -p %{buildroot}%{python27_sitelib}/directory/
|
||||||
|
echo "print()" > %{buildroot}%{python27_sitelib}/directory/file.py
|
||||||
|
|
||||||
%check
|
%check
|
||||||
|
LOCATIONS="
|
||||||
|
%{buildroot}%{basedir}
|
||||||
|
%{buildroot}%{python3_sitelib}/directory/
|
||||||
|
%{buildroot}%{python36_sitelib}/directory/
|
||||||
|
%{buildroot}%{python27_sitelib}/directory/
|
||||||
|
"
|
||||||
|
|
||||||
# Count .py and .pyc files
|
# Count .py and .pyc files
|
||||||
PY=$(find %{buildroot}%{basedir} -name "*.py" | wc -l)
|
PY=$(find $LOCATIONS -name "*.py" | wc -l)
|
||||||
PYC=$(find %{buildroot}%{basedir} -name "*.pyc" | wc -l)
|
PYC=$(find $LOCATIONS -name "*.py[co]" | wc -l)
|
||||||
|
|
||||||
|
# We should have 5 .py files (3 for python3, one each for 3.6 & 2.7)
|
||||||
|
test $PY -eq 5
|
||||||
|
|
||||||
# Every .py file should be byte-compiled to two .pyc files (optimization level 0 and 1)
|
# Every .py file should be byte-compiled to two .pyc files (optimization level 0 and 1)
|
||||||
# so we should have two times more .pyc files than .py files
|
# so we should have two times more .pyc files than .py files
|
||||||
test $(expr $PY \* 2) -eq $PYC
|
test $(expr $PY \* 2) -eq $PYC
|
||||||
|
|
||||||
|
# In this case the .pyc files should be identical across omtimization levels
|
||||||
|
# (they don't use docstrings and assert staements)
|
||||||
|
# So they should be hardlinked; the number of distinct inodes should match the
|
||||||
|
# number of source files. (Or be smaller, if the dupe detection is done
|
||||||
|
# across all files.)
|
||||||
|
|
||||||
|
INODES=$(stat --format %i $(find $LOCATIONS -name "*.py[co]") | sort -u | wc -l)
|
||||||
|
test $PY -ge $INODES
|
||||||
|
|
||||||
|
|
||||||
%files
|
%files
|
||||||
%pycached %{basedir}/file.py
|
%pycached %{basedir}/file.py
|
||||||
%pycached %{basedir}/directory/to/test/recursion/file_in_dir.py
|
%pycached %{basedir}/directory/to/test/recursion/file_in_dir.py
|
||||||
|
%pycached %{python3_sitelib}/directory/file.py
|
||||||
|
%pycached %{python36_sitelib}/directory/file.py
|
||||||
|
%{python27_sitelib}/directory/file.py*
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import platform
|
import platform
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
@ -15,7 +16,8 @@ XY = f'{sys.version_info[0]}{sys.version_info[1]}'
|
|||||||
# You can use * if you escape it from your Shell:
|
# You can use * if you escape it from your Shell:
|
||||||
# TESTED_FILES='macros.*' pytest -v
|
# TESTED_FILES='macros.*' pytest -v
|
||||||
# Remember that some tests might need more macros files than just
|
# Remember that some tests might need more macros files than just
|
||||||
# the local ones.
|
# the local ones. You might need to use:
|
||||||
|
# TESTED_FILES='/usr/lib/rpm/macros:/usr/lib/rpm/platform/x86_64-linux/macros:macros.*'
|
||||||
TESTED_FILES = os.getenv("TESTED_FILES", None)
|
TESTED_FILES = os.getenv("TESTED_FILES", None)
|
||||||
|
|
||||||
|
|
||||||
@ -38,6 +40,56 @@ def rpm_eval(expression, fails=False, **kwargs):
|
|||||||
return cp.stdout.strip().splitlines()
|
return cp.stdout.strip().splitlines()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def lib():
|
||||||
|
lib_eval = rpm_eval("%_lib")[0]
|
||||||
|
if lib_eval == "%_lib" and TESTED_FILES:
|
||||||
|
raise ValueError(
|
||||||
|
"%_lib is not resolved to an actual value. "
|
||||||
|
"You may want to include /usr/lib/rpm/platform/x86_64-linux/macros to TESTED_FILES."
|
||||||
|
)
|
||||||
|
return lib_eval
|
||||||
|
|
||||||
|
|
||||||
|
def get_alt_x_y():
|
||||||
|
"""
|
||||||
|
Some tests require alternate Python version to be installed.
|
||||||
|
In order to allow any Python version (or none at all),
|
||||||
|
this function/fixture exists.
|
||||||
|
You can control the behavior by setting the $ALTERNATE_PYTHON_VERSION
|
||||||
|
environment variable to X.Y (e.g. 3.6) or SKIP.
|
||||||
|
The environment variable must be set.
|
||||||
|
"""
|
||||||
|
env_name = "ALTERNATE_PYTHON_VERSION"
|
||||||
|
alternate_python_version = os.getenv(env_name, "")
|
||||||
|
if alternate_python_version.upper() == "SKIP":
|
||||||
|
pytest.skip(f"${env_name} set to SKIP")
|
||||||
|
if not alternate_python_version:
|
||||||
|
raise ValueError(f"${env_name} must be set, "
|
||||||
|
f"set it to SKIP if you want to skip tests that "
|
||||||
|
f"require alternate Python version.")
|
||||||
|
if not re.match(r"^\d+\.\d+$", alternate_python_version):
|
||||||
|
raise ValueError(f"${env_name} must be X.Y")
|
||||||
|
return alternate_python_version
|
||||||
|
|
||||||
|
|
||||||
|
def get_alt_xy():
|
||||||
|
"""
|
||||||
|
Same as get_alt_x_y() but without a dot
|
||||||
|
"""
|
||||||
|
return get_alt_x_y().replace(".", "")
|
||||||
|
|
||||||
|
|
||||||
|
# We don't use decorators, to be able to call the functions directly
|
||||||
|
alt_x_y = pytest.fixture(scope="session")(get_alt_x_y)
|
||||||
|
alt_xy = pytest.fixture(scope="session")(get_alt_xy)
|
||||||
|
|
||||||
|
|
||||||
|
# https://fedoraproject.org/wiki/Changes/PythonSafePath
|
||||||
|
def safe_path_flag(x_y):
|
||||||
|
return 'P' if tuple(int(i) for i in x_y.split('.')) >= (3, 11) else ''
|
||||||
|
|
||||||
|
|
||||||
def shell_stdout(script):
|
def shell_stdout(script):
|
||||||
return subprocess.check_output(script,
|
return subprocess.check_output(script,
|
||||||
env={**os.environ, 'LANG': 'C.utf-8'},
|
env={**os.environ, 'LANG': 'C.utf-8'},
|
||||||
@ -45,6 +97,17 @@ def shell_stdout(script):
|
|||||||
shell=True).rstrip()
|
shell=True).rstrip()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('macro', ['%__python3', '%python3'])
|
||||||
|
def test_python3(macro):
|
||||||
|
assert rpm_eval(macro) == ['/usr/bin/python3']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('macro', ['%__python3', '%python3'])
|
||||||
|
@pytest.mark.parametrize('pkgversion', ['3', '3.9', '3.12'])
|
||||||
|
def test_python3_with_pkgversion(macro, pkgversion):
|
||||||
|
assert rpm_eval(macro, python3_pkgversion=pkgversion) == [f'/usr/bin/python{pkgversion}']
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('argument, result', [
|
@pytest.mark.parametrize('argument, result', [
|
||||||
('a', 'a'),
|
('a', 'a'),
|
||||||
('a-a', 'a-a'),
|
('a-a', 'a-a'),
|
||||||
@ -69,8 +132,8 @@ def test_py3_dist():
|
|||||||
assert rpm_eval(f'%py3_dist Aha[Boom] a') == ['python3dist(aha[boom]) python3dist(a)']
|
assert rpm_eval(f'%py3_dist Aha[Boom] a') == ['python3dist(aha[boom]) python3dist(a)']
|
||||||
|
|
||||||
|
|
||||||
def test_py3_dist_with_python3_pkgversion_redefined():
|
def test_py3_dist_with_python3_pkgversion_redefined(alt_x_y):
|
||||||
assert rpm_eval(f'%py3_dist Aha[Boom] a', python3_pkgversion="3.6") == ['python3.6dist(aha[boom]) python3.6dist(a)']
|
assert rpm_eval(f'%py3_dist Aha[Boom] a', python3_pkgversion=alt_x_y) == [f'python{alt_x_y}dist(aha[boom]) python{alt_x_y}dist(a)']
|
||||||
|
|
||||||
|
|
||||||
def test_python_provide_python():
|
def test_python_provide_python():
|
||||||
@ -119,69 +182,122 @@ def test_python_provide_doubleuse():
|
|||||||
assert len(set(lines)) == 3
|
assert len(set(lines)) == 3
|
||||||
|
|
||||||
|
|
||||||
def test_py_provides_python():
|
@pytest.mark.parametrize('rhel', [None, 10])
|
||||||
lines = rpm_eval('%py_provides python-foo', version='6', release='1.fc66')
|
def test_py_provides_python(rhel):
|
||||||
|
lines = rpm_eval('%py_provides python-foo', version='6', release='1.fc66', rhel=rhel)
|
||||||
assert 'Provides: python-foo = 6-1.fc66' in lines
|
assert 'Provides: python-foo = 6-1.fc66' in lines
|
||||||
assert len(lines) == 1
|
assert len(lines) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_py_provides_whatever():
|
@pytest.mark.parametrize('rhel', [None, 12])
|
||||||
lines = rpm_eval('%py_provides whatever', version='6', release='1.fc66')
|
def test_py_provides_whatever(rhel):
|
||||||
|
lines = rpm_eval('%py_provides whatever', version='6', release='1.fc66', rhel=rhel)
|
||||||
assert 'Provides: whatever = 6-1.fc66' in lines
|
assert 'Provides: whatever = 6-1.fc66' in lines
|
||||||
assert len(lines) == 1
|
assert len(lines) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_py_provides_python3():
|
@pytest.mark.parametrize('rhel', [None, 9])
|
||||||
lines = rpm_eval('%py_provides python3-foo', version='6', release='1.fc66')
|
def test_py_provides_python3(rhel):
|
||||||
|
lines = rpm_eval('%py_provides python3-foo', version='6', release='1.fc66', rhel=rhel)
|
||||||
assert 'Provides: python3-foo = 6-1.fc66' in lines
|
assert 'Provides: python3-foo = 6-1.fc66' in lines
|
||||||
assert 'Provides: python-foo = 6-1.fc66' in lines
|
assert 'Provides: python-foo = 6-1.fc66' in lines
|
||||||
assert f'Provides: python{X_Y}-foo = 6-1.fc66' in lines
|
assert f'Provides: python{X_Y}-foo = 6-1.fc66' in lines
|
||||||
|
if rhel:
|
||||||
|
assert f'Obsoletes: python{X_Y}-foo < 6-1.fc66' in lines
|
||||||
|
assert len(lines) == 4
|
||||||
|
else:
|
||||||
assert len(lines) == 3
|
assert len(lines) == 3
|
||||||
|
|
||||||
|
|
||||||
def test_py_provides_python3_epoched():
|
@pytest.mark.parametrize('rhel', [None, 9])
|
||||||
lines = rpm_eval('%py_provides python3-foo', epoch='1', version='6', release='1.fc66')
|
def test_py_provides_python3_with_isa(rhel):
|
||||||
|
lines = rpm_eval('%py_provides python3-foo(x86_64)', version='6', release='1.fc66', rhel=rhel)
|
||||||
|
assert 'Provides: python3-foo(x86_64) = 6-1.fc66' in lines
|
||||||
|
assert 'Provides: python-foo(x86_64) = 6-1.fc66' in lines
|
||||||
|
assert f'Provides: python{X_Y}-foo(x86_64) = 6-1.fc66' in lines
|
||||||
|
assert f'Obsoletes: python{X_Y}-foo(x86_64) < 6-1.fc66' not in lines
|
||||||
|
assert len(lines) == 3
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('rhel', [None, 13])
|
||||||
|
def test_py_provides_python3_epoched(rhel):
|
||||||
|
lines = rpm_eval('%py_provides python3-foo', epoch='1', version='6', release='1.fc66', rhel=rhel)
|
||||||
assert 'Provides: python3-foo = 1:6-1.fc66' in lines
|
assert 'Provides: python3-foo = 1:6-1.fc66' in lines
|
||||||
assert 'Provides: python-foo = 1:6-1.fc66' in lines
|
assert 'Provides: python-foo = 1:6-1.fc66' in lines
|
||||||
assert f'Provides: python{X_Y}-foo = 1:6-1.fc66' in lines
|
assert f'Provides: python{X_Y}-foo = 1:6-1.fc66' in lines
|
||||||
|
if rhel:
|
||||||
|
assert f'Obsoletes: python{X_Y}-foo < 1:6-1.fc66' in lines
|
||||||
|
assert len(lines) == 4
|
||||||
|
else:
|
||||||
assert len(lines) == 3
|
assert len(lines) == 3
|
||||||
|
|
||||||
|
|
||||||
def test_py_provides_python3X():
|
@pytest.mark.parametrize('rhel', [None, 13])
|
||||||
lines = rpm_eval(f'%py_provides python{X_Y}-foo', version='6', release='1.fc66')
|
def test_py_provides_python3X(rhel):
|
||||||
|
lines = rpm_eval(f'%py_provides python{X_Y}-foo', version='6', release='1.fc66', rhel=rhel)
|
||||||
assert f'Provides: python{X_Y}-foo = 6-1.fc66' in lines
|
assert f'Provides: python{X_Y}-foo = 6-1.fc66' in lines
|
||||||
assert 'Provides: python-foo = 6-1.fc66' in lines
|
assert 'Provides: python-foo = 6-1.fc66' in lines
|
||||||
assert 'Provides: python3-foo = 6-1.fc66' in lines
|
assert 'Provides: python3-foo = 6-1.fc66' in lines
|
||||||
assert len(lines) == 3
|
assert len(lines) == 3
|
||||||
|
|
||||||
|
|
||||||
def test_py_provides_python3X_epoched():
|
@pytest.mark.parametrize('rhel', [None, 27])
|
||||||
lines = rpm_eval(f'%py_provides python{X_Y}-foo', epoch='1', version='6', release='1.fc66')
|
def test_py_provides_python3X_epoched(rhel):
|
||||||
|
lines = rpm_eval(f'%py_provides python{X_Y}-foo', epoch='1', version='6', release='1.fc66', rhel=rhel)
|
||||||
assert f'Provides: python{X_Y}-foo = 1:6-1.fc66' in lines
|
assert f'Provides: python{X_Y}-foo = 1:6-1.fc66' in lines
|
||||||
assert 'Provides: python-foo = 1:6-1.fc66' in lines
|
assert 'Provides: python-foo = 1:6-1.fc66' in lines
|
||||||
assert 'Provides: python3-foo = 1:6-1.fc66' in lines
|
assert 'Provides: python3-foo = 1:6-1.fc66' in lines
|
||||||
assert len(lines) == 3
|
assert len(lines) == 3
|
||||||
|
|
||||||
|
|
||||||
def test_py_provides_doubleuse():
|
@pytest.mark.parametrize('rhel', [None, 2])
|
||||||
|
def test_py_provides_doubleuse(rhel):
|
||||||
lines = rpm_eval('%{py_provides python3-foo}%{py_provides python3-foo}',
|
lines = rpm_eval('%{py_provides python3-foo}%{py_provides python3-foo}',
|
||||||
version='6', release='1.fc66')
|
version='6', release='1.fc66', rhel=rhel)
|
||||||
assert 'Provides: python3-foo = 6-1.fc66' in lines
|
assert 'Provides: python3-foo = 6-1.fc66' in lines
|
||||||
assert 'Provides: python-foo = 6-1.fc66' in lines
|
assert 'Provides: python-foo = 6-1.fc66' in lines
|
||||||
assert f'Provides: python{X_Y}-foo = 6-1.fc66' in lines
|
assert f'Provides: python{X_Y}-foo = 6-1.fc66' in lines
|
||||||
|
if rhel:
|
||||||
|
assert f'Obsoletes: python{X_Y}-foo < 6-1.fc66' in lines
|
||||||
|
assert len(lines) == 8
|
||||||
|
assert len(set(lines)) == 4
|
||||||
|
else:
|
||||||
assert len(lines) == 6
|
assert len(lines) == 6
|
||||||
assert len(set(lines)) == 3
|
assert len(set(lines)) == 3
|
||||||
|
|
||||||
|
|
||||||
def test_py_provides_with_evr():
|
@pytest.mark.parametrize('rhel', [None, 2])
|
||||||
|
def test_py_provides_with_evr(rhel):
|
||||||
lines = rpm_eval('%py_provides python3-foo 123',
|
lines = rpm_eval('%py_provides python3-foo 123',
|
||||||
version='6', release='1.fc66')
|
version='6', release='1.fc66', rhel=rhel)
|
||||||
assert 'Provides: python3-foo = 123' in lines
|
assert 'Provides: python3-foo = 123' in lines
|
||||||
assert 'Provides: python-foo = 123' in lines
|
assert 'Provides: python-foo = 123' in lines
|
||||||
assert f'Provides: python{X_Y}-foo = 123' in lines
|
assert f'Provides: python{X_Y}-foo = 123' in lines
|
||||||
|
if rhel:
|
||||||
|
assert f'Obsoletes: python{X_Y}-foo < 123' in lines
|
||||||
|
assert len(lines) == 4
|
||||||
|
else:
|
||||||
assert len(lines) == 3
|
assert len(lines) == 3
|
||||||
|
|
||||||
|
|
||||||
|
def test_python_wheel_pkg_prefix():
|
||||||
|
assert rpm_eval('%python_wheel_pkg_prefix', fedora='44', rhel=None, eln=None) == ['python']
|
||||||
|
assert rpm_eval('%python_wheel_pkg_prefix', fedora='44', rhel=None, eln=None, python3_pkgversion='3.9') == ['python']
|
||||||
|
assert rpm_eval('%python_wheel_pkg_prefix', fedora=None, rhel='1', eln='1') == ['python']
|
||||||
|
assert rpm_eval('%python_wheel_pkg_prefix', fedora=None, rhel='1', eln=None) == ['python3']
|
||||||
|
assert rpm_eval('%python_wheel_pkg_prefix', fedora=None, rhel='1', eln=None, python3_pkgversion='3.10') == ['python3.10']
|
||||||
|
assert rpm_eval('%python_wheel_pkg_prefix', fedora=None, rhel='1', eln=None, python3_pkgversion='3.11') == ['python3.11']
|
||||||
|
|
||||||
|
|
||||||
|
def test_python_wheel_dir():
|
||||||
|
assert rpm_eval('%python_wheel_dir', fedora='44', rhel=None, eln=None) == ['/usr/share/python-wheels']
|
||||||
|
assert rpm_eval('%python_wheel_dir', fedora='44', rhel=None, eln=None, python3_pkgversion='3.9') == ['/usr/share/python-wheels']
|
||||||
|
assert rpm_eval('%python_wheel_dir', fedora=None, rhel='1', eln='1') == ['/usr/share/python-wheels']
|
||||||
|
assert rpm_eval('%python_wheel_dir', fedora=None, rhel='1', eln=None) == ['/usr/share/python3-wheels']
|
||||||
|
assert rpm_eval('%python_wheel_dir', fedora=None, rhel='1', eln=None, python3_pkgversion='3.10') == ['/usr/share/python3.10-wheels']
|
||||||
|
assert rpm_eval('%python_wheel_dir', fedora=None, rhel='1', eln=None, python3_pkgversion='3.11') == ['/usr/share/python3.11-wheels']
|
||||||
|
|
||||||
|
|
||||||
def test_pytest_passes_options_naturally():
|
def test_pytest_passes_options_naturally():
|
||||||
lines = rpm_eval('%pytest -k foo')
|
lines = rpm_eval('%pytest -k foo')
|
||||||
assert '/usr/bin/pytest -k foo' in lines[-1]
|
assert '/usr/bin/pytest -k foo' in lines[-1]
|
||||||
@ -195,62 +311,99 @@ def test_pytest_different_command():
|
|||||||
def test_pytest_command_suffix():
|
def test_pytest_command_suffix():
|
||||||
lines = rpm_eval('%pytest -v')
|
lines = rpm_eval('%pytest -v')
|
||||||
assert '/usr/bin/pytest -v' in lines[-1]
|
assert '/usr/bin/pytest -v' in lines[-1]
|
||||||
lines = rpm_eval('%pytest -v', python3_pkgversion="3.6", python3_version="3.6")
|
|
||||||
assert '/usr/bin/pytest-3.6 -v' in lines[-1]
|
# this test does not require alternate Pythons to be installed
|
||||||
|
@pytest.mark.parametrize('version', ['3.6', '3.7', '3.12'])
|
||||||
|
def test_pytest_command_suffix_alternate_pkgversion(version):
|
||||||
|
lines = rpm_eval('%pytest -v', python3_pkgversion=version, python3_version=version)
|
||||||
|
assert f'/usr/bin/pytest-{version} -v' in lines[-1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_pytest_undefined_addopts_are_not_set():
|
||||||
|
lines = rpm_eval('%pytest', __pytest_addopts=None)
|
||||||
|
assert 'PYTEST_ADDOPTS' not in '\n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pytest_defined_addopts_are_set():
|
||||||
|
lines = rpm_eval('%pytest', __pytest_addopts="--ignore=stuff")
|
||||||
|
assert 'PYTEST_ADDOPTS="${PYTEST_ADDOPTS:-} --ignore=stuff"' in '\n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('__pytest_addopts', ['--macronized-option', 'x y z', None])
|
||||||
|
def test_pytest_addopts_preserves_envvar(__pytest_addopts):
|
||||||
|
# this is the line a packager might put in the spec file before running %pytest:
|
||||||
|
spec_line = 'export PYTEST_ADDOPTS="--exported-option1 --exported-option2"'
|
||||||
|
|
||||||
|
# instead of actually running /usr/bin/pytest,
|
||||||
|
# we run a small shell script that echoes the tested value for inspection
|
||||||
|
lines = rpm_eval('%pytest', __pytest_addopts=__pytest_addopts,
|
||||||
|
__pytest="sh -c 'echo $PYTEST_ADDOPTS'")
|
||||||
|
|
||||||
|
echoed = shell_stdout('\n'.join([spec_line] + lines))
|
||||||
|
|
||||||
|
# assert all values were echoed
|
||||||
|
assert '--exported-option1' in echoed
|
||||||
|
assert '--exported-option2' in echoed
|
||||||
|
if __pytest_addopts is not None:
|
||||||
|
assert __pytest_addopts in echoed
|
||||||
|
|
||||||
|
# assert the options are separated
|
||||||
|
assert 'option--' not in echoed
|
||||||
|
assert 'z--' not in echoed
|
||||||
|
|
||||||
|
|
||||||
def test_pypi_source_default_name():
|
def test_pypi_source_default_name():
|
||||||
url = rpm_eval('%pypi_source',
|
urls = rpm_eval('%pypi_source',
|
||||||
name='foo', version='6')[0]
|
name='foo', version='6')
|
||||||
assert url == 'https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz'
|
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz']
|
||||||
|
|
||||||
|
|
||||||
def test_pypi_source_default_srcname():
|
def test_pypi_source_default_srcname():
|
||||||
url = rpm_eval('%pypi_source',
|
urls = rpm_eval('%pypi_source',
|
||||||
name='python-foo', srcname='foo', version='6')[0]
|
name='python-foo', srcname='foo', version='6')
|
||||||
assert url == 'https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz'
|
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz']
|
||||||
|
|
||||||
|
|
||||||
def test_pypi_source_default_pypi_name():
|
def test_pypi_source_default_pypi_name():
|
||||||
url = rpm_eval('%pypi_source',
|
urls = rpm_eval('%pypi_source',
|
||||||
name='python-foo', pypi_name='foo', version='6')[0]
|
name='python-foo', pypi_name='foo', version='6')
|
||||||
assert url == 'https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz'
|
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz']
|
||||||
|
|
||||||
|
|
||||||
def test_pypi_source_default_name_uppercase():
|
def test_pypi_source_default_name_uppercase():
|
||||||
url = rpm_eval('%pypi_source',
|
urls = rpm_eval('%pypi_source',
|
||||||
name='Foo', version='6')[0]
|
name='Foo', version='6')
|
||||||
assert url == 'https://files.pythonhosted.org/packages/source/F/Foo/Foo-6.tar.gz'
|
assert urls == ['https://files.pythonhosted.org/packages/source/F/Foo/Foo-6.tar.gz']
|
||||||
|
|
||||||
|
|
||||||
def test_pypi_source_provided_name():
|
def test_pypi_source_provided_name():
|
||||||
url = rpm_eval('%pypi_source foo',
|
urls = rpm_eval('%pypi_source foo',
|
||||||
name='python-bar', pypi_name='bar', version='6')[0]
|
name='python-bar', pypi_name='bar', version='6')
|
||||||
assert url == 'https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz'
|
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz']
|
||||||
|
|
||||||
|
|
||||||
def test_pypi_source_provided_name_version():
|
def test_pypi_source_provided_name_version():
|
||||||
url = rpm_eval('%pypi_source foo 6',
|
urls = rpm_eval('%pypi_source foo 6',
|
||||||
name='python-bar', pypi_name='bar', version='3')[0]
|
name='python-bar', pypi_name='bar', version='3')
|
||||||
assert url == 'https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz'
|
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz']
|
||||||
|
|
||||||
|
|
||||||
def test_pypi_source_provided_name_version_ext():
|
def test_pypi_source_provided_name_version_ext():
|
||||||
url = rpm_eval('%pypi_source foo 6 zip',
|
url = rpm_eval('%pypi_source foo 6 zip',
|
||||||
name='python-bar', pypi_name='bar', version='3')[0]
|
name='python-bar', pypi_name='bar', version='3')
|
||||||
assert url == 'https://files.pythonhosted.org/packages/source/f/foo/foo-6.zip'
|
assert url == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6.zip']
|
||||||
|
|
||||||
|
|
||||||
def test_pypi_source_prerelease():
|
def test_pypi_source_prerelease():
|
||||||
url = rpm_eval('%pypi_source',
|
urls = rpm_eval('%pypi_source',
|
||||||
name='python-foo', pypi_name='foo', version='6~b2')[0]
|
name='python-foo', pypi_name='foo', version='6~b2')
|
||||||
assert url == 'https://files.pythonhosted.org/packages/source/f/foo/foo-6b2.tar.gz'
|
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6b2.tar.gz']
|
||||||
|
|
||||||
|
|
||||||
def test_pypi_source_explicit_tilde():
|
def test_pypi_source_explicit_tilde():
|
||||||
url = rpm_eval('%pypi_source foo 6~6',
|
urls = rpm_eval('%pypi_source foo 6~6',
|
||||||
name='python-foo', pypi_name='foo', version='6')[0]
|
name='python-foo', pypi_name='foo', version='6')
|
||||||
assert url == 'https://files.pythonhosted.org/packages/source/f/foo/foo-6~6.tar.gz'
|
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6~6.tar.gz']
|
||||||
|
|
||||||
|
|
||||||
def test_py3_shebang_fix():
|
def test_py3_shebang_fix():
|
||||||
@ -261,7 +414,7 @@ def test_py3_shebang_fix():
|
|||||||
def test_py3_shebang_fix_default_shebang_flags():
|
def test_py3_shebang_fix_default_shebang_flags():
|
||||||
lines = rpm_eval('%py3_shebang_fix arg1 arg2')
|
lines = rpm_eval('%py3_shebang_fix arg1 arg2')
|
||||||
lines[-1] = 'echo $shebang_flags'
|
lines[-1] = 'echo $shebang_flags'
|
||||||
assert shell_stdout('\n'.join(lines)) == '-kas'
|
assert shell_stdout('\n'.join(lines)) == f'-kas{safe_path_flag(X_Y)}'
|
||||||
|
|
||||||
|
|
||||||
def test_py3_shebang_fix_custom_shebang_flags():
|
def test_py3_shebang_fix_custom_shebang_flags():
|
||||||
@ -270,6 +423,31 @@ def test_py3_shebang_fix_custom_shebang_flags():
|
|||||||
assert shell_stdout('\n'.join(lines)) == '-kaEs'
|
assert shell_stdout('\n'.join(lines)) == '-kaEs'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('_py3_shebang_s', [None, '%{nil}'])
|
||||||
|
def test_py3_shebang_fix_undefined_py3_shebang_s(_py3_shebang_s):
|
||||||
|
lines = rpm_eval('%py3_shebang_fix arg1 arg2', _py3_shebang_s=_py3_shebang_s)
|
||||||
|
lines[-1] = 'echo $shebang_flags'
|
||||||
|
expected = f'-ka{safe_path_flag(X_Y)}' if safe_path_flag(X_Y) else '-k'
|
||||||
|
assert shell_stdout('\n'.join(lines)) == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('_py3_shebang_P', [None, '%{nil}'])
|
||||||
|
def test_py3_shebang_fix_undefined_py3_shebang_P(_py3_shebang_P):
|
||||||
|
lines = rpm_eval('%py3_shebang_fix arg1 arg2', _py3_shebang_P=_py3_shebang_P)
|
||||||
|
lines[-1] = 'echo $shebang_flags'
|
||||||
|
assert shell_stdout('\n'.join(lines)) == '-kas'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('_py3_shebang_s', [None, '%{nil}'])
|
||||||
|
@pytest.mark.parametrize('_py3_shebang_P', [None, '%{nil}'])
|
||||||
|
def test_py3_shebang_fix_undefined_py3_shebang_sP(_py3_shebang_s, _py3_shebang_P):
|
||||||
|
lines = rpm_eval('%py3_shebang_fix arg1 arg2',
|
||||||
|
_py3_shebang_s=_py3_shebang_s,
|
||||||
|
_py3_shebang_P=_py3_shebang_P)
|
||||||
|
lines[-1] = 'echo $shebang_flags'
|
||||||
|
assert shell_stdout('\n'.join(lines)) == '-k'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('flags', [None, '%{nil}'])
|
@pytest.mark.parametrize('flags', [None, '%{nil}'])
|
||||||
def test_py3_shebang_fix_no_shebang_flags(flags):
|
def test_py3_shebang_fix_no_shebang_flags(flags):
|
||||||
lines = rpm_eval('%py3_shebang_fix arg1 arg2', py3_shebang_flags=flags)
|
lines = rpm_eval('%py3_shebang_fix arg1 arg2', py3_shebang_flags=flags)
|
||||||
@ -290,20 +468,22 @@ def test_pycached_in_sitelib():
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_pycached_in_sitearch():
|
def test_pycached_in_sitearch(lib):
|
||||||
lines = rpm_eval('%pycached %{python3_sitearch}/foo*.py')
|
lines = rpm_eval('%pycached %{python3_sitearch}/foo*.py')
|
||||||
lib = rpm_eval('%_lib')[0]
|
|
||||||
assert lines == [
|
assert lines == [
|
||||||
f'/usr/{lib}/python{X_Y}/site-packages/foo*.py',
|
f'/usr/{lib}/python{X_Y}/site-packages/foo*.py',
|
||||||
f'/usr/{lib}/python{X_Y}/site-packages/__pycache__/foo*.cpython-{XY}{{,.opt-?}}.pyc'
|
f'/usr/{lib}/python{X_Y}/site-packages/__pycache__/foo*.cpython-{XY}{{,.opt-?}}.pyc'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_pycached_in_36():
|
# this test does not require alternate Pythons to be installed
|
||||||
lines = rpm_eval('%pycached /usr/lib/python3.6/site-packages/foo*.py')
|
@pytest.mark.parametrize('version', ['3.6', '3.7', '3.12'])
|
||||||
|
def test_pycached_with_alternate_version(version):
|
||||||
|
version_nodot = version.replace('.', '')
|
||||||
|
lines = rpm_eval(f'%pycached /usr/lib/python{version}/site-packages/foo*.py')
|
||||||
assert lines == [
|
assert lines == [
|
||||||
'/usr/lib/python3.6/site-packages/foo*.py',
|
f'/usr/lib/python{version}/site-packages/foo*.py',
|
||||||
'/usr/lib/python3.6/site-packages/__pycache__/foo*.cpython-36{,.opt-?}.pyc'
|
f'/usr/lib/python{version}/site-packages/__pycache__/foo*.cpython-{version_nodot}{{,.opt-?}}.pyc'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -497,6 +677,7 @@ unversioned_macros = pytest.mark.parametrize('macro', [
|
|||||||
'%python_platform',
|
'%python_platform',
|
||||||
'%python_platform_triplet',
|
'%python_platform_triplet',
|
||||||
'%python_ext_suffix',
|
'%python_ext_suffix',
|
||||||
|
'%python_cache_tag',
|
||||||
'%py_shebang_fix',
|
'%py_shebang_fix',
|
||||||
'%py_build',
|
'%py_build',
|
||||||
'%py_build_egg',
|
'%py_build_egg',
|
||||||
@ -504,14 +685,15 @@ unversioned_macros = pytest.mark.parametrize('macro', [
|
|||||||
'%py_install',
|
'%py_install',
|
||||||
'%py_install_egg',
|
'%py_install_egg',
|
||||||
'%py_install_wheel',
|
'%py_install_wheel',
|
||||||
|
'%py_check_import',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@unversioned_macros
|
@unversioned_macros
|
||||||
def test_unversioned_python_errors(macro):
|
def test_unversioned_python_errors(macro):
|
||||||
lines = rpm_eval(macro, fails=True)
|
lines = rpm_eval(macro, fails=True)
|
||||||
assert lines[0] == ('error: attempt to use unversioned python, '
|
assert lines == ['error: attempt to use unversioned python, '
|
||||||
'define %__python to /usr/bin/python2 or /usr/bin/python3 explicitly')
|
'define %__python to /usr/bin/python2 or /usr/bin/python3 explicitly']
|
||||||
|
|
||||||
|
|
||||||
@unversioned_macros
|
@unversioned_macros
|
||||||
@ -526,9 +708,147 @@ x86_64_only = pytest.mark.skipif(platform.machine() != "x86_64", reason="works o
|
|||||||
|
|
||||||
@x86_64_only
|
@x86_64_only
|
||||||
def test_platform_triplet():
|
def test_platform_triplet():
|
||||||
assert rpm_eval("%python3_platform_triplet")[0] == "x86_64-linux-gnu"
|
assert rpm_eval("%python3_platform_triplet") == ["x86_64-linux-gnu"]
|
||||||
|
|
||||||
|
|
||||||
@x86_64_only
|
@x86_64_only
|
||||||
def test_ext_suffix():
|
def test_ext_suffix():
|
||||||
assert rpm_eval("%python3_ext_suffix")[0] == f".cpython-{XY}-x86_64-linux-gnu.so"
|
assert rpm_eval("%python3_ext_suffix") == [f".cpython-{XY}-x86_64-linux-gnu.so"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_cache_tag():
|
||||||
|
assert rpm_eval("%python3_cache_tag") == [f"cpython-{XY}"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_cache_tag_alternate_python(alt_x_y, alt_xy):
|
||||||
|
assert rpm_eval("%python_cache_tag", __python=f"/usr/bin/python{alt_x_y}") == [f"cpython-{alt_xy}"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_cache_tag_alternate_python3(alt_x_y, alt_xy):
|
||||||
|
assert rpm_eval("%python3_cache_tag", __python3=f"/usr/bin/python{alt_x_y}") == [f"cpython-{alt_xy}"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_python_sitelib_value_python3():
|
||||||
|
macro = '%python_sitelib'
|
||||||
|
assert rpm_eval(macro, __python='%__python3') == [f'/usr/lib/python{X_Y}/site-packages']
|
||||||
|
|
||||||
|
|
||||||
|
def test_python_sitelib_value_alternate_python(alt_x_y):
|
||||||
|
macro = '%python_sitelib'
|
||||||
|
assert rpm_eval(macro, __python=f'/usr/bin/python{alt_x_y}') == [f'/usr/lib/python{alt_x_y}/site-packages']
|
||||||
|
|
||||||
|
|
||||||
|
def test_python3_sitelib_value_default():
|
||||||
|
macro = '%python3_sitelib'
|
||||||
|
assert rpm_eval(macro) == [f'/usr/lib/python{X_Y}/site-packages']
|
||||||
|
|
||||||
|
|
||||||
|
def test_python3_sitelib_value_alternate_python(alt_x_y):
|
||||||
|
macro = '%python3_sitelib'
|
||||||
|
assert (rpm_eval(macro, __python3=f'/usr/bin/python{alt_x_y}') ==
|
||||||
|
rpm_eval(macro, python3_pkgversion=alt_x_y) ==
|
||||||
|
[f'/usr/lib/python{alt_x_y}/site-packages'])
|
||||||
|
|
||||||
|
|
||||||
|
def test_python3_sitelib_value_alternate_prefix():
|
||||||
|
macro = '%python3_sitelib'
|
||||||
|
assert rpm_eval(macro, _prefix='/app') == [f'/app/lib/python{X_Y}/site-packages']
|
||||||
|
|
||||||
|
|
||||||
|
def test_python_sitearch_value_python3(lib):
|
||||||
|
macro = '%python_sitearch'
|
||||||
|
assert rpm_eval(macro, __python='%__python3') == [f'/usr/{lib}/python{X_Y}/site-packages']
|
||||||
|
|
||||||
|
|
||||||
|
def test_python_sitearch_value_alternate_python(lib, alt_x_y):
|
||||||
|
macro = '%python_sitearch'
|
||||||
|
assert rpm_eval(macro, __python=f'/usr/bin/python{alt_x_y}') == [f'/usr/{lib}/python{alt_x_y}/site-packages']
|
||||||
|
|
||||||
|
|
||||||
|
def test_python3_sitearch_value_default(lib):
|
||||||
|
macro = '%python3_sitearch'
|
||||||
|
assert rpm_eval(macro) == [f'/usr/{lib}/python{X_Y}/site-packages']
|
||||||
|
|
||||||
|
|
||||||
|
def test_python3_sitearch_value_alternate_python(lib, alt_x_y):
|
||||||
|
macro = '%python3_sitearch'
|
||||||
|
assert (rpm_eval(macro, __python3=f'/usr/bin/python{alt_x_y}') ==
|
||||||
|
rpm_eval(macro, python3_pkgversion=alt_x_y) ==
|
||||||
|
[f'/usr/{lib}/python{alt_x_y}/site-packages'])
|
||||||
|
|
||||||
|
|
||||||
|
def test_python3_sitearch_value_alternate_prefix(lib):
|
||||||
|
macro = '%python3_sitearch'
|
||||||
|
assert rpm_eval(macro, _prefix='/app') == [f'/app/{lib}/python{X_Y}/site-packages']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'args, expected_args',
|
||||||
|
[
|
||||||
|
('six', 'six'),
|
||||||
|
('-f foo.txt', '-f foo.txt'),
|
||||||
|
('-t -f foo.txt six, seven', '-t -f foo.txt six, seven'),
|
||||||
|
('-e "foo*" -f foo.txt six, seven', '-e "foo*" -f foo.txt six, seven'),
|
||||||
|
('six.quarter six.half,, SIX', 'six.quarter six.half,, SIX'),
|
||||||
|
('-f foo.txt six\nsix.half\nSIX', '-f foo.txt six six.half SIX'),
|
||||||
|
('six \\ -e six.half', 'six -e six.half'),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize('__python3',
|
||||||
|
[None,
|
||||||
|
f'/usr/bin/python{X_Y}',
|
||||||
|
'/usr/bin/pythonX.Y'])
|
||||||
|
def test_py3_check_import(args, expected_args, __python3, lib):
|
||||||
|
x_y = X_Y
|
||||||
|
macros = {
|
||||||
|
'buildroot': 'BUILDROOT',
|
||||||
|
'_rpmconfigdir': 'RPMCONFIGDIR',
|
||||||
|
}
|
||||||
|
if __python3 is not None:
|
||||||
|
if 'X.Y' in __python3:
|
||||||
|
__python3 = __python3.replace('X.Y', get_alt_x_y())
|
||||||
|
macros['__python3'] = __python3
|
||||||
|
# If the __python3 command has version at the end, parse it and expect it.
|
||||||
|
# Note that the command is used to determine %python3_sitelib and %python3_sitearch,
|
||||||
|
# so we only test known CPython schemes here and not PyPy for simplicity.
|
||||||
|
if (match := re.match(r'.+python(\d+\.\d+)$', __python3)):
|
||||||
|
x_y = match.group(1)
|
||||||
|
|
||||||
|
invocation = '%{py3_check_import ' + args +'}'
|
||||||
|
lines = rpm_eval(invocation, **macros)
|
||||||
|
|
||||||
|
# An equality check is a bit inflexible here,
|
||||||
|
# every time we change the macro we need to change this test.
|
||||||
|
# However actually executing it and verifying the result is much harder :/
|
||||||
|
# At least, let's make the lines saner to check:
|
||||||
|
lines = [line.rstrip('\\').strip() for line in lines]
|
||||||
|
expected = textwrap.dedent(fr"""
|
||||||
|
PATH="BUILDROOT/usr/bin:$PATH"
|
||||||
|
PYTHONPATH="${{PYTHONPATH:-BUILDROOT/usr/{lib}/python{x_y}/site-packages:BUILDROOT/usr/lib/python{x_y}/site-packages}}"
|
||||||
|
_PYTHONSITE="BUILDROOT/usr/{lib}/python{x_y}/site-packages:BUILDROOT/usr/lib/python{x_y}/site-packages"
|
||||||
|
PYTHONDONTWRITEBYTECODE=1
|
||||||
|
{__python3 or '/usr/bin/python3'} -s{safe_path_flag(x_y)} RPMCONFIGDIR/redhat/import_all_modules.py {expected_args}
|
||||||
|
""")
|
||||||
|
assert lines == expected.splitlines()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'shebang_flags_value, expected_shebang_flags',
|
||||||
|
[
|
||||||
|
('sP', '-sP'),
|
||||||
|
('s', '-s'),
|
||||||
|
('%{nil}', ''),
|
||||||
|
(None, ''),
|
||||||
|
('Es', '-Es'),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_py3_check_import_respects_shebang_flags(shebang_flags_value, expected_shebang_flags, lib):
|
||||||
|
macros = {
|
||||||
|
'_rpmconfigdir': 'RPMCONFIGDIR',
|
||||||
|
'__python3': '/usr/bin/python3',
|
||||||
|
'py3_shebang_flags': shebang_flags_value,
|
||||||
|
}
|
||||||
|
lines = rpm_eval('%py3_check_import sys', **macros)
|
||||||
|
# Compare the last line of the command, that's where lua part is evaluated
|
||||||
|
expected = f'/usr/bin/python3 {expected_shebang_flags} RPMCONFIGDIR/redhat/import_all_modules.py sys'
|
||||||
|
assert lines[-1].strip() == expected
|
||||||
|
426
tests/test_import_all_modules.py
Normal file
426
tests/test_import_all_modules.py
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
from import_all_modules import argparser, exclude_unwanted_module_globs
|
||||||
|
from import_all_modules import main as modules_main
|
||||||
|
from import_all_modules import read_modules_from_cli, filter_top_level_modules_only
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import shlex
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def preserve_sys_path():
|
||||||
|
original_sys_path = list(sys.path)
|
||||||
|
yield
|
||||||
|
sys.path = original_sys_path
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def preserve_sys_modules():
|
||||||
|
original_sys_modules = dict(sys.modules)
|
||||||
|
yield
|
||||||
|
sys.modules = original_sys_modules
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'args, imports',
|
||||||
|
[
|
||||||
|
('six', ['six']),
|
||||||
|
('five six seven', ['five', 'six', 'seven']),
|
||||||
|
('six,seven, eight', ['six', 'seven', 'eight']),
|
||||||
|
('six.quarter six.half,, SIX', ['six.quarter', 'six.half', 'SIX']),
|
||||||
|
('six.quarter six.half,, SIX \\ ', ['six.quarter', 'six.half', 'SIX']),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_read_modules_from_cli(args, imports):
|
||||||
|
argv = shlex.split(args)
|
||||||
|
cli_args = argparser().parse_args(argv)
|
||||||
|
assert read_modules_from_cli(cli_args.modules) == imports
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'all_mods, imports',
|
||||||
|
[
|
||||||
|
(['six'], ['six']),
|
||||||
|
(['five', 'six', 'seven'], ['five', 'six', 'seven']),
|
||||||
|
(['six.seven', 'eight'], ['eight']),
|
||||||
|
(['SIX', 'six.quarter', 'six.half.and.sth', 'seven'], ['SIX', 'seven']),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_filter_top_level_modules_only(all_mods, imports):
|
||||||
|
assert filter_top_level_modules_only(all_mods) == imports
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'globs, expected',
|
||||||
|
[
|
||||||
|
(['*.*'], ['foo', 'boo']),
|
||||||
|
(['?oo'], ['foo.bar', 'foo.bar.baz', 'foo.baz']),
|
||||||
|
(['*.baz'], ['foo', 'foo.bar', 'boo']),
|
||||||
|
(['foo'], ['foo.bar', 'foo.bar.baz', 'foo.baz', 'boo']),
|
||||||
|
(['foo*'], ['boo']),
|
||||||
|
(['foo*', '*bar'], ['boo']),
|
||||||
|
(['foo', 'bar'], ['foo.bar', 'foo.bar.baz', 'foo.baz', 'boo']),
|
||||||
|
(['*'], []),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_exclude_unwanted_module_globs(globs, expected):
|
||||||
|
my_modules = ['foo', 'foo.bar', 'foo.bar.baz', 'foo.baz', 'boo']
|
||||||
|
tested = exclude_unwanted_module_globs(globs, my_modules)
|
||||||
|
assert tested == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_cli_with_all_args():
|
||||||
|
'''A smoke test, all args must be parsed correctly.'''
|
||||||
|
mods = ['foo', 'foo.bar', 'baz']
|
||||||
|
files = ['-f', './foo']
|
||||||
|
top = ['-t']
|
||||||
|
exclude = ['-e', 'foo*']
|
||||||
|
cli_args = argparser().parse_args([*mods, *files, *top, *exclude])
|
||||||
|
|
||||||
|
assert cli_args.filename == [Path('foo')]
|
||||||
|
assert cli_args.top_level is True
|
||||||
|
assert cli_args.modules == ['foo', 'foo.bar', 'baz']
|
||||||
|
assert cli_args.exclude == ['foo*']
|
||||||
|
|
||||||
|
|
||||||
|
def test_cli_without_filename_toplevel():
|
||||||
|
'''Modules provided on command line (without files) must be parsed correctly.'''
|
||||||
|
mods = ['foo', 'foo.bar', 'baz']
|
||||||
|
cli_args = argparser().parse_args(mods)
|
||||||
|
|
||||||
|
assert cli_args.filename is None
|
||||||
|
assert cli_args.top_level is False
|
||||||
|
assert cli_args.modules == ['foo', 'foo.bar', 'baz']
|
||||||
|
|
||||||
|
|
||||||
|
def test_cli_with_filename_no_cli_mods():
|
||||||
|
'''Files (without any modules provided on command line) must be parsed correctly.'''
|
||||||
|
|
||||||
|
files = ['-f', './foo', '-f', './bar', '-f', './baz']
|
||||||
|
cli_args = argparser().parse_args(files)
|
||||||
|
|
||||||
|
assert cli_args.filename == [Path('foo'), Path('./bar'), Path('./baz')]
|
||||||
|
assert not cli_args.top_level
|
||||||
|
|
||||||
|
|
||||||
|
def test_main_raises_error_when_no_modules_provided():
|
||||||
|
'''If no filename nor modules were provided, ValueError is raised.'''
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
modules_main([])
|
||||||
|
|
||||||
|
|
||||||
|
def test_import_all_modules_does_not_import():
|
||||||
|
'''Ensure the files from /usr/lib/rpm/redhat cannot be imported and
|
||||||
|
checked for import'''
|
||||||
|
|
||||||
|
# We already imported it in this file once, make sure it's not imported
|
||||||
|
# from the cache
|
||||||
|
sys.modules.pop('import_all_modules')
|
||||||
|
with pytest.raises(ModuleNotFoundError):
|
||||||
|
modules_main(['import_all_modules'])
|
||||||
|
|
||||||
|
|
||||||
|
def test_modules_from_cwd_not_found(tmp_path, monkeypatch):
|
||||||
|
test_module = tmp_path / 'this_is_a_module_in_cwd.py'
|
||||||
|
test_module.write_text('')
|
||||||
|
monkeypatch.chdir(tmp_path)
|
||||||
|
with pytest.raises(ModuleNotFoundError):
|
||||||
|
modules_main(['this_is_a_module_in_cwd'])
|
||||||
|
|
||||||
|
|
||||||
|
def test_modules_from_sys_path_found(tmp_path):
|
||||||
|
test_module = tmp_path / 'this_is_a_module_in_sys_path.py'
|
||||||
|
test_module.write_text('')
|
||||||
|
sys.path.append(str(tmp_path))
|
||||||
|
modules_main(['this_is_a_module_in_sys_path'])
|
||||||
|
assert 'this_is_a_module_in_sys_path' in sys.modules
|
||||||
|
|
||||||
|
|
||||||
|
def test_modules_from_file_are_found(tmp_path):
|
||||||
|
test_file = tmp_path / 'this_is_a_file_in_tmp_path.txt'
|
||||||
|
test_file.write_text('math\nwave\nsunau\n')
|
||||||
|
|
||||||
|
# Make sure the tested modules are not already in sys.modules
|
||||||
|
for m in ('math', 'wave', 'sunau'):
|
||||||
|
sys.modules.pop(m, None)
|
||||||
|
|
||||||
|
modules_main(['-f', str(test_file)])
|
||||||
|
|
||||||
|
assert 'sunau' in sys.modules
|
||||||
|
assert 'math' in sys.modules
|
||||||
|
assert 'wave' in sys.modules
|
||||||
|
|
||||||
|
|
||||||
|
def test_modules_from_files_are_found(tmp_path):
|
||||||
|
test_file_1 = tmp_path / 'this_is_a_file_in_tmp_path_1.txt'
|
||||||
|
test_file_2 = tmp_path / 'this_is_a_file_in_tmp_path_2.txt'
|
||||||
|
test_file_3 = tmp_path / 'this_is_a_file_in_tmp_path_3.txt'
|
||||||
|
|
||||||
|
test_file_1.write_text('math\nwave\n')
|
||||||
|
test_file_2.write_text('sunau\npathlib\n')
|
||||||
|
test_file_3.write_text('logging\nsunau\n')
|
||||||
|
|
||||||
|
# Make sure the tested modules are not already in sys.modules
|
||||||
|
for m in ('math', 'wave', 'sunau', 'pathlib', 'logging'):
|
||||||
|
sys.modules.pop(m, None)
|
||||||
|
|
||||||
|
modules_main(['-f', str(test_file_1), '-f', str(test_file_2), '-f', str(test_file_3), ])
|
||||||
|
for module in ('sunau', 'math', 'wave', 'pathlib', 'logging'):
|
||||||
|
assert module in sys.modules
|
||||||
|
|
||||||
|
|
||||||
|
def test_nonexisting_modules_raise_exception_on_import(tmp_path):
|
||||||
|
test_file = tmp_path / 'this_is_a_file_in_tmp_path.txt'
|
||||||
|
test_file.write_text('nonexisting_module\nanother\n')
|
||||||
|
with pytest.raises(ModuleNotFoundError):
|
||||||
|
modules_main(['-f', str(test_file)])
|
||||||
|
|
||||||
|
|
||||||
|
def test_nested_modules_found_when_expected(tmp_path, monkeypatch, capsys):
|
||||||
|
|
||||||
|
# This one is supposed to raise an error
|
||||||
|
cwd_path = tmp_path / 'test_cwd'
|
||||||
|
Path.mkdir(cwd_path)
|
||||||
|
test_module_1 = cwd_path / 'this_is_a_module_in_cwd.py'
|
||||||
|
|
||||||
|
# Nested structure that is supposed to be importable
|
||||||
|
nested_path_1 = tmp_path / 'nested'
|
||||||
|
nested_path_2 = nested_path_1 / 'more_nested'
|
||||||
|
|
||||||
|
for path in (nested_path_1, nested_path_2):
|
||||||
|
Path.mkdir(path)
|
||||||
|
|
||||||
|
test_module_2 = tmp_path / 'this_is_a_module_in_level_0.py'
|
||||||
|
test_module_3 = nested_path_1 / 'this_is_a_module_in_level_1.py'
|
||||||
|
test_module_4 = nested_path_2 / 'this_is_a_module_in_level_2.py'
|
||||||
|
|
||||||
|
for module in (test_module_1, test_module_2, test_module_3, test_module_4):
|
||||||
|
module.write_text('')
|
||||||
|
|
||||||
|
sys.path.append(str(tmp_path))
|
||||||
|
monkeypatch.chdir(cwd_path)
|
||||||
|
|
||||||
|
with pytest.raises(ModuleNotFoundError):
|
||||||
|
modules_main([
|
||||||
|
'this_is_a_module_in_level_0',
|
||||||
|
'nested.this_is_a_module_in_level_1',
|
||||||
|
'nested.more_nested.this_is_a_module_in_level_2',
|
||||||
|
'this_is_a_module_in_cwd'])
|
||||||
|
|
||||||
|
_, err = capsys.readouterr()
|
||||||
|
assert 'Check import: this_is_a_module_in_level_0' in err
|
||||||
|
assert 'Check import: nested.this_is_a_module_in_level_1' in err
|
||||||
|
assert 'Check import: nested.more_nested.this_is_a_module_in_level_2' in err
|
||||||
|
assert 'Check import: this_is_a_module_in_cwd' in err
|
||||||
|
|
||||||
|
|
||||||
|
def test_modules_both_from_files_and_cli_are_imported(tmp_path):
|
||||||
|
test_file_1 = tmp_path / 'this_is_a_file_in_tmp_path_1.txt'
|
||||||
|
test_file_1.write_text('this_is_a_module_in_tmp_path_1')
|
||||||
|
|
||||||
|
test_file_2 = tmp_path / 'this_is_a_file_in_tmp_path_2.txt'
|
||||||
|
test_file_2.write_text('this_is_a_module_in_tmp_path_2')
|
||||||
|
|
||||||
|
test_module_1 = tmp_path / 'this_is_a_module_in_tmp_path_1.py'
|
||||||
|
test_module_2 = tmp_path / 'this_is_a_module_in_tmp_path_2.py'
|
||||||
|
test_module_3 = tmp_path / 'this_is_a_module_in_tmp_path_3.py'
|
||||||
|
|
||||||
|
for module in (test_module_1, test_module_2, test_module_3):
|
||||||
|
module.write_text('')
|
||||||
|
|
||||||
|
sys.path.append(str(tmp_path))
|
||||||
|
modules_main([
|
||||||
|
'-f', str(test_file_1),
|
||||||
|
'this_is_a_module_in_tmp_path_3',
|
||||||
|
'-f', str(test_file_2),
|
||||||
|
])
|
||||||
|
|
||||||
|
expected = (
|
||||||
|
'this_is_a_module_in_tmp_path_1',
|
||||||
|
'this_is_a_module_in_tmp_path_2',
|
||||||
|
'this_is_a_module_in_tmp_path_3',
|
||||||
|
)
|
||||||
|
for module in expected:
|
||||||
|
assert module in sys.modules
|
||||||
|
|
||||||
|
|
||||||
|
def test_non_existing_module_raises_exception(tmp_path):
|
||||||
|
|
||||||
|
test_module_1 = tmp_path / 'this_is_a_module_in_tmp_path_1.py'
|
||||||
|
test_module_1.write_text('')
|
||||||
|
sys.path.append(str(tmp_path))
|
||||||
|
|
||||||
|
with pytest.raises(ModuleNotFoundError):
|
||||||
|
modules_main([
|
||||||
|
'this_is_a_module_in_tmp_path_1',
|
||||||
|
'this_is_a_module_in_tmp_path_2',
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def test_module_with_error_propagates_exception(tmp_path):
|
||||||
|
|
||||||
|
test_module_1 = tmp_path / 'this_is_a_module_in_tmp_path_1.py'
|
||||||
|
test_module_1.write_text('0/0')
|
||||||
|
sys.path.append(str(tmp_path))
|
||||||
|
|
||||||
|
# The correct exception must be raised
|
||||||
|
with pytest.raises(ZeroDivisionError):
|
||||||
|
modules_main([
|
||||||
|
'this_is_a_module_in_tmp_path_1',
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def test_correct_modules_are_excluded(tmp_path):
|
||||||
|
test_module_1 = tmp_path / 'module_in_tmp_path_1.py'
|
||||||
|
test_module_2 = tmp_path / 'module_in_tmp_path_2.py'
|
||||||
|
test_module_3 = tmp_path / 'module_in_tmp_path_3.py'
|
||||||
|
|
||||||
|
for module in (test_module_1, test_module_2, test_module_3):
|
||||||
|
module.write_text('')
|
||||||
|
|
||||||
|
sys.path.append(str(tmp_path))
|
||||||
|
test_file_1 = tmp_path / 'a_file_in_tmp_path_1.txt'
|
||||||
|
test_file_1.write_text('module_in_tmp_path_1\nmodule_in_tmp_path_2\nmodule_in_tmp_path_3\n')
|
||||||
|
|
||||||
|
modules_main([
|
||||||
|
'-e', 'module_in_tmp_path_2',
|
||||||
|
'-f', str(test_file_1),
|
||||||
|
'-e', 'module_in_tmp_path_3',
|
||||||
|
])
|
||||||
|
|
||||||
|
assert 'module_in_tmp_path_1' in sys.modules
|
||||||
|
assert 'module_in_tmp_path_2' not in sys.modules
|
||||||
|
assert 'module_in_tmp_path_3' not in sys.modules
|
||||||
|
|
||||||
|
|
||||||
|
def test_excluding_all_modules_raises_error(tmp_path):
|
||||||
|
test_module_1 = tmp_path / 'module_in_tmp_path_1.py'
|
||||||
|
test_module_2 = tmp_path / 'module_in_tmp_path_2.py'
|
||||||
|
test_module_3 = tmp_path / 'module_in_tmp_path_3.py'
|
||||||
|
|
||||||
|
for module in (test_module_1, test_module_2, test_module_3):
|
||||||
|
module.write_text('')
|
||||||
|
|
||||||
|
sys.path.append(str(tmp_path))
|
||||||
|
test_file_1 = tmp_path / 'a_file_in_tmp_path_1.txt'
|
||||||
|
test_file_1.write_text('module_in_tmp_path_1\nmodule_in_tmp_path_2\nmodule_in_tmp_path_3\n')
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
modules_main([
|
||||||
|
'-e', 'module_in_tmp_path*',
|
||||||
|
'-f', str(test_file_1),
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def test_only_toplevel_modules_found(tmp_path):
|
||||||
|
|
||||||
|
# Nested structure that is supposed to be importable
|
||||||
|
nested_path_1 = tmp_path / 'nested'
|
||||||
|
nested_path_2 = nested_path_1 / 'more_nested'
|
||||||
|
|
||||||
|
for path in (nested_path_1, nested_path_2):
|
||||||
|
Path.mkdir(path)
|
||||||
|
|
||||||
|
test_module_1 = tmp_path / 'this_is_a_module_in_level_0.py'
|
||||||
|
test_module_2 = nested_path_1 / 'this_is_a_module_in_level_1.py'
|
||||||
|
test_module_3 = nested_path_2 / 'this_is_a_module_in_level_2.py'
|
||||||
|
|
||||||
|
for module in (test_module_1, test_module_2, test_module_3):
|
||||||
|
module.write_text('')
|
||||||
|
|
||||||
|
sys.path.append(str(tmp_path))
|
||||||
|
|
||||||
|
modules_main([
|
||||||
|
'this_is_a_module_in_level_0',
|
||||||
|
'nested.this_is_a_module_in_level_1',
|
||||||
|
'nested.more_nested.this_is_a_module_in_level_2',
|
||||||
|
'-t'])
|
||||||
|
|
||||||
|
assert 'nested.this_is_a_module_in_level_1' not in sys.modules
|
||||||
|
assert 'nested.more_nested.this_is_a_module_in_level_2' not in sys.modules
|
||||||
|
|
||||||
|
|
||||||
|
def test_only_toplevel_included_modules_found(tmp_path):
|
||||||
|
|
||||||
|
# Nested structure that is supposed to be importable
|
||||||
|
nested_path_1 = tmp_path / 'nested'
|
||||||
|
nested_path_2 = nested_path_1 / 'more_nested'
|
||||||
|
|
||||||
|
for path in (nested_path_1, nested_path_2):
|
||||||
|
Path.mkdir(path)
|
||||||
|
|
||||||
|
test_module_1 = tmp_path / 'this_is_a_module_in_level_0.py'
|
||||||
|
test_module_4 = tmp_path / 'this_is_another_module_in_level_0.py'
|
||||||
|
|
||||||
|
test_module_2 = nested_path_1 / 'this_is_a_module_in_level_1.py'
|
||||||
|
test_module_3 = nested_path_2 / 'this_is_a_module_in_level_2.py'
|
||||||
|
|
||||||
|
for module in (test_module_1, test_module_2, test_module_3, test_module_4):
|
||||||
|
module.write_text('')
|
||||||
|
|
||||||
|
sys.path.append(str(tmp_path))
|
||||||
|
|
||||||
|
modules_main([
|
||||||
|
'this_is_a_module_in_level_0',
|
||||||
|
'this_is_another_module_in_level_0',
|
||||||
|
'nested.this_is_a_module_in_level_1',
|
||||||
|
'nested.more_nested.this_is_a_module_in_level_2',
|
||||||
|
'-t',
|
||||||
|
'-e', '*another*'
|
||||||
|
])
|
||||||
|
|
||||||
|
assert 'nested.this_is_a_module_in_level_1' not in sys.modules
|
||||||
|
assert 'nested.more_nested.this_is_a_module_in_level_2' not in sys.modules
|
||||||
|
assert 'this_is_another_module_in_level_0' not in sys.modules
|
||||||
|
assert 'this_is_a_module_in_level_0' in sys.modules
|
||||||
|
|
||||||
|
|
||||||
|
def test_module_list_from_relative_path(tmp_path, monkeypatch):
|
||||||
|
|
||||||
|
monkeypatch.chdir(tmp_path)
|
||||||
|
test_file_1 = Path('this_is_a_file_in_cwd.txt')
|
||||||
|
test_file_1.write_text('wave')
|
||||||
|
|
||||||
|
sys.modules.pop('wave', None)
|
||||||
|
|
||||||
|
modules_main([
|
||||||
|
'-f', 'this_is_a_file_in_cwd.txt'
|
||||||
|
])
|
||||||
|
|
||||||
|
assert 'wave' in sys.modules
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('arch_in_path', [True, False])
|
||||||
|
def test_pth_files_are_read_from__PYTHONSITE(arch_in_path, tmp_path, monkeypatch, capsys):
|
||||||
|
sitearch = tmp_path / 'lib64'
|
||||||
|
sitearch.mkdir()
|
||||||
|
sitelib = tmp_path / 'lib'
|
||||||
|
sitelib.mkdir()
|
||||||
|
|
||||||
|
for where, word in (sitearch, "ARCH"), (sitelib, "LIB"), (sitelib, "MOD"):
|
||||||
|
module = where / f'print{word}.py'
|
||||||
|
module.write_text(f'print("{word}")')
|
||||||
|
|
||||||
|
pth_sitearch = sitearch / 'ARCH.pth'
|
||||||
|
pth_sitearch.write_text('import printARCH\n')
|
||||||
|
|
||||||
|
pth_sitelib = sitelib / 'LIB.pth'
|
||||||
|
pth_sitelib.write_text('import printLIB\n')
|
||||||
|
|
||||||
|
if arch_in_path:
|
||||||
|
sys.path.append(str(sitearch))
|
||||||
|
sys.path.append(str(sitelib))
|
||||||
|
|
||||||
|
# we always add sitearch to _PYTHONSITE
|
||||||
|
# but when not in sys.path, it should not be processed for .pth files
|
||||||
|
monkeypatch.setenv('_PYTHONSITE', f'{sitearch}:{sitelib}')
|
||||||
|
|
||||||
|
modules_main(['printMOD'])
|
||||||
|
out, err = capsys.readouterr()
|
||||||
|
if arch_in_path:
|
||||||
|
assert out == 'ARCH\nLIB\nMOD\n'
|
||||||
|
else:
|
||||||
|
assert out == 'LIB\nMOD\n'
|
@ -15,7 +15,7 @@
|
|||||||
tests:
|
tests:
|
||||||
- pytest:
|
- pytest:
|
||||||
dir: .
|
dir: .
|
||||||
run: pytest -v
|
run: PYTHONPATH=/usr/lib/rpm/redhat ALTERNATE_PYTHON_VERSION=3.6 pytest -v
|
||||||
- manual_byte_compilation:
|
- manual_byte_compilation:
|
||||||
dir: .
|
dir: .
|
||||||
run: rpmbuild -ba pythontest.spec
|
run: rpmbuild -ba pythontest.spec
|
||||||
@ -25,4 +25,6 @@
|
|||||||
- python3-rpm-macros
|
- python3-rpm-macros
|
||||||
- python3-devel
|
- python3-devel
|
||||||
- python3-pytest
|
- python3-pytest
|
||||||
|
- python3.6
|
||||||
|
- python2.7
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user