Compare commits
No commits in common. "imports/c10s/python-rpm-macros-3.12-9.1.el10" and "c8" have entirely different histories.
imports/c1
...
c8
24
SOURCES/macros.pybytecompile
Normal file
24
SOURCES/macros.pybytecompile
Normal file
@ -0,0 +1,24 @@
|
||||
# Note that the path could itself be a python file, or a directory
|
||||
|
||||
# Python's compile_all module only works on directories, and requires a max
|
||||
# recursion depth
|
||||
|
||||
# Usage:
|
||||
# %py_byte_compile <interpereter> <path>
|
||||
# Example:
|
||||
# %py_byte_compile %{__python3} %{buildroot}%{_datadir}/spam/plugins/
|
||||
|
||||
# This will terminate build on SyntaxErrors, if you want to avoid that,
|
||||
# use it in a subshell like this:
|
||||
# (%{py_byte_compile <interpereter> <path>}) || :
|
||||
|
||||
%py_byte_compile()\
|
||||
python_binary="%1"\
|
||||
buildroot_path="%2"\
|
||||
bytecode_compilation_path=".${buildroot_path/#$RPM_BUILD_ROOT}"\
|
||||
failure=0\
|
||||
pushd $RPM_BUILD_ROOT\
|
||||
find $bytecode_compilation_path -type f -a -name "*.py" -print0 | xargs -0 $python_binary -O -m py_compile || failure=1\
|
||||
find $bytecode_compilation_path -type f -a -name "*.py" -print0 | xargs -0 $python_binary -m py_compile || failure=1\
|
||||
popd\
|
||||
test $failure -eq 0
|
92
SOURCES/macros.python
Normal file
92
SOURCES/macros.python
Normal file
@ -0,0 +1,92 @@
|
||||
# %%__python is defined in /usr/lib/rpm/macros to raise an error
|
||||
# so if you don't redefine it, you'll get the same error from %%python
|
||||
%python %__python
|
||||
|
||||
%python_platform_triplet %(%{__python} -Esc "import sysconfig; print(sysconfig.get_config_var('MULTIARCH'))")
|
||||
%python_ext_suffix %(%{__python} -Esc "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
|
||||
|
||||
%py_setup setup.py
|
||||
%py_shbang_opts -s
|
||||
|
||||
%py_shbang_opts_nodash %(opts=%{py_shbang_opts}; echo ${opts#-})
|
||||
%py_shebang_flags %(opts=%{py_shbang_opts}; echo ${opts#-})
|
||||
%py_shebang_fix %{expand:\\\
|
||||
if [ -f /usr/bin/pathfix%{python_version}.py ]; then
|
||||
pathfix=/usr/bin/pathfix%{python_version}.py
|
||||
else
|
||||
# unversioned pathfix.py provided by platform-python-devel
|
||||
pathfix=/usr/bin/pathfix.py
|
||||
fi
|
||||
if [ -z "%{?py_shebang_flags}" ]; then
|
||||
shebang_flags="-k"
|
||||
else
|
||||
shebang_flags="-ka%{py_shebang_flags}"
|
||||
fi
|
||||
$pathfix -pni %{__python} $shebang_flags}
|
||||
|
||||
# Use the slashes after expand so that the command starts on the same line as
|
||||
# the macro
|
||||
%py_build() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python} %{py_setup} %{?py_setup_args} build --executable="%{__python} %{py_shbang_opts}" %{?*}
|
||||
sleep 1
|
||||
}
|
||||
|
||||
%py_build_egg() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python} %{py_setup} %{?py_setup_args} bdist_egg %{?*}
|
||||
sleep 1
|
||||
}
|
||||
|
||||
%py_build_wheel() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python} %{py_setup} %{?py_setup_args} bdist_wheel %{?*}
|
||||
sleep 1
|
||||
}
|
||||
|
||||
%py_install() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*}
|
||||
}
|
||||
|
||||
%py_install_egg() %{expand:\\\
|
||||
mkdir -p %{buildroot}%{python_sitelib}
|
||||
easy_install -m --prefix %{buildroot}%{_prefix} -Z dist/*-py%{python_version}.egg %{?*}
|
||||
}
|
||||
|
||||
%py_install_wheel() %{expand:\\\
|
||||
pip install -I dist/%{1} --root %{buildroot} --strip-file-prefix %{buildroot} --no-deps
|
||||
}
|
||||
|
||||
%python_provide() %{lua:
|
||||
function string.starts(String,Start)
|
||||
return string.sub(String,1,string.len(Start))==Start
|
||||
end
|
||||
package = rpm.expand("%{?1}")
|
||||
vr = rpm.expand("%{?epoch:%{epoch}:}%{version}-%{release}")
|
||||
if (string.starts(package, "python2-")) then
|
||||
--No unversioned provides as python2 is not default
|
||||
elseif (string.starts(package, "python" .. rpm.expand("%{python3_pkgversion}") .. "-")) then
|
||||
--No unversioned provides as python3 is not default
|
||||
elseif (rpm.expand("%{?python3_other_pkgversion}") ~= "" and string.starts(package, "python" .. rpm.expand("%{python3_other_pkgversion}") .. "-")) then
|
||||
--No unversioned provides as python3_other is not default
|
||||
elseif (string.starts(package, "pypy-")) then
|
||||
--No unversioned provides as pypy is not default
|
||||
elseif (string.starts(package, "pypy3-")) then
|
||||
--No unversioned provides as pypy is not default
|
||||
elseif (string.starts(package, "python-")) then
|
||||
--Providing the current default python
|
||||
print("Provides: python2-")
|
||||
print(string.sub(package,8,string.len(package)))
|
||||
print(" = ")
|
||||
print(vr)
|
||||
else
|
||||
print("%python_provide: ERROR: ")
|
||||
print(package)
|
||||
print(" not recognized.")
|
||||
end
|
||||
}
|
||||
|
||||
%python_enable_dependency_generator() \
|
||||
%global __python_requires %{_rpmconfigdir}/pythondistdeps.py --requires \
|
||||
%{nil}
|
152
SOURCES/macros.python-srpm
Normal file
152
SOURCES/macros.python-srpm
Normal file
@ -0,0 +1,152 @@
|
||||
# python3_pkgversion specifies the version of Python 3 in the distro. It can be
|
||||
# a specific version (e.g. 34 in Fedora EPEL7)
|
||||
%python3_pkgversion 3
|
||||
|
||||
# Set to /bin/true to avoid %ifdefs and %{? in specfiles
|
||||
%__python3_other /bin/true
|
||||
%py3_other_build /bin/true
|
||||
%py3_other_install /bin/true
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
# === Macros for Build/Requires tags using Python dist tags ===
|
||||
# - https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages
|
||||
# - These macros need to be in macros.python-srpm, because BuildRequires tags
|
||||
# get rendered as runtime requires into the metadata of SRPMs.
|
||||
|
||||
# Converts Python dist name to a canonical format
|
||||
%py_dist_name() %{lua:\
|
||||
name = rpm.expand("%{?1:%{1}}");\
|
||||
canonical = string.gsub(string.lower(name), "[^%w%.]+", "-");\
|
||||
print(canonical);\
|
||||
}
|
||||
|
||||
# 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
|
||||
# macro (%py_dist_name) overwrites them
|
||||
%py2_dist() %{lua:\
|
||||
args = {}\
|
||||
arg = 1\
|
||||
while (true) do\
|
||||
name = rpm.expand("%{?" .. arg .. ":%{" .. arg .. "}}");\
|
||||
if (name == nil or name == '') then\
|
||||
break\
|
||||
end\
|
||||
args[arg] = name\
|
||||
arg = arg + 1\
|
||||
end\
|
||||
for arg, name in ipairs(args) do\
|
||||
canonical = rpm.expand("%py_dist_name " .. name);\
|
||||
print("python2dist(" .. canonical .. ") ");\
|
||||
end\
|
||||
}
|
||||
|
||||
# RHEL 9+ and Fedora compatibility macro
|
||||
# Only use in macro backports, not intended to be used in spec files!
|
||||
# In the future, the %%python3_pkgversion macro has a dot, e.g. 3.9 or 3.11
|
||||
# However, in RHEL 8 at least, it does not, e.g. 38, 39
|
||||
# This is a helpful macro that determines the proper "Python version" string with dot
|
||||
# from %%python3_pkgversion without actually having Python installed.
|
||||
# For values other than 3X, it should expand to %%python3_pkgversion unchanged.
|
||||
# Examples of %%python3_pkgversion -> %%_python3_pkgversion_with_dot:
|
||||
# 3 -> 3
|
||||
# 38 -> 3.8
|
||||
# 39 -> 3.9
|
||||
# 310 -> 3.10
|
||||
# 3.12 -> 3.12
|
||||
# 4 -> 4
|
||||
# 412 -> 412
|
||||
%_python3_pkgversion_with_dot %{lua:print((rpm.expand("%python3_pkgversion"):gsub('^3(%d)', '3.%1')))}
|
||||
|
||||
# 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
|
||||
# macro (%py_dist_name) overwrites them
|
||||
%py3_dist() %{lua:\
|
||||
python3_pkgversion_with_dot = rpm.expand("%_python3_pkgversion_with_dot")\
|
||||
args = {}\
|
||||
arg = 1\
|
||||
while (true) do\
|
||||
name = rpm.expand("%{?" .. arg .. ":%{" .. arg .. "}}");\
|
||||
if (name == nil or name == '') then\
|
||||
break\
|
||||
end\
|
||||
args[arg] = name\
|
||||
arg = arg + 1\
|
||||
end\
|
||||
for arg, name in ipairs(args) do\
|
||||
canonical = rpm.expand("%py_dist_name " .. name);\
|
||||
print("python" .. python3_pkgversion_with_dot .. "dist(" .. canonical .. ") ");\
|
||||
end\
|
||||
}
|
||||
|
||||
# Macro to replace overly complicated references to PyPI source files.
|
||||
# Expands to the pythonhosted URL for a package
|
||||
# Accepts zero to three arguments:
|
||||
# 1: The PyPI project name, defaulting to %srcname if it is defined, then
|
||||
# %pypi_name if it is defined, then just %name.
|
||||
# 2: The PYPI version, defaulting to %version with tildes stripped.
|
||||
# 3: The file extension, defaulting to "tar.gz". (A period will be added
|
||||
# automatically.)
|
||||
# Requires %__pypi_url and %__pypi_default_extension to be defined.
|
||||
%__pypi_url https://files.pythonhosted.org/packages/source/
|
||||
%__pypi_default_extension tar.gz
|
||||
|
||||
%pypi_source() %{lua:
|
||||
local src = rpm.expand('%1')
|
||||
local ver = rpm.expand('%2')
|
||||
local ext = rpm.expand('%3')
|
||||
local url = rpm.expand('%__pypi_url')
|
||||
\
|
||||
-- If no first argument, try %srcname, then %pypi_name, then %name
|
||||
-- Note that rpm leaves macros unchanged if they are not defined.
|
||||
if src == '%1' then
|
||||
src = rpm.expand('%srcname')
|
||||
end
|
||||
if src == '%srcname' then
|
||||
src = rpm.expand('%pypi_name')
|
||||
end
|
||||
if src == '%pypi_name' then
|
||||
src = rpm.expand('%name')
|
||||
end
|
||||
\
|
||||
-- If no second argument, use %version
|
||||
if ver == '%2' then
|
||||
ver = rpm.expand('%version'):gsub('~', '')
|
||||
end
|
||||
\
|
||||
-- If no third argument, use the preset default extension
|
||||
if ext == '%3' then
|
||||
ext = rpm.expand('%__pypi_default_extension')
|
||||
end
|
||||
\
|
||||
local first = string.sub(src, 1, 1)
|
||||
\
|
||||
print(url .. first .. '/' .. src .. '/' .. src .. '-' .. ver .. '.' .. ext)
|
||||
}
|
||||
|
||||
# Python packages in RHEL 8 should not provide unversioned python- names
|
||||
# so this macro here is just a compatibility layer and only provides the given name.
|
||||
%py_provides() %{lua:
|
||||
local name = rpm.expand('%1')
|
||||
if name == '%1' then
|
||||
rpm.expand('%{error:%%py_provides requires at least 1 argument, the name to provide}')
|
||||
end
|
||||
local evr = rpm.expand('%2')
|
||||
if evr == '%2' then
|
||||
evr = rpm.expand('%{?epoch:%{epoch}:}%{version}-%{release}')
|
||||
end
|
||||
print('Provides: ' .. name .. ' = ' .. evr .. '\\n')
|
||||
}
|
41
SOURCES/macros.python2
Normal file
41
SOURCES/macros.python2
Normal file
@ -0,0 +1,41 @@
|
||||
%__python2 /usr/bin/python2
|
||||
%python2_sitelib %(RHEL_ALLOW_PYTHON2_FOR_BUILD=1 %{__python2} -Esc "from distutils.sysconfig import get_python_lib; print(get_python_lib())")
|
||||
%python2_sitearch %(RHEL_ALLOW_PYTHON2_FOR_BUILD=1 %{__python2} -Esc "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")
|
||||
%python2_version %(RHEL_ALLOW_PYTHON2_FOR_BUILD=1 %{__python2} -Esc "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
|
||||
%python2_version_nodots %(RHEL_ALLOW_PYTHON2_FOR_BUILD=1 %{__python2} -Esc "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
|
||||
|
||||
%py2_shbang_opts -s
|
||||
|
||||
# Use the slashes after expand so that the command starts on the same line as
|
||||
# the macro
|
||||
%py2_build() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python2} %{py_setup} %{?py_setup_args} build --executable="%{__python2} %{py2_shbang_opts}" %{?*}
|
||||
sleep 1
|
||||
}
|
||||
|
||||
%py2_build_egg() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python2} %{py_setup} %{?py_setup_args} bdist_egg %{?*}
|
||||
sleep 1
|
||||
}
|
||||
|
||||
%py2_build_wheel() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python2} %{py_setup} %{?py_setup_args} bdist_wheel %{?*}
|
||||
sleep 1
|
||||
}
|
||||
|
||||
%py2_install() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python2} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*}
|
||||
}
|
||||
|
||||
%py2_install_egg() %{expand:\\\
|
||||
mkdir -p %{buildroot}%{python2_sitelib}
|
||||
easy_install-%{python2_version} -m --prefix %{buildroot}%{_prefix} -Z dist/*-py%{python2_version}.egg %{?*}
|
||||
}
|
||||
|
||||
%py2_install_wheel() %{expand:\\\
|
||||
pip%{python2_version} install -I dist/%{1} --root %{buildroot} --strip-file-prefix %{buildroot} --no-deps
|
||||
}
|
85
SOURCES/macros.python3
Normal file
85
SOURCES/macros.python3
Normal file
@ -0,0 +1,85 @@
|
||||
%__python3 /usr/libexec/platform-python
|
||||
%python3 %__python3
|
||||
%python3_sitelib %(%{__python3} -Ic "from distutils.sysconfig import get_python_lib; print(get_python_lib())")
|
||||
%python3_sitearch %(%{__python3} -Ic "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")
|
||||
%python3_version %(%{__python3} -Ic "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
|
||||
%python3_version_nodots %(%{__python3} -Ic "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info).replace('.',''))")
|
||||
%python3_platform %(%{__python3} -Ic "import sysconfig; print(sysconfig.get_platform())")
|
||||
%python3_platform_triplet %(%{__python3} -Ic "import sysconfig; print(sysconfig.get_config_var('MULTIARCH'))")
|
||||
%python3_ext_suffix %(%{__python3} -Ic "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
|
||||
%py3dir %{_builddir}/python3-%{name}-%{version}-%{release}
|
||||
|
||||
%py3_shbang_opts -s
|
||||
%py3_shbang_opts_nodash %(opts=%{py3_shbang_opts}; echo ${opts#-})
|
||||
%py3_shebang_flags %(opts=%{py3_shbang_opts}; echo ${opts#-})
|
||||
%py3_shebang_fix %{expand:\\\
|
||||
if [ -f /usr/bin/pathfix%{python3_version}.py ]; then
|
||||
pathfix=/usr/bin/pathfix%{python3_version}.py
|
||||
else
|
||||
# unversioned pathfix.py provided by platform-python-devel
|
||||
pathfix=/usr/bin/pathfix.py
|
||||
fi
|
||||
if [ -z "%{?py3_shebang_flags}" ]; then
|
||||
shebang_flags="-k"
|
||||
else
|
||||
shebang_flags="-ka%{py3_shebang_flags}"
|
||||
fi
|
||||
$pathfix -pni %{__python3} $shebang_flags}
|
||||
|
||||
# Use the slashes after expand so that the command starts on the same line as
|
||||
# the macro
|
||||
%py3_build() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python3} %{py_setup} %{?py_setup_args} build --executable="%{__python3} %{py3_shbang_opts}" %{?*}
|
||||
sleep 1
|
||||
}
|
||||
|
||||
%py3_build_egg() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python3} %{py_setup} %{?py_setup_args} bdist_egg %{?*}
|
||||
sleep 1
|
||||
}
|
||||
|
||||
%py3_build_wheel() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python3} %{py_setup} %{?py_setup_args} bdist_wheel %{?*}
|
||||
sleep 1
|
||||
}
|
||||
|
||||
%py3_install() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python3} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*}
|
||||
}
|
||||
|
||||
%py3_install_egg() %{expand:\\\
|
||||
mkdir -p %{buildroot}%{python3_sitelib}
|
||||
CFLAGS="%{optflags}" %{__python3} -m easy_install -m --prefix %{buildroot}%{_prefix} -Z dist/*-py%{python3_version}.egg %{?*}
|
||||
}
|
||||
|
||||
%py3_install_wheel() %{expand:\\\
|
||||
CFLAGS="%{optflags}" %{__python3} -m pip install -I dist/%{1} --root %{buildroot} --strip-file-prefix %{buildroot} --no-deps
|
||||
}
|
||||
|
||||
# This only supports Python 3.5+ and will never work with Python 2.
|
||||
# Hence, it has no Python version in the name.
|
||||
%pycached() %{lua:
|
||||
path = rpm.expand("%{?*}")
|
||||
if (string.sub(path, "-3") ~= ".py") then
|
||||
rpm.expand("%{error:%%pycached can only be used with paths explicitly ending with .py}")
|
||||
else
|
||||
print(path)
|
||||
pyminor = path:match("/python3.(%d+)/") or "*"
|
||||
dirname = path:match("(.*/)")
|
||||
modulename = path:match(".*/([^/]+).py")
|
||||
print("\\n" .. dirname .. "__pycache__/" .. modulename .. ".cpython-3" .. pyminor .. "{,.opt-?}.pyc")
|
||||
end
|
||||
}
|
||||
|
||||
# This is intended for Python 3 only, hence also no Python version in the name.
|
||||
%__pytest /usr/bin/pytest-%{_python3_pkgversion_with_dot}
|
||||
%pytest %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
PATH="%{buildroot}%{_bindir}:$PATH"\\\
|
||||
PYTHONPATH="${PYTHONPATH:-%{buildroot}%{python3_sitearch}:%{buildroot}%{python3_sitelib}}"\\\
|
||||
PYTHONDONTWRITEBYTECODE=1\\\
|
||||
%__pytest}
|
245
SPECS/python-rpm-macros.spec
Normal file
245
SPECS/python-rpm-macros.spec
Normal file
@ -0,0 +1,245 @@
|
||||
Name: python-rpm-macros
|
||||
Version: 3
|
||||
Release: 45%{?dist}
|
||||
Summary: The unversioned Python RPM macros
|
||||
|
||||
License: MIT
|
||||
Source0: macros.python
|
||||
Source1: macros.python-srpm
|
||||
Source2: macros.python2
|
||||
Source3: macros.python3
|
||||
Source4: macros.pybytecompile
|
||||
|
||||
BuildArch: noarch
|
||||
# For %%python3_pkgversion used in %%python_provide
|
||||
Requires: python-srpm-macros
|
||||
Obsoletes: python-macros < 3
|
||||
Provides: python-macros = %{version}-%{release}
|
||||
|
||||
%description
|
||||
This package contains the unversioned Python RPM macros, that most
|
||||
implementations should rely on.
|
||||
|
||||
You should not need to install this package manually as the various
|
||||
python?-devel packages require it. So install a python-devel package instead.
|
||||
|
||||
%package -n python-srpm-macros
|
||||
Summary: RPM macros for building Python source packages
|
||||
|
||||
%description -n python-srpm-macros
|
||||
RPM macros for building Python source packages.
|
||||
|
||||
%package -n python2-rpm-macros
|
||||
Summary: RPM macros for building Python 2 packages
|
||||
# For %%py_setup
|
||||
Requires: python-rpm-macros = %{version}-%{release}
|
||||
|
||||
%description -n python2-rpm-macros
|
||||
RPM macros for building Python 2 packages.
|
||||
|
||||
%package -n python3-rpm-macros
|
||||
Summary: RPM macros for building Python 3 packages
|
||||
# Older versions have old pathfix.py without -ka options support
|
||||
Conflicts: platform-python-devel < 3.6.8-35
|
||||
# For %%py_setup
|
||||
Requires: python-rpm-macros = %{version}-%{release}
|
||||
# For %%_python3_pkgversion_with_dot needed by %%__pytest
|
||||
Requires: python-srpm-macros = %{version}-%{release}
|
||||
|
||||
%description -n python3-rpm-macros
|
||||
RPM macros for building Python 3 packages.
|
||||
|
||||
|
||||
%prep
|
||||
|
||||
%build
|
||||
|
||||
%install
|
||||
mkdir -p %{buildroot}/%{rpmmacrodir}
|
||||
install -m 644 %{SOURCE0} %{SOURCE1} %{SOURCE2} %{SOURCE3} %{SOURCE4} \
|
||||
%{buildroot}/%{rpmmacrodir}/
|
||||
|
||||
|
||||
%files
|
||||
%{rpmmacrodir}/macros.python
|
||||
%{rpmmacrodir}/macros.pybytecompile
|
||||
|
||||
%files -n python-srpm-macros
|
||||
%{rpmmacrodir}/macros.python-srpm
|
||||
|
||||
%files -n python2-rpm-macros
|
||||
%{rpmmacrodir}/macros.python2
|
||||
|
||||
%files -n python3-rpm-macros
|
||||
%{rpmmacrodir}/macros.python3
|
||||
|
||||
|
||||
%changelog
|
||||
* Wed Feb 22 2023 Miro Hrončok <mhroncok@redhat.com> - 3-45
|
||||
- Fix %%python3_version macros for Python 3.10+
|
||||
Resolves: rhbz#2169780
|
||||
|
||||
* Fri Oct 14 2022 Charalampos Stratakis <cstratak@redhat.com> - 3-44
|
||||
- Backport the %%python_wheel_pkg_prefix and the %%python_wheel_dir macros from Fedora
|
||||
Resolves: rhbz#2143991
|
||||
|
||||
* Tue Jul 26 2022 Tomas Orsava <torsava@redhat.com> - 3-43
|
||||
- Make %%pytest macro respect %%python3_pkgversion
|
||||
Resolves: rhbz#2091462
|
||||
|
||||
* Wed May 25 2022 Miro Hrončok <mhroncok@redhat.com> - 3-42
|
||||
- Make %%py3_dist respect %%python3_pkgversion
|
||||
Resolves: rhbz#2090007
|
||||
|
||||
* Mon Feb 01 2021 Lumír Balhar <lbalhar@redhat.com> - 3-41
|
||||
- Fix dependencies between subpackages
|
||||
Resolves: rhbz#1892797
|
||||
|
||||
* Thu Jan 14 2021 Lumír Balhar <lbalhar@redhat.com> - 3-40
|
||||
- New macros backported from Fedora/EPEL
|
||||
Resolves: rhbz#1892797
|
||||
|
||||
* Tue Jun 16 2020 Charalampos Stratakis <cstratak@redhat.com> - 3-39
|
||||
- Strip tildes from %%version in %%pypi_source by default
|
||||
- Resolves: rhbz#1844902
|
||||
|
||||
* Mon Oct 14 2019 Charalampos Stratakis <cstratak@redhat.com> - 3-38
|
||||
- Fix the %%py_build macro to respect the global definition of %%__python
|
||||
- Resolves: rhbz#1757833
|
||||
|
||||
* Fri Dec 14 2018 Miro Hrončok <mhroncok@redhat.com> - 3-37
|
||||
- Workaround leaking buildroot PATH in %py_byte_compile
|
||||
- Resolves: rhbz#1644455
|
||||
|
||||
* Fri Dec 14 2018 Miro Hrončok <mhroncok@redhat.com> - 3-36
|
||||
- Make %%py_byte_compile terminate build on SyntaxErrors
|
||||
- Resolves: rhbz#1620168
|
||||
|
||||
* Mon Sep 17 2018 Tomas Orsava <torsava@redhat.com> - 3-35
|
||||
- Disable the python_provide macro for `python2-` prefixed packages
|
||||
- Resolves: rhbz#1636029
|
||||
|
||||
* Mon Jul 16 2018 Tomas Orsava <torsava@redhat.com> - 3-34
|
||||
- macros.pybytecompile: Macro was not line-continued properly and thus didn't work
|
||||
|
||||
* Wed Jul 11 2018 Tomas Orsava <torsava@redhat.com> - 3-33
|
||||
- macros.pybytecompile: Detect Python version through sys.version_info instead
|
||||
of guessing from the executable name
|
||||
|
||||
* Tue Jul 10 2018 Tomas Orsava <torsava@redhat.com> - 3-32
|
||||
- Merging: (Tue Jul 10 2018 Tomas Orsava <torsava@redhat.com> - 3-32)
|
||||
- Fix %%py_byte_compile macro: when invoked with a Python 2 binary it also
|
||||
mistakenly ran py3_byte_compile
|
||||
- Merging: (Tue Jul 03 2018 Miro Hrončok <mhroncok@redhat.com> - 3-31)
|
||||
- Add %%python3_platform useful for PYTHONPATH on arched builds
|
||||
- Merging: (Mon Jun 18 2018 Jason L Tibbitts III <tibbs@math.uh.edu> - 3-30)
|
||||
- Add %%pypi_source macro, as well as %%__pypi_url and
|
||||
%%_pypi_default_extension.
|
||||
- Merging: (Wed Apr 18 2018 Miro Hrončok <mhroncok@redhat.com> - 3-29)
|
||||
- move macros.pybytecompile from python3-devel
|
||||
|
||||
* Wed Jun 27 2018 Tomas Orsava <torsava@redhat.com> - 3-31
|
||||
- Remove RHEL_ALLOW_PYTHON2_FOR_BUILD=1 from build and install macros,
|
||||
as that is where the user needs to set it themself
|
||||
|
||||
* Thu Jun 21 2018 Tomas Orsava <torsava@redhat.com> - 3-30
|
||||
- Explicitly enable Python 2 when invoking Python 2 macros
|
||||
See: https://url.corp.redhat.com/rhel8-py2
|
||||
|
||||
* Wed May 09 2018 Tomas Orsava <torsava@redhat.com> - 3-29
|
||||
- Switch the Python 3 executable to /usr/libexec/platform-python
|
||||
- Update macros using pip or easy_install to be invoked through the main
|
||||
executable
|
||||
|
||||
* Fri Apr 06 2018 Tomas Orsava <torsava@redhat.com> - 3-28
|
||||
- Fix the %%py_dist_name macro to not convert dots (".") into dashes, so that
|
||||
submodules can be addressed as well
|
||||
Resolves: rhbz#1564095
|
||||
|
||||
* Fri Mar 23 2018 Miro Hrončok <mhroncok@redhat.com> - 3-27
|
||||
- make LDFLAGS propagated whenever CFLAGS are
|
||||
|
||||
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 3-26
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
|
||||
|
||||
* Fri Jan 19 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 3-25
|
||||
- Add %%python_enable_dependency_generator
|
||||
|
||||
* Tue Nov 28 2017 Tomas Orsava <torsava@redhat.com> - 3-24
|
||||
- Remove platform-python macros (https://fedoraproject.org/wiki/Changes/Platform_Python_Stack)
|
||||
|
||||
* Thu Oct 26 2017 Ville Skyttä <ville.skytta@iki.fi> - 3-23
|
||||
- Use -Es/-I to invoke macro scriptlets (#1506355)
|
||||
|
||||
* Wed Aug 02 2017 Tomas Orsava <torsava@redhat.com> - 3-22
|
||||
- Add platform-python macros (https://fedoraproject.org/wiki/Changes/Platform_Python_Stack)
|
||||
|
||||
* Thu Jul 27 2017 Fedora Release Engineering <releng@fedoraproject.org> - 3-21
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
|
||||
|
||||
* Fri Mar 03 2017 Michal Cyprian <mcyprian@redhat.com> - 3-20
|
||||
- Revert "Switch %%__python3 to /usr/libexec/system-python"
|
||||
after the Fedora Change https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe
|
||||
was postponed
|
||||
|
||||
* Fri Feb 17 2017 Michal Cyprian <mcyprian@redhat.com> - 3-19
|
||||
- Switch %%__python3 to /usr/libexec/system-python
|
||||
|
||||
* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 3-18
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
|
||||
|
||||
* Mon Jan 23 2017 Michal Cyprian <mcyprian@redhat.com> - 3-17
|
||||
- Add --no-deps option to py_install_wheel macros
|
||||
|
||||
* Tue Jan 17 2017 Tomas Orsava <torsava@redhat.com> - 3-16
|
||||
- Added macros for Build/Requires tags using Python dist tags:
|
||||
https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages
|
||||
|
||||
* Thu Nov 24 2016 Orion Poplawski <orion@cora.nwra.com> 3-15
|
||||
- Make expanded macros start on the same line as the macro
|
||||
|
||||
* Wed Nov 16 2016 Orion Poplawski <orion@cora.nwra.com> 3-14
|
||||
- Fix %%py3_install_wheel (bug #1395953)
|
||||
|
||||
* Wed Nov 16 2016 Orion Poplawski <orion@cora.nwra.com> 3-13
|
||||
- Add missing sleeps to other build macros
|
||||
- Fix build_egg macros
|
||||
- Add %%py_build_wheel and %%py_install_wheel macros
|
||||
|
||||
* Tue Nov 15 2016 Orion Poplawski <orion@cora.nwra.com> 3-12
|
||||
- Add %%py_build_egg and %%py_install_egg macros
|
||||
- Allow multiple args to %%py_build/install macros
|
||||
- Tidy up macro formatting
|
||||
|
||||
* Wed Aug 24 2016 Orion Poplawski <orion@cora.nwra.com> 3-11
|
||||
- Use %%rpmmacrodir
|
||||
|
||||
* Tue Jul 12 2016 Orion Poplawski <orion@cora.nwra.com> 3-10
|
||||
- Do not generate useless Obsoletes with %%{?_isa}
|
||||
|
||||
* Fri May 13 2016 Orion Poplawski <orion@cora.nwra.com> 3-9
|
||||
- Make python-rpm-macros require python-srpm-macros (bug #1335860)
|
||||
|
||||
* Thu May 12 2016 Jason L Tibbitts III <tibbs@math.uh.edu> - 3-8
|
||||
- Add single-second sleeps to work around setuptools bug.
|
||||
|
||||
* Thu Feb 04 2016 Fedora Release Engineering <releng@fedoraproject.org> - 3-7
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
|
||||
|
||||
* Thu Jan 14 2016 Orion Poplawski <orion@cora.nwra.com> 3-6
|
||||
- Fix typo in %%python_provide
|
||||
|
||||
* Thu Jan 14 2016 Orion Poplawski <orion@cora.nwra.com> 3-5
|
||||
- Handle noarch python sub-packages (bug #1290900)
|
||||
|
||||
* Wed Jan 13 2016 Orion Poplawski <orion@cora.nwra.com> 3-4
|
||||
- Fix python2/3-rpm-macros package names
|
||||
|
||||
* Thu Jan 7 2016 Orion Poplawski <orion@cora.nwra.com> 3-3
|
||||
- Add empty %%prep and %%build
|
||||
|
||||
* Mon Jan 4 2016 Orion Poplawski <orion@cora.nwra.com> 3-2
|
||||
- Combined package
|
||||
|
||||
* Wed Dec 30 2015 Orion Poplawski <orion@cora.nwra.com> 3-1
|
||||
- Initial package
|
@ -1,20 +0,0 @@
|
||||
#!/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
|
@ -1,157 +0,0 @@
|
||||
#!/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
|
||||
|
||||
compileall_flags="$4"
|
||||
|
||||
# If using normal root, avoid changing anything.
|
||||
if [ -z "$RPM_BUILD_ROOT" -o "$RPM_BUILD_ROOT" = "/" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# This function clamps the source mtime, see https://fedoraproject.org/wiki/Changes/ReproducibleBuildsClampMtimes
|
||||
function python_clamp_source_mtime()
|
||||
{
|
||||
local _=$1
|
||||
local python_binary=$2
|
||||
local _=$3
|
||||
local python_libdir="$4"
|
||||
PYTHONPATH=/usr/lib/rpm/redhat/ $python_binary -B -m clamp_source_mtime -q "$python_libdir"
|
||||
}
|
||||
|
||||
# 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"
|
||||
local compileall_flags="$5"
|
||||
|
||||
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
|
||||
|
||||
if [ "$python_version" -ge 37 ]; then
|
||||
# Force the TIMESTAMP invalidation mode
|
||||
invalidation_option=--invalidation-mode=timestamp
|
||||
else
|
||||
# For older Pythons, the option does not exist
|
||||
# as the invalidation is always based on size+mtime
|
||||
invalidation_option=
|
||||
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 $compileall_flags -o 0 -o 1 -q -f $exclude -s "$RPM_BUILD_ROOT" -p / --hardlink-dupes $invalidation_option -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_clamp_source_mtime "" "$python_binary" "" "$python_libdir" ""
|
||||
if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then
|
||||
# One or more of the files had inaccessible mtime
|
||||
exit 1
|
||||
fi
|
||||
python_bytecompile "" "$python_binary" "" "$python_libdir" "$compileall_flags"
|
||||
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" "$compileall_flags"
|
||||
if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then
|
||||
# One or more of the files had a syntax error
|
||||
exit 1
|
||||
fi
|
||||
done
|
@ -1,25 +0,0 @@
|
||||
#!/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
|
@ -1,163 +0,0 @@
|
||||
"""Module/script to clamp the mtimes of all .py files to $SOURCE_DATE_EPOCH
|
||||
|
||||
When called as a script with arguments, this compiles the directories
|
||||
given as arguments recursively.
|
||||
|
||||
If upstream is interested, this can be later integrated to the compileall module
|
||||
as an additional option (e.g. --clamp-source-mtime).
|
||||
|
||||
License:
|
||||
This has been derived from the Python's compileall module
|
||||
and it follows Python licensing. For more info see: https://www.python.org/psf/license/
|
||||
"""
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Python 3.6 and higher
|
||||
PY36 = sys.version_info[0:2] >= (3, 6)
|
||||
|
||||
__all__ = ["clamp_dir", "clamp_file"]
|
||||
|
||||
|
||||
def _walk_dir(dir, maxlevels, quiet=0):
|
||||
if PY36 and quiet < 2 and isinstance(dir, os.PathLike):
|
||||
dir = os.fspath(dir)
|
||||
else:
|
||||
dir = str(dir)
|
||||
if not quiet:
|
||||
print('Listing {!r}...'.format(dir))
|
||||
try:
|
||||
names = os.listdir(dir)
|
||||
except OSError:
|
||||
if quiet < 2:
|
||||
print("Can't list {!r}".format(dir))
|
||||
names = []
|
||||
names.sort()
|
||||
for name in names:
|
||||
if name == '__pycache__':
|
||||
continue
|
||||
fullname = os.path.join(dir, name)
|
||||
if not os.path.isdir(fullname):
|
||||
yield fullname
|
||||
elif (maxlevels > 0 and name != os.curdir and name != os.pardir and
|
||||
os.path.isdir(fullname) and not os.path.islink(fullname)):
|
||||
for result in _walk_dir(fullname, maxlevels=maxlevels - 1,
|
||||
quiet=quiet):
|
||||
yield result
|
||||
|
||||
|
||||
def clamp_dir(dir, source_date_epoch, quiet=0):
|
||||
"""Clamp the mtime of all modules in the given directory tree.
|
||||
|
||||
Arguments:
|
||||
|
||||
dir: the directory to byte-compile
|
||||
source_date_epoch: integer parsed from $SOURCE_DATE_EPOCH
|
||||
quiet: full output with False or 0, errors only with 1,
|
||||
no output with 2
|
||||
"""
|
||||
maxlevels = sys.getrecursionlimit()
|
||||
files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels)
|
||||
success = True
|
||||
for file in files:
|
||||
if not clamp_file(file, source_date_epoch, quiet=quiet):
|
||||
success = False
|
||||
return success
|
||||
|
||||
|
||||
def clamp_file(fullname, source_date_epoch, quiet=0):
|
||||
"""Clamp the mtime of one file.
|
||||
|
||||
Arguments:
|
||||
|
||||
fullname: the file to byte-compile
|
||||
source_date_epoch: integer parsed from $SOURCE_DATE_EPOCH
|
||||
quiet: full output with False or 0, errors only with 1,
|
||||
no output with 2
|
||||
"""
|
||||
if PY36 and quiet < 2 and isinstance(fullname, os.PathLike):
|
||||
fullname = os.fspath(fullname)
|
||||
else:
|
||||
fullname = str(fullname)
|
||||
name = os.path.basename(fullname)
|
||||
|
||||
if os.path.isfile(fullname) and not os.path.islink(fullname):
|
||||
if name[-3:] == '.py':
|
||||
try:
|
||||
mtime = int(os.stat(fullname).st_mtime)
|
||||
atime = int(os.stat(fullname).st_atime)
|
||||
except OSError as e:
|
||||
if quiet >= 2:
|
||||
return False
|
||||
elif quiet:
|
||||
print('*** Error checking mtime of {!r}...'.format(fullname))
|
||||
else:
|
||||
print('*** ', end='')
|
||||
print(e.__class__.__name__ + ':', e)
|
||||
return False
|
||||
if mtime > source_date_epoch:
|
||||
if not quiet:
|
||||
print('Clamping mtime of {!r}'.format(fullname))
|
||||
try:
|
||||
os.utime(fullname, (atime, source_date_epoch))
|
||||
except OSError as e:
|
||||
if quiet >= 2:
|
||||
return False
|
||||
elif quiet:
|
||||
print('*** Error clamping mtime of {!r}...'.format(fullname))
|
||||
else:
|
||||
print('*** ', end='')
|
||||
print(e.__class__.__name__ + ':', e)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
"""Script main program."""
|
||||
import argparse
|
||||
|
||||
source_date_epoch = os.getenv('SOURCE_DATE_EPOCH')
|
||||
if not source_date_epoch:
|
||||
print("Not clamping source mtimes, $SOURCE_DATE_EPOCH not set")
|
||||
return True # This is a success, no action needed
|
||||
try:
|
||||
source_date_epoch = int(source_date_epoch)
|
||||
except ValueError:
|
||||
print("$SOURCE_DATE_EPOCH must be an integer")
|
||||
return False
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Clamp .py source mtime to $SOURCE_DATE_EPOCH.')
|
||||
parser.add_argument('-q', action='count', dest='quiet', default=0,
|
||||
help='output only error messages; -qq will suppress '
|
||||
'the error messages as well.')
|
||||
parser.add_argument('clamp_dest', metavar='FILE|DIR', nargs='+',
|
||||
help=('zero or more file and directory paths '
|
||||
'to clamp'))
|
||||
|
||||
args = parser.parse_args()
|
||||
clamp_dests = args.clamp_dest
|
||||
|
||||
success = True
|
||||
try:
|
||||
for dest in clamp_dests:
|
||||
if os.path.isfile(dest):
|
||||
if not clamp_file(dest, quiet=args.quiet,
|
||||
source_date_epoch=source_date_epoch):
|
||||
success = False
|
||||
else:
|
||||
if not clamp_dir(dest, quiet=args.quiet,
|
||||
source_date_epoch=source_date_epoch):
|
||||
success = False
|
||||
return success
|
||||
except KeyboardInterrupt:
|
||||
if args.quiet < 2:
|
||||
print("\n[interrupted]")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit_status = int(not main())
|
||||
sys.exit(exit_status)
|
515
compileall2.py
515
compileall2.py
@ -1,515 +0,0 @@
|
||||
"""Module/script to byte-compile all .py files to .pyc files.
|
||||
|
||||
When called as a script with arguments, this compiles the directories
|
||||
given as arguments recursively; the -l option prevents it from
|
||||
recursing into directories.
|
||||
|
||||
Without arguments, if compiles all modules on sys.path, without
|
||||
recursing into subdirectories. (Even though it should do so for
|
||||
packages -- for now, you'll have to deal with packages separately.)
|
||||
|
||||
See module py_compile for details of the actual byte-compilation.
|
||||
|
||||
License:
|
||||
Compileall2 is an enhanced copy of Python's compileall module
|
||||
and it follows Python licensing. For more info see: https://www.python.org/psf/license/
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import importlib.util
|
||||
import py_compile
|
||||
import struct
|
||||
import filecmp
|
||||
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
|
||||
# Python 3.7 and higher
|
||||
PY37 = sys.version_info[0:2] >= (3, 7)
|
||||
# Python 3.6 and higher
|
||||
PY36 = sys.version_info[0:2] >= (3, 6)
|
||||
# Python 3.5 and higher
|
||||
PY35 = sys.version_info[0:2] >= (3, 5)
|
||||
|
||||
# Python 3.7 and above has a different structure and length
|
||||
# of pyc files header. Also, multiple ways how to invalidate pyc file was
|
||||
# introduced in Python 3.7. These cases are covered by variables here or by PY37
|
||||
# variable itself.
|
||||
if PY37:
|
||||
pyc_struct_format = '<4sll'
|
||||
pyc_header_lenght = 12
|
||||
pyc_header_format = (pyc_struct_format, importlib.util.MAGIC_NUMBER, 0)
|
||||
else:
|
||||
pyc_struct_format = '<4sl'
|
||||
pyc_header_lenght = 8
|
||||
pyc_header_format = (pyc_struct_format, importlib.util.MAGIC_NUMBER)
|
||||
|
||||
__all__ = ["compile_dir","compile_file","compile_path"]
|
||||
|
||||
def optimization_kwarg(opt):
|
||||
"""Returns opt as a dictionary {optimization: opt} for use as **kwarg
|
||||
for Python >= 3.5 and empty dictionary for Python 3.4"""
|
||||
if PY35:
|
||||
return dict(optimization=opt)
|
||||
else:
|
||||
# `debug_override` is a way how to enable optimized byte-compiled files
|
||||
# (.pyo) in Python <= 3.4
|
||||
if opt:
|
||||
return dict(debug_override=False)
|
||||
else:
|
||||
return dict()
|
||||
|
||||
def _walk_dir(dir, maxlevels, quiet=0):
|
||||
if PY36 and quiet < 2 and isinstance(dir, os.PathLike):
|
||||
dir = os.fspath(dir)
|
||||
else:
|
||||
dir = str(dir)
|
||||
if not quiet:
|
||||
print('Listing {!r}...'.format(dir))
|
||||
try:
|
||||
names = os.listdir(dir)
|
||||
except OSError:
|
||||
if quiet < 2:
|
||||
print("Can't list {!r}".format(dir))
|
||||
names = []
|
||||
names.sort()
|
||||
for name in names:
|
||||
if name == '__pycache__':
|
||||
continue
|
||||
fullname = os.path.join(dir, name)
|
||||
if not os.path.isdir(fullname):
|
||||
yield fullname
|
||||
elif (maxlevels > 0 and name != os.curdir and name != os.pardir and
|
||||
os.path.isdir(fullname) and not os.path.islink(fullname)):
|
||||
yield from _walk_dir(fullname, maxlevels=maxlevels - 1,
|
||||
quiet=quiet)
|
||||
|
||||
def compile_dir(dir, maxlevels=None, ddir=None, force=False,
|
||||
rx=None, quiet=0, legacy=False, optimize=-1, workers=1,
|
||||
invalidation_mode=None, stripdir=None,
|
||||
prependdir=None, limit_sl_dest=None, hardlink_dupes=False):
|
||||
"""Byte-compile all modules in the given directory tree.
|
||||
|
||||
Arguments (only dir is required):
|
||||
|
||||
dir: the directory to byte-compile
|
||||
maxlevels: maximum recursion level (default `sys.getrecursionlimit()`)
|
||||
ddir: the directory that will be prepended to the path to the
|
||||
file as it is compiled into each byte-code file.
|
||||
force: if True, force compilation, even if timestamps are up-to-date
|
||||
quiet: full output with False or 0, errors only with 1,
|
||||
no output with 2
|
||||
legacy: if True, produce legacy pyc paths instead of PEP 3147 paths
|
||||
optimize: int or list of optimization levels or -1 for level of
|
||||
the interpreter. Multiple levels leads to multiple compiled
|
||||
files each with one optimization level.
|
||||
workers: maximum number of parallel workers
|
||||
invalidation_mode: how the up-to-dateness of the pyc will be checked
|
||||
stripdir: part of path to left-strip from source file path
|
||||
prependdir: path to prepend to beggining of original file path, applied
|
||||
after stripdir
|
||||
limit_sl_dest: ignore symlinks if they are pointing outside of
|
||||
the defined path
|
||||
hardlink_dupes: hardlink duplicated pyc files
|
||||
"""
|
||||
ProcessPoolExecutor = None
|
||||
if ddir is not None and (stripdir is not None or prependdir is not None):
|
||||
raise ValueError(("Destination dir (ddir) cannot be used "
|
||||
"in combination with stripdir or prependdir"))
|
||||
if ddir is not None:
|
||||
stripdir = dir
|
||||
prependdir = ddir
|
||||
ddir = None
|
||||
if workers is not None:
|
||||
if workers < 0:
|
||||
raise ValueError('workers must be greater or equal to 0')
|
||||
elif workers != 1:
|
||||
try:
|
||||
# Only import when needed, as low resource platforms may
|
||||
# fail to import it
|
||||
from concurrent.futures import ProcessPoolExecutor
|
||||
except ImportError:
|
||||
workers = 1
|
||||
if maxlevels is None:
|
||||
maxlevels = sys.getrecursionlimit()
|
||||
files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels)
|
||||
success = True
|
||||
if workers is not None and workers != 1 and ProcessPoolExecutor is not None:
|
||||
workers = workers or None
|
||||
with ProcessPoolExecutor(max_workers=workers) as executor:
|
||||
results = executor.map(partial(compile_file,
|
||||
ddir=ddir, force=force,
|
||||
rx=rx, quiet=quiet,
|
||||
legacy=legacy,
|
||||
optimize=optimize,
|
||||
invalidation_mode=invalidation_mode,
|
||||
stripdir=stripdir,
|
||||
prependdir=prependdir,
|
||||
limit_sl_dest=limit_sl_dest),
|
||||
files)
|
||||
success = min(results, default=True)
|
||||
else:
|
||||
for file in files:
|
||||
if not compile_file(file, ddir, force, rx, quiet,
|
||||
legacy, optimize, invalidation_mode,
|
||||
stripdir=stripdir, prependdir=prependdir,
|
||||
limit_sl_dest=limit_sl_dest,
|
||||
hardlink_dupes=hardlink_dupes):
|
||||
success = False
|
||||
return success
|
||||
|
||||
def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
|
||||
legacy=False, optimize=-1,
|
||||
invalidation_mode=None, stripdir=None, prependdir=None,
|
||||
limit_sl_dest=None, hardlink_dupes=False):
|
||||
"""Byte-compile one file.
|
||||
|
||||
Arguments (only fullname is required):
|
||||
|
||||
fullname: the file to byte-compile
|
||||
ddir: if given, the directory name compiled in to the
|
||||
byte-code file.
|
||||
force: if True, force compilation, even if timestamps are up-to-date
|
||||
quiet: full output with False or 0, errors only with 1,
|
||||
no output with 2
|
||||
legacy: if True, produce legacy pyc paths instead of PEP 3147 paths
|
||||
optimize: int or list of optimization levels or -1 for level of
|
||||
the interpreter. Multiple levels leads to multiple compiled
|
||||
files each with one optimization level.
|
||||
invalidation_mode: how the up-to-dateness of the pyc will be checked
|
||||
stripdir: part of path to left-strip from source file path
|
||||
prependdir: path to prepend to beggining of original file path, applied
|
||||
after stripdir
|
||||
limit_sl_dest: ignore symlinks if they are pointing outside of
|
||||
the defined path.
|
||||
hardlink_dupes: hardlink duplicated pyc files
|
||||
"""
|
||||
|
||||
if ddir is not None and (stripdir is not None or prependdir is not None):
|
||||
raise ValueError(("Destination dir (ddir) cannot be used "
|
||||
"in combination with stripdir or prependdir"))
|
||||
|
||||
success = True
|
||||
if PY36 and quiet < 2 and isinstance(fullname, os.PathLike):
|
||||
fullname = os.fspath(fullname)
|
||||
else:
|
||||
fullname = str(fullname)
|
||||
name = os.path.basename(fullname)
|
||||
|
||||
dfile = None
|
||||
|
||||
if ddir is not None:
|
||||
if not PY36:
|
||||
ddir = str(ddir)
|
||||
dfile = os.path.join(ddir, name)
|
||||
|
||||
if stripdir is not None:
|
||||
fullname_parts = fullname.split(os.path.sep)
|
||||
stripdir_parts = stripdir.split(os.path.sep)
|
||||
ddir_parts = list(fullname_parts)
|
||||
|
||||
for spart, opart in zip(stripdir_parts, fullname_parts):
|
||||
if spart == opart:
|
||||
ddir_parts.remove(spart)
|
||||
|
||||
dfile = os.path.join(*ddir_parts)
|
||||
|
||||
if prependdir is not None:
|
||||
if dfile is None:
|
||||
dfile = os.path.join(prependdir, fullname)
|
||||
else:
|
||||
dfile = os.path.join(prependdir, dfile)
|
||||
|
||||
if isinstance(optimize, int):
|
||||
optimize = [optimize]
|
||||
|
||||
if hardlink_dupes:
|
||||
raise ValueError(("Hardlinking of duplicated bytecode makes sense "
|
||||
"only for more than one optimization level."))
|
||||
|
||||
if rx is not None:
|
||||
mo = rx.search(fullname)
|
||||
if mo:
|
||||
return success
|
||||
|
||||
if limit_sl_dest is not None and os.path.islink(fullname):
|
||||
if Path(limit_sl_dest).resolve() not in Path(fullname).resolve().parents:
|
||||
return success
|
||||
|
||||
opt_cfiles = {}
|
||||
|
||||
if os.path.isfile(fullname):
|
||||
for opt_level in optimize:
|
||||
if legacy:
|
||||
opt_cfiles[opt_level] = fullname + 'c'
|
||||
else:
|
||||
if opt_level >= 0:
|
||||
opt = opt_level if opt_level >= 1 else ''
|
||||
opt_kwarg = optimization_kwarg(opt)
|
||||
cfile = (importlib.util.cache_from_source(
|
||||
fullname, **opt_kwarg))
|
||||
opt_cfiles[opt_level] = cfile
|
||||
else:
|
||||
cfile = importlib.util.cache_from_source(fullname)
|
||||
opt_cfiles[opt_level] = cfile
|
||||
|
||||
head, tail = name[:-3], name[-3:]
|
||||
if tail == '.py':
|
||||
if not force:
|
||||
try:
|
||||
mtime = int(os.stat(fullname).st_mtime)
|
||||
expect = struct.pack(*(pyc_header_format + (mtime,)))
|
||||
for cfile in opt_cfiles.values():
|
||||
with open(cfile, 'rb') as chandle:
|
||||
actual = chandle.read(pyc_header_lenght)
|
||||
if expect != actual:
|
||||
break
|
||||
else:
|
||||
return success
|
||||
except OSError:
|
||||
pass
|
||||
if not quiet:
|
||||
print('Compiling {!r}...'.format(fullname))
|
||||
try:
|
||||
for index, opt_level in enumerate(sorted(optimize)):
|
||||
cfile = opt_cfiles[opt_level]
|
||||
if PY37:
|
||||
ok = py_compile.compile(fullname, cfile, dfile, True,
|
||||
optimize=opt_level,
|
||||
invalidation_mode=invalidation_mode)
|
||||
else:
|
||||
ok = py_compile.compile(fullname, cfile, dfile, True,
|
||||
optimize=opt_level)
|
||||
|
||||
if index > 0 and hardlink_dupes:
|
||||
previous_cfile = opt_cfiles[optimize[index - 1]]
|
||||
if previous_cfile == cfile and optimize[0] not in (1, 2):
|
||||
# Python 3.4 has only one .pyo file for -O and -OO so
|
||||
# we hardlink it only if there is a .pyc file
|
||||
# with the same content
|
||||
previous_cfile = opt_cfiles[optimize[0]]
|
||||
if previous_cfile != cfile and filecmp.cmp(cfile, previous_cfile, shallow=False):
|
||||
os.unlink(cfile)
|
||||
os.link(previous_cfile, cfile)
|
||||
|
||||
except py_compile.PyCompileError as err:
|
||||
success = False
|
||||
if quiet >= 2:
|
||||
return success
|
||||
elif quiet:
|
||||
print('*** Error compiling {!r}...'.format(fullname))
|
||||
else:
|
||||
print('*** ', end='')
|
||||
# escape non-printable characters in msg
|
||||
msg = err.msg.encode(sys.stdout.encoding,
|
||||
errors='backslashreplace')
|
||||
msg = msg.decode(sys.stdout.encoding)
|
||||
print(msg)
|
||||
except (SyntaxError, UnicodeError, OSError) as e:
|
||||
success = False
|
||||
if quiet >= 2:
|
||||
return success
|
||||
elif quiet:
|
||||
print('*** Error compiling {!r}...'.format(fullname))
|
||||
else:
|
||||
print('*** ', end='')
|
||||
print(e.__class__.__name__ + ':', e)
|
||||
else:
|
||||
if ok == 0:
|
||||
success = False
|
||||
return success
|
||||
|
||||
def compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=0,
|
||||
legacy=False, optimize=-1,
|
||||
invalidation_mode=None):
|
||||
"""Byte-compile all module on sys.path.
|
||||
|
||||
Arguments (all optional):
|
||||
|
||||
skip_curdir: if true, skip current directory (default True)
|
||||
maxlevels: max recursion level (default 0)
|
||||
force: as for compile_dir() (default False)
|
||||
quiet: as for compile_dir() (default 0)
|
||||
legacy: as for compile_dir() (default False)
|
||||
optimize: as for compile_dir() (default -1)
|
||||
invalidation_mode: as for compiler_dir()
|
||||
"""
|
||||
success = True
|
||||
for dir in sys.path:
|
||||
if (not dir or dir == os.curdir) and skip_curdir:
|
||||
if quiet < 2:
|
||||
print('Skipping current directory')
|
||||
else:
|
||||
success = success and compile_dir(
|
||||
dir,
|
||||
maxlevels,
|
||||
None,
|
||||
force,
|
||||
quiet=quiet,
|
||||
legacy=legacy,
|
||||
optimize=optimize,
|
||||
invalidation_mode=invalidation_mode,
|
||||
)
|
||||
return success
|
||||
|
||||
|
||||
def main():
|
||||
"""Script main program."""
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Utilities to support installing Python libraries.')
|
||||
parser.add_argument('-l', action='store_const', const=0,
|
||||
default=None, dest='maxlevels',
|
||||
help="don't recurse into subdirectories")
|
||||
parser.add_argument('-r', type=int, dest='recursion',
|
||||
help=('control the maximum recursion level. '
|
||||
'if `-l` and `-r` options are specified, '
|
||||
'then `-r` takes precedence.'))
|
||||
parser.add_argument('-f', action='store_true', dest='force',
|
||||
help='force rebuild even if timestamps are up to date')
|
||||
parser.add_argument('-q', action='count', dest='quiet', default=0,
|
||||
help='output only error messages; -qq will suppress '
|
||||
'the error messages as well.')
|
||||
parser.add_argument('-b', action='store_true', dest='legacy',
|
||||
help='use legacy (pre-PEP3147) compiled file locations')
|
||||
parser.add_argument('-d', metavar='DESTDIR', dest='ddir', default=None,
|
||||
help=('directory to prepend to file paths for use in '
|
||||
'compile-time tracebacks and in runtime '
|
||||
'tracebacks in cases where the source file is '
|
||||
'unavailable'))
|
||||
parser.add_argument('-s', metavar='STRIPDIR', dest='stripdir',
|
||||
default=None,
|
||||
help=('part of path to left-strip from path '
|
||||
'to source file - for example buildroot. '
|
||||
'`-d` and `-s` options cannot be '
|
||||
'specified together.'))
|
||||
parser.add_argument('-p', metavar='PREPENDDIR', dest='prependdir',
|
||||
default=None,
|
||||
help=('path to add as prefix to path '
|
||||
'to source file - for example / to make '
|
||||
'it absolute when some part is removed '
|
||||
'by `-s` option. '
|
||||
'`-d` and `-p` options cannot be '
|
||||
'specified together.'))
|
||||
parser.add_argument('-x', metavar='REGEXP', dest='rx', default=None,
|
||||
help=('skip files matching the regular expression; '
|
||||
'the regexp is searched for in the full path '
|
||||
'of each file considered for compilation'))
|
||||
parser.add_argument('-i', metavar='FILE', dest='flist',
|
||||
help=('add all the files and directories listed in '
|
||||
'FILE to the list considered for compilation; '
|
||||
'if "-", names are read from stdin'))
|
||||
parser.add_argument('compile_dest', metavar='FILE|DIR', nargs='*',
|
||||
help=('zero or more file and directory names '
|
||||
'to compile; if no arguments given, defaults '
|
||||
'to the equivalent of -l sys.path'))
|
||||
parser.add_argument('-j', '--workers', default=1,
|
||||
type=int, help='Run compileall concurrently')
|
||||
parser.add_argument('-o', action='append', type=int, dest='opt_levels',
|
||||
help=('Optimization levels to run compilation with. '
|
||||
'Default is -1 which uses optimization level of '
|
||||
'Python interpreter itself (specified by -O).'))
|
||||
parser.add_argument('-e', metavar='DIR', dest='limit_sl_dest',
|
||||
help='Ignore symlinks pointing outsite of the DIR')
|
||||
parser.add_argument('--hardlink-dupes', action='store_true',
|
||||
dest='hardlink_dupes',
|
||||
help='Hardlink duplicated pyc files')
|
||||
|
||||
if PY37:
|
||||
invalidation_modes = [mode.name.lower().replace('_', '-')
|
||||
for mode in py_compile.PycInvalidationMode]
|
||||
parser.add_argument('--invalidation-mode',
|
||||
choices=sorted(invalidation_modes),
|
||||
help=('set .pyc invalidation mode; defaults to '
|
||||
'"checked-hash" if the SOURCE_DATE_EPOCH '
|
||||
'environment variable is set, and '
|
||||
'"timestamp" otherwise.'))
|
||||
|
||||
args = parser.parse_args()
|
||||
compile_dests = args.compile_dest
|
||||
|
||||
if args.rx:
|
||||
import re
|
||||
args.rx = re.compile(args.rx)
|
||||
|
||||
if args.limit_sl_dest == "":
|
||||
args.limit_sl_dest = None
|
||||
|
||||
if args.recursion is not None:
|
||||
maxlevels = args.recursion
|
||||
else:
|
||||
maxlevels = args.maxlevels
|
||||
|
||||
if args.opt_levels is None:
|
||||
args.opt_levels = [-1]
|
||||
|
||||
if len(args.opt_levels) == 1 and args.hardlink_dupes:
|
||||
parser.error(("Hardlinking of duplicated bytecode makes sense "
|
||||
"only for more than one optimization level."))
|
||||
|
||||
if args.ddir is not None and (
|
||||
args.stripdir is not None or args.prependdir is not None
|
||||
):
|
||||
parser.error("-d cannot be used in combination with -s or -p")
|
||||
|
||||
# if flist is provided then load it
|
||||
if args.flist:
|
||||
try:
|
||||
with (sys.stdin if args.flist=='-' else open(args.flist)) as f:
|
||||
for line in f:
|
||||
compile_dests.append(line.strip())
|
||||
except OSError:
|
||||
if args.quiet < 2:
|
||||
print("Error reading file list {}".format(args.flist))
|
||||
return False
|
||||
|
||||
if args.workers is not None:
|
||||
args.workers = args.workers or None
|
||||
|
||||
if PY37 and args.invalidation_mode:
|
||||
ivl_mode = args.invalidation_mode.replace('-', '_').upper()
|
||||
invalidation_mode = py_compile.PycInvalidationMode[ivl_mode]
|
||||
else:
|
||||
invalidation_mode = None
|
||||
|
||||
success = True
|
||||
try:
|
||||
if compile_dests:
|
||||
for dest in compile_dests:
|
||||
if os.path.isfile(dest):
|
||||
if not compile_file(dest, args.ddir, args.force, args.rx,
|
||||
args.quiet, args.legacy,
|
||||
invalidation_mode=invalidation_mode,
|
||||
stripdir=args.stripdir,
|
||||
prependdir=args.prependdir,
|
||||
optimize=args.opt_levels,
|
||||
limit_sl_dest=args.limit_sl_dest,
|
||||
hardlink_dupes=args.hardlink_dupes):
|
||||
success = False
|
||||
else:
|
||||
if not compile_dir(dest, maxlevels, args.ddir,
|
||||
args.force, args.rx, args.quiet,
|
||||
args.legacy, workers=args.workers,
|
||||
invalidation_mode=invalidation_mode,
|
||||
stripdir=args.stripdir,
|
||||
prependdir=args.prependdir,
|
||||
optimize=args.opt_levels,
|
||||
limit_sl_dest=args.limit_sl_dest,
|
||||
hardlink_dupes=args.hardlink_dupes):
|
||||
success = False
|
||||
return success
|
||||
else:
|
||||
return compile_path(legacy=args.legacy, force=args.force,
|
||||
quiet=args.quiet,
|
||||
invalidation_mode=invalidation_mode)
|
||||
except KeyboardInterrupt:
|
||||
if args.quiet < 2:
|
||||
print("\n[interrupted]")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit_status = int(not main())
|
||||
sys.exit(exit_status)
|
@ -1,5 +0,0 @@
|
||||
--- !Policy
|
||||
|
||||
decision_context: osci_compose_gate
|
||||
rules:
|
||||
- !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional}
|
@ -1,171 +0,0 @@
|
||||
'''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()
|
@ -1,69 +0,0 @@
|
||||
# Note that the path could itself be a python file, or a directory
|
||||
|
||||
# Note that the py_byte_compile macro should work for all Python versions
|
||||
# Which unfortunately makes the definition more complicated than it should be
|
||||
|
||||
# Usage:
|
||||
# %%py_byte_compile <interpereter> <path>
|
||||
# Example:
|
||||
# %%py_byte_compile %%{__python3} %%{buildroot}%%{_datadir}/spam/plugins/
|
||||
|
||||
# This will terminate build on SyntaxErrors, if you want to avoid that,
|
||||
# use it in a subshell like this:
|
||||
# (%%{py_byte_compile <interpereter> <path>}) || :
|
||||
|
||||
# Setting PYTHONHASHSEED=0 disables 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)
|
||||
|
||||
%py_byte_compile()\
|
||||
clamp_source_mtime () {\
|
||||
python_binary="%{__env_unset_source_date_epoch_if_not_clamp_mtime} %1"\
|
||||
bytecode_compilation_path="%2"\
|
||||
PYTHONPATH="%{_rpmconfigdir}/redhat" $python_binary -s -B -m clamp_source_mtime $bytecode_compilation_path \
|
||||
}\
|
||||
\
|
||||
py2_byte_compile () {\
|
||||
python_binary="%{__env_unset_source_date_epoch_if_not_clamp_mtime} PYTHONHASHSEED=0 %1"\
|
||||
bytecode_compilation_path="%2"\
|
||||
failure=0\
|
||||
find $bytecode_compilation_path -type f -a -name "*.py" -print0 | xargs -0 $python_binary -s -c 'import py_compile, sys; [py_compile.compile(f, dfile=f.partition("'"$RPM_BUILD_ROOT"'")[2], doraise=True) for f in sys.argv[1:]]' || failure=1\
|
||||
find $bytecode_compilation_path -type f -a -name "*.py" -print0 | xargs -0 $python_binary -s -O -c 'import py_compile, sys; [py_compile.compile(f, dfile=f.partition("'"$RPM_BUILD_ROOT"'")[2], doraise=True) for f in sys.argv[1:]]' || failure=1\
|
||||
test $failure -eq 0\
|
||||
}\
|
||||
\
|
||||
py34_byte_compile () {\
|
||||
python_binary="%{__env_unset_source_date_epoch_if_not_clamp_mtime} PYTHONHASHSEED=0 %1"\
|
||||
bytecode_compilation_path="%2"\
|
||||
PYTHONPATH="%{_rpmconfigdir}/redhat" $python_binary -s -B -m compileall2 %{?_smp_build_ncpus:-j%{_smp_build_ncpus}} -o 0 -o 1 -s $RPM_BUILD_ROOT -p / --hardlink-dupes $bytecode_compilation_path \
|
||||
}\
|
||||
py37_byte_compile () {\
|
||||
python_binary="%{__env_unset_source_date_epoch_if_not_clamp_mtime} PYTHONHASHSEED=0 %1"\
|
||||
bytecode_compilation_path="%2"\
|
||||
PYTHONPATH="%{_rpmconfigdir}/redhat" $python_binary -s -B -m compileall2 %{?_smp_build_ncpus:-j%{_smp_build_ncpus}} -o 0 -o 1 -s $RPM_BUILD_ROOT -p / --hardlink-dupes --invalidation-mode=timestamp $bytecode_compilation_path \
|
||||
}\
|
||||
\
|
||||
py39_byte_compile () {\
|
||||
python_binary="%{__env_unset_source_date_epoch_if_not_clamp_mtime} PYTHONHASHSEED=0 %1"\
|
||||
bytecode_compilation_path="%2"\
|
||||
$python_binary -s -B -m compileall %{?_smp_build_ncpus:-j%{_smp_build_ncpus}} -o 0 -o 1 -s $RPM_BUILD_ROOT -p / --hardlink-dupes --invalidation-mode=timestamp $bytecode_compilation_path \
|
||||
}\
|
||||
\
|
||||
# Path to intepreter should not contain any arguments \
|
||||
[[ "%1" =~ " -" ]] && echo "ERROR py_byte_compile: Path to interpreter should not contain any arguments" >&2 && exit 1 \
|
||||
# First, clamp source mtime https://fedoraproject.org/wiki/Changes/ReproducibleBuildsClampMtimes \
|
||||
clamp_source_mtime "%1" "%2"; \
|
||||
# Get version without a dot (36 instead of 3.6), bash doesn't compare floats well \
|
||||
python_version=$(%1 -c "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))") \
|
||||
# compileall2 is an enhanced fork of stdlib compileall module for Python >= 3.4 \
|
||||
# and it was merged back to stdlib in Python >= 3.9 \
|
||||
# Only Python 3.7+ supports and needs the --invalidation-mode option \
|
||||
if [ "$python_version" -ge 39 ]; then \
|
||||
py39_byte_compile "%1" "%2"; \
|
||||
elif [ "$python_version" -ge 37 ]; then \
|
||||
py37_byte_compile "%1" "%2"; \
|
||||
elif [ "$python_version" -ge 34 ]; then \
|
||||
py34_byte_compile "%1" "%2"; \
|
||||
else \
|
||||
py2_byte_compile "%1" "%2"; \
|
||||
fi
|
176
macros.python
176
macros.python
@ -1,176 +0,0 @@
|
||||
# Memoize a macro to avoid calling the same expensive code multiple times in
|
||||
# the specfile.
|
||||
# There is no error handling,
|
||||
# memoizing an undefined macro (or using such a key) has undefined behavior.
|
||||
# Options:
|
||||
# -n - The name of the macro to wrap
|
||||
# -k - The name of the macro to use as a cache key
|
||||
%_python_memoize(n:k:) %{lua:
|
||||
local name = opt.n
|
||||
-- NB: We use rpm.expand() here instead of the macros table to make sure errors
|
||||
-- are propogated properly.
|
||||
local cache_key = rpm.expand("%{" .. opt.k .. "}")
|
||||
if not _python_macro_cache then
|
||||
-- This is intentionally a global lua table
|
||||
_python_macro_cache = {}
|
||||
end
|
||||
if not _python_macro_cache[cache_key] then
|
||||
_python_macro_cache[cache_key] = {}
|
||||
end
|
||||
if not _python_macro_cache[cache_key][name] then
|
||||
_python_macro_cache[cache_key][name] = rpm.expand("%{" .. name .. "}")
|
||||
end
|
||||
print(_python_macro_cache[cache_key][name])
|
||||
}
|
||||
|
||||
# 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
|
||||
# nb: $RPM_BUILD_ROOT is not set when the macros are expanded (at spec parse time)
|
||||
# so we set it manually (to empty string), making our Python prefer the correct install scheme location
|
||||
# platbase/base is explicitly set to %%{_prefix} to support custom values, such as /app for flatpaks
|
||||
%__python_sitelib %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_path('purelib', vars={'platbase': '%{_prefix}', 'base': '%{_prefix}'}))")
|
||||
%python_sitelib %{_python_memoize -n __python_sitelib -k __python}
|
||||
|
||||
%__python_sitearch %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_path('platlib', vars={'platbase': '%{_prefix}', 'base': '%{_prefix}'}))")
|
||||
%python_sitearch %{_python_memoize -n __python_sitearch -k __python}
|
||||
|
||||
%__python_version %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
|
||||
%python_version %{_python_memoize -n __python_version -k __python}
|
||||
|
||||
%__python_version_nodots %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
|
||||
%python_version_nodots %{_python_memoize -n __python_version_nodots -k __python}
|
||||
|
||||
%__python_platform %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_platform())")
|
||||
%python_platform %{_python_memoize -n __python_platform -k __python}
|
||||
|
||||
%__python_platform_triplet %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_config_var('MULTIARCH'))")
|
||||
%python_platform_triplet %{_python_memoize -n __python_platform_triplet -k __python}
|
||||
|
||||
%__python_ext_suffix %(RPM_BUILD_ROOT= %{__python} -Esc "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
|
||||
%python_ext_suffix %{_python_memoize -n __python_ext_suffix -k __python}
|
||||
|
||||
%__python_cache_tag %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; print(sys.implementation.cache_tag)")
|
||||
%python_cache_tag %{_python_memoize -n __python_cache_tag -k __python}
|
||||
|
||||
%py_setup setup.py
|
||||
%_py_shebang_s s
|
||||
%__py_shebang_P %(RPM_BUILD_ROOT= %{__python} -Esc "import sys; print('P' if hasattr(sys.flags, 'safe_path') else '')")
|
||||
%_py_shebang_P %{_python_memoize -n __py_shebang_P -k __python}
|
||||
%py_shbang_opts -%{?_py_shebang_s}%{?_py_shebang_P}
|
||||
%py_shbang_opts_nodash %(opts=%{py_shbang_opts}; echo ${opts#-})
|
||||
%py_shebang_flags %(opts=%{py_shbang_opts}; echo ${opts#-})
|
||||
%py_shebang_fix %{expand:\\\
|
||||
if [ -z "%{?py_shebang_flags}" ]; then
|
||||
shebang_flags="-k"
|
||||
else
|
||||
shebang_flags="-ka%{py_shebang_flags}"
|
||||
fi
|
||||
%{__python} -B %{_rpmconfigdir}/redhat/pathfix.py -pni %{__python} $shebang_flags}
|
||||
|
||||
# Use the slashes after expand so that the command starts on the same line as
|
||||
# the macro
|
||||
%py_build() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python} %{py_setup} %{?py_setup_args} build --executable="%{__python} %{py_shbang_opts}" %{?*}
|
||||
}
|
||||
|
||||
%py_build_wheel() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python} %{py_setup} %{?py_setup_args} bdist_wheel %{?*}
|
||||
}
|
||||
|
||||
%py_install() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} --prefix %{_prefix} %{?*}
|
||||
rm -rfv %{buildroot}%{_bindir}/__pycache__
|
||||
}
|
||||
|
||||
%py_install_wheel() %{expand:\\\
|
||||
%{__python} -m pip install -I dist/%{1} --root %{buildroot} --prefix %{_prefix} --no-deps --no-index --no-warn-script-location
|
||||
rm -rfv %{buildroot}%{_bindir}/__pycache__
|
||||
for distinfo in %{buildroot}%{python_sitelib}/*.dist-info %{buildroot}%{python_sitearch}/*.dist-info; do
|
||||
if [ -f ${distinfo}/direct_url.json ]; then
|
||||
rm -fv ${distinfo}/direct_url.json
|
||||
sed -i '/direct_url.json/d' ${distinfo}/RECORD
|
||||
fi
|
||||
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:
|
||||
local python = require "fedora.srpm.python"
|
||||
function string.starts(String,Start)
|
||||
return string.sub(String,1,string.len(Start))==Start
|
||||
end
|
||||
local package = rpm.expand("%{?1}")
|
||||
local vr = rpm.expand("%{?epoch:%{epoch}:}%{version}-%{release}")
|
||||
local provides = python.python_altprovides(package, vr)
|
||||
local default_python3_pkgversion = rpm.expand("%{__default_python3_pkgversion}")
|
||||
if (string.starts(package, "python3-")) then
|
||||
for i, provide in ipairs(provides) do
|
||||
print("\\nProvides: " .. provide)
|
||||
end
|
||||
--Obsoleting the previous default python package (if it doesn't have isa)
|
||||
if (string.sub(package, "-1") ~= ")") then
|
||||
print("\\nObsoletes: python-")
|
||||
print(string.sub(package,9,string.len(package)))
|
||||
print(" < " .. vr)
|
||||
end
|
||||
elseif (string.starts(package, "python" .. default_python3_pkgversion .. "-")) then
|
||||
for i, provide in ipairs(provides) do
|
||||
print("\\nProvides: " .. provide)
|
||||
end
|
||||
--Obsoleting the previous default python package (if it doesn't have isa)
|
||||
if (string.sub(package, "-1") ~= ")") then
|
||||
print("\\nObsoletes: python-")
|
||||
print(string.sub(package,8+string.len(default_python3_pkgversion),string.len(package)))
|
||||
print(" < " .. vr)
|
||||
end
|
||||
elseif (string.starts(package, "python")) then
|
||||
--No unversioned provides as other python3 cases are not the default
|
||||
elseif (string.starts(package, "pypy")) then
|
||||
--No unversioned provides as pypy is not default either
|
||||
else
|
||||
print("%python_provide: ERROR: ")
|
||||
print(package)
|
||||
print(" not recognized.")
|
||||
end
|
||||
}
|
||||
|
||||
# Environment variables for testing used standalone, e.g.:
|
||||
# %%{py_test_envvars} %%{python} -m unittest
|
||||
%py_test_envvars %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
PATH="%{buildroot}%{_bindir}:$PATH"\\\
|
||||
PYTHONPATH="${PYTHONPATH:-%{buildroot}%{python_sitearch}:%{buildroot}%{python_sitelib}}"\\\
|
||||
PYTHONDONTWRITEBYTECODE=1\\\
|
||||
%{?__pytest_addopts:PYTEST_ADDOPTS="${PYTEST_ADDOPTS:-} %{__pytest_addopts}"}\\\
|
||||
PYTEST_XDIST_AUTO_NUM_WORKERS="${PYTEST_XDIST_AUTO_NUM_WORKERS:-%{_smp_build_ncpus}}"}
|
||||
|
||||
%python_disable_dependency_generator() \
|
||||
%undefine __pythondist_requires \
|
||||
%{nil}
|
@ -1,295 +0,0 @@
|
||||
# There are multiple Python 3 versions packaged, but only one can be the "main" version
|
||||
# That means that it owns the "python3" namespace:
|
||||
# - python3 package name
|
||||
# - /usr/bin/python3 command
|
||||
# - python3-foo packages are meant for this version
|
||||
# Other versions of Python 3 always contain the version in the namespace:
|
||||
# - python3.XX package name
|
||||
# - /usr/bin/python3.XX command
|
||||
# - python3.XX-foo packages (if allowed)
|
||||
#
|
||||
# Python spec files use the version defined here to determine defaults for the
|
||||
# %%py_provides and %%python_provide macros, as well as for the "pythonname" generator that
|
||||
# provides python3-foo for python3.XX-foo and vice versa for the default "main" version.
|
||||
# E.g. in Fedora 33, python3.9-foo will provide python3-foo,
|
||||
# python3-foo will provide python3.9-foo.
|
||||
#
|
||||
# There are two macros:
|
||||
#
|
||||
# This always contains the major.minor version (with dots), default for %%python3_version.
|
||||
%__default_python3_version 3.12
|
||||
#
|
||||
# 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.
|
||||
# This is left intentionally a separate macro, in case the naming convention ever changes.
|
||||
%__default_python3_pkgversion %__default_python3_version
|
||||
|
||||
# python3_pkgversion specifies the version of Python 3 in the distro.
|
||||
# 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
|
||||
|
||||
# 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/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
|
||||
## Helper macro to unset $SOURCE_DATE_EPOCH if %%clamp_mtime_to_source_date_epoch is not set
|
||||
## https://fedoraproject.org/wiki/Changes/ReproducibleBuildsClampMtimes#Python_bytecode
|
||||
%__env_unset_source_date_epoch_if_not_clamp_mtime %[0%{?clamp_mtime_to_source_date_epoch} == 0 ? "env -u SOURCE_DATE_EPOCH" : "env"]
|
||||
|
||||
## The individual BRP scripts
|
||||
%__brp_python_bytecompile %{__env_unset_source_date_epoch_if_not_clamp_mtime} %{_rpmconfigdir}/redhat/brp-python-bytecompile "" "%{?_python_bytecompile_errors_terminate_build}" "%{?_python_bytecompile_extra}" "%{?_smp_build_ncpus:-j%{_smp_build_ncpus}}"
|
||||
%__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 ===
|
||||
# - https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages
|
||||
# - These macros need to be in macros.python-srpm, because BuildRequires tags
|
||||
# get rendered as runtime requires into the metadata of SRPMs.
|
||||
|
||||
# Converts Python dist name to a canonical format
|
||||
%py_dist_name() %{lua:\
|
||||
name = rpm.expand("%{?1:%{1}}");\
|
||||
canonical = string.gsub(string.lower(name), "[^%w%[%]]+", "-");\
|
||||
print(canonical);\
|
||||
}
|
||||
|
||||
# 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
|
||||
# macro (%%py_dist_name) overwrites them
|
||||
%py2_dist() %{lua:\
|
||||
args = {}\
|
||||
arg = 1\
|
||||
while (true) do\
|
||||
name = rpm.expand("%{?" .. arg .. ":%{" .. arg .. "}}");\
|
||||
if (name == nil or name == '') then\
|
||||
break\
|
||||
end\
|
||||
args[arg] = name\
|
||||
arg = arg + 1\
|
||||
end\
|
||||
for arg, name in ipairs(args) do\
|
||||
canonical = rpm.expand("%py_dist_name " .. name);\
|
||||
print("python2dist(" .. canonical .. ") ");\
|
||||
end\
|
||||
}
|
||||
|
||||
# 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
|
||||
# macro (%%py_dist_name) overwrites them
|
||||
%py3_dist() %{lua:\
|
||||
python3_pkgversion = rpm.expand("%python3_pkgversion");\
|
||||
args = {}\
|
||||
arg = 1\
|
||||
while (true) do\
|
||||
name = rpm.expand("%{?" .. arg .. ":%{" .. arg .. "}}");\
|
||||
if (name == nil or name == '') then\
|
||||
break\
|
||||
end\
|
||||
args[arg] = name\
|
||||
arg = arg + 1\
|
||||
end\
|
||||
for arg, name in ipairs(args) do\
|
||||
canonical = rpm.expand("%py_dist_name " .. name);\
|
||||
print("python" .. python3_pkgversion .. "dist(" .. canonical .. ") ");\
|
||||
end\
|
||||
}
|
||||
|
||||
# Macro to replace overly complicated references to PyPI source files.
|
||||
# Expands to the pythonhosted URL for a package
|
||||
# Accepts zero to three arguments:
|
||||
# 1: The PyPI project name, defaulting to %%srcname if it is defined, then
|
||||
# %%pypi_name if it is defined, then just %%name.
|
||||
# 2: The PYPI version, defaulting to %%version with tildes stripped.
|
||||
# 3: The file extension, defaulting to "tar.gz". (A period will be added
|
||||
# automatically.)
|
||||
# Requires %%__pypi_url and %%__pypi_default_extension to be defined.
|
||||
%__pypi_url https://files.pythonhosted.org/packages/source/
|
||||
%__pypi_default_extension tar.gz
|
||||
|
||||
%pypi_source() %{lua:
|
||||
local src = rpm.expand('%1')
|
||||
local ver = rpm.expand('%2')
|
||||
local ext = rpm.expand('%3')
|
||||
local url = rpm.expand('%__pypi_url')
|
||||
\
|
||||
-- If no first argument, try %srcname, then %pypi_name, then %name
|
||||
-- Note that rpm leaves macros unchanged if they are not defined.
|
||||
if src == '%1' then
|
||||
src = rpm.expand('%srcname')
|
||||
end
|
||||
if src == '%srcname' then
|
||||
src = rpm.expand('%pypi_name')
|
||||
end
|
||||
if src == '%pypi_name' then
|
||||
src = rpm.expand('%name')
|
||||
end
|
||||
\
|
||||
-- If no second argument, use %version
|
||||
if ver == '%2' then
|
||||
ver = rpm.expand('%version'):gsub('~', '')
|
||||
end
|
||||
\
|
||||
-- If no third argument, use the preset default extension
|
||||
if ext == '%3' then
|
||||
ext = rpm.expand('%__pypi_default_extension')
|
||||
end
|
||||
\
|
||||
local first = string.sub(src, 1, 1)
|
||||
\
|
||||
print(url .. first .. '/' .. src .. '/' .. src .. '-' .. ver .. '.' .. ext)
|
||||
}
|
||||
|
||||
%py_provides() %{lua:
|
||||
local python = require 'fedora.srpm.python'
|
||||
local rhel = rpm.expand('%{?rhel}')
|
||||
local name = rpm.expand('%1')
|
||||
if name == '%1' then
|
||||
rpm.expand('%{error:%%py_provides requires at least 1 argument, the name to provide}')
|
||||
end
|
||||
local evr = rpm.expand('%2')
|
||||
if evr == '%2' then
|
||||
evr = rpm.expand('%{?epoch:%{epoch}:}%{version}-%{release}')
|
||||
end
|
||||
print('Provides: ' .. name .. ' = ' .. evr .. '\\n')
|
||||
local provides = python.python_altprovides(name, evr)
|
||||
for i, provide in ipairs(provides) do
|
||||
print('Provides: ' .. provide .. '\\n')
|
||||
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:FaA) %{expand:%{lua:
|
||||
local option_n = '-n (name of the base package)'
|
||||
local option_i = '-i (buildroot path to metadata)'
|
||||
local option_f = '-f (builddir path to a filelist)'
|
||||
local option_F = '-F (skip %%files section)'
|
||||
local option_a = '-a (insert BuildArch: noarch)'
|
||||
local option_A = '-A (do not insert BuildArch: noarch (default))'
|
||||
local value_n = rpm.expand('%{-n*}')
|
||||
local value_i = rpm.expand('%{-i*}')
|
||||
local value_f = rpm.expand('%{-f*}')
|
||||
local value_F = rpm.expand('%{-F}')
|
||||
local value_a = rpm.expand('%{-a}')
|
||||
local value_A = rpm.expand('%{-A}')
|
||||
local args = rpm.expand('%{*}')
|
||||
if value_n == '' then
|
||||
rpm.expand('%{error:%%%0: missing option ' .. option_n .. '}')
|
||||
end
|
||||
if value_i == '' and value_f == '' and value_F == '' then
|
||||
rpm.expand('%{error:%%%0: missing option ' .. option_i .. ' or ' .. option_f .. ' or ' .. option_F .. '}')
|
||||
end
|
||||
if value_i ~= '' and value_f ~= '' then
|
||||
rpm.expand('%{error:%%%0: simultaneous ' .. option_i .. ' and ' .. option_f .. ' options are not possible}')
|
||||
end
|
||||
if value_i ~= '' and value_F ~= '' then
|
||||
rpm.expand('%{error:%%%0: simultaneous ' .. option_i .. ' and ' .. option_F .. ' options are not possible}')
|
||||
end
|
||||
if value_f ~= '' and value_F ~= '' then
|
||||
rpm.expand('%{error:%%%0: simultaneous ' .. option_f .. ' and ' .. option_F .. ' options are not possible}')
|
||||
end
|
||||
if value_a ~= '' and value_A ~= '' then
|
||||
rpm.expand('%{error:%%%0: simultaneous ' .. option_a .. ' and ' .. option_A .. ' options are not possible}')
|
||||
end
|
||||
if args == '' then
|
||||
rpm.expand('%{error:%%%0 requires at least one argument with "extras" name}')
|
||||
end
|
||||
local requires = 'Requires: ' .. value_n .. ' = %{?epoch:%{epoch}:}%{version}-%{release}'
|
||||
for extras in args:gmatch('[^%s,]+') do
|
||||
local rpmname = value_n .. '+' .. extras
|
||||
local pkgdef = '%package -n ' .. rpmname
|
||||
local summary = 'Summary: Metapackage for ' .. value_n .. ': ' .. extras .. ' extras'
|
||||
local description = '%description -n ' .. rpmname .. '\\\n'
|
||||
local current_line = 'This is a metapackage bringing in'
|
||||
for _, word in ipairs({extras, 'extras', 'requires', 'for', value_n .. '.'}) do
|
||||
local line = current_line .. ' ' .. word
|
||||
if line:len() > 79 then
|
||||
description = description .. current_line .. '\\\n'
|
||||
current_line = word
|
||||
else
|
||||
current_line = line
|
||||
end
|
||||
end
|
||||
description = description .. current_line .. '\\\n' ..
|
||||
'It makes sure the dependencies are installed.\\\n'
|
||||
local files = ''
|
||||
if value_i ~= '' then
|
||||
files = '%files -n ' .. rpmname .. '\\\n' .. '%ghost ' .. value_i
|
||||
elseif value_f ~= '' then
|
||||
files = '%files -n ' .. rpmname .. ' -f ' .. value_f
|
||||
end
|
||||
local tags = summary .. '\\\n' .. requires
|
||||
if value_a ~= '' then
|
||||
tags = tags .. '\\\nBuildArch: noarch'
|
||||
end
|
||||
for i, line in ipairs({pkgdef, tags, description, files, ''}) do
|
||||
print(line .. '\\\n')
|
||||
end
|
||||
end
|
||||
}}
|
126
macros.python3
126
macros.python3
@ -1,126 +0,0 @@
|
||||
# nb: $RPM_BUILD_ROOT is not set when the macros are expanded (at spec parse time)
|
||||
# so we set it manually (to empty string), making our Python prefer the correct install scheme location
|
||||
# platbase/base is explicitly set to %%{_prefix} to support custom values, such as /app for flatpaks
|
||||
%__python3_sitelib %(RPM_BUILD_ROOT= %{__python3} -Esc "import sysconfig; print(sysconfig.get_path('purelib', vars={'platbase': '%{_prefix}', 'base': '%{_prefix}'}))")
|
||||
%python3_sitelib %{_python_memoize -n __python3_sitelib -k __python3}
|
||||
|
||||
%__python3_sitearch %(RPM_BUILD_ROOT= %{__python3} -Esc "import sysconfig; print(sysconfig.get_path('platlib', vars={'platbase': '%{_prefix}', 'base': '%{_prefix}'}))")
|
||||
%python3_sitearch %{_python_memoize -n __python3_sitearch -k __python3}
|
||||
|
||||
%__python3_version %(RPM_BUILD_ROOT= %{__python3} -Esc "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
|
||||
%python3_version %{_python_memoize -n __python3_version -k __python3}
|
||||
|
||||
%__python3_version_nodots %(RPM_BUILD_ROOT= %{__python3} -Esc "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")
|
||||
%python3_version_nodots %{_python_memoize -n __python3_version_nodots -k __python3}
|
||||
|
||||
%__python3_platform %(RPM_BUILD_ROOT= %{__python3} -Esc "import sysconfig; print(sysconfig.get_platform())")
|
||||
%python3_platform %{_python_memoize -n __python3_platform -k __python3}
|
||||
|
||||
%__python3_platform_triplet %(RPM_BUILD_ROOT= %{__python3} -Esc "import sysconfig; print(sysconfig.get_config_var('MULTIARCH'))")
|
||||
%python3_platform_triplet %{_python_memoize -n __python3_platform_triplet -k __python3}
|
||||
|
||||
%__python3_ext_suffix %(RPM_BUILD_ROOT= %{__python3} -Esc "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
|
||||
%python3_ext_suffix %{_python_memoize -n __python3_ext_suffix -k __python3}
|
||||
|
||||
%__python3_cache_tag %(RPM_BUILD_ROOT= %{__python3} -Esc "import sys; print(sys.implementation.cache_tag)")
|
||||
%python3_cache_tag %{_python_memoize -n __python3_cache_tag -k __python3}
|
||||
|
||||
%py3dir %{_builddir}/python3-%{name}-%{version}-%{release}
|
||||
|
||||
%_py3_shebang_s s
|
||||
%__py3_shebang_P %(RPM_BUILD_ROOT= %{__python3} -Ic "import sys; print('P' if hasattr(sys.flags, 'safe_path') else '')")
|
||||
%_py3_shebang_P %{_python_memoize -n __py3_shebang_P -k __python3}
|
||||
%py3_shbang_opts -%{?_py3_shebang_s}%{?_py3_shebang_P}
|
||||
%py3_shbang_opts_nodash %(opts=%{py3_shbang_opts}; echo ${opts#-})
|
||||
%py3_shebang_flags %(opts=%{py3_shbang_opts}; echo ${opts#-})
|
||||
%py3_shebang_fix %{expand:\\\
|
||||
if [ -z "%{?py3_shebang_flags}" ]; then
|
||||
shebang_flags="-k"
|
||||
else
|
||||
shebang_flags="-ka%{py3_shebang_flags}"
|
||||
fi
|
||||
%{__python3} -B %{_rpmconfigdir}/redhat/pathfix.py -pni %{__python3} $shebang_flags}
|
||||
|
||||
# Use the slashes after expand so that the command starts on the same line as
|
||||
# the macro
|
||||
%py3_build() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python3} %{py_setup} %{?py_setup_args} build --executable="%{__python3} %{py3_shbang_opts}" %{?*}
|
||||
}
|
||||
|
||||
%py3_build_wheel() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python3} %{py_setup} %{?py_setup_args} bdist_wheel %{?*}
|
||||
}
|
||||
|
||||
%py3_install() %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
%{__python3} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} --prefix %{_prefix} %{?*}
|
||||
rm -rfv %{buildroot}%{_bindir}/__pycache__
|
||||
}
|
||||
|
||||
%py3_install_wheel() %{expand:\\\
|
||||
%{__python3} -m pip install -I dist/%{1} --root %{buildroot} --prefix %{_prefix} --no-deps --no-index --no-warn-script-location
|
||||
rm -rfv %{buildroot}%{_bindir}/__pycache__
|
||||
for distinfo in %{buildroot}%{python3_sitelib}/*.dist-info %{buildroot}%{python3_sitearch}/*.dist-info; do
|
||||
if [ -f ${distinfo}/direct_url.json ]; then
|
||||
rm -fv ${distinfo}/direct_url.json
|
||||
sed -i '/direct_url.json/d' ${distinfo}/RECORD
|
||||
fi
|
||||
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.
|
||||
# Hence, it has no Python version in the name.
|
||||
%pycached() %{lua:
|
||||
path = rpm.expand("%{?*}")
|
||||
if (string.sub(path, "-3") ~= ".py") then
|
||||
rpm.expand("%{error:%%pycached can only be used with paths explicitly ending with .py}")
|
||||
else
|
||||
print(path)
|
||||
pyminor = path:match("/python3.(%d+)/") or "*"
|
||||
dirname = path:match("(.*/)")
|
||||
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")
|
||||
end
|
||||
}
|
||||
|
||||
# Environment variables used by %%pytest, %%tox or standalone, e.g.:
|
||||
# %%{py3_test_envvars} %%{python3} -m unittest
|
||||
%py3_test_envvars %{expand:\\\
|
||||
CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"\\\
|
||||
PATH="%{buildroot}%{_bindir}:$PATH"\\\
|
||||
PYTHONPATH="${PYTHONPATH:-%{buildroot}%{python3_sitearch}:%{buildroot}%{python3_sitelib}}"\\\
|
||||
PYTHONDONTWRITEBYTECODE=1\\\
|
||||
%{?__pytest_addopts:PYTEST_ADDOPTS="${PYTEST_ADDOPTS:-} %{__pytest_addopts}"}\\\
|
||||
PYTEST_XDIST_AUTO_NUM_WORKERS="${PYTEST_XDIST_AUTO_NUM_WORKERS:-%{_smp_build_ncpus}}"}
|
||||
|
||||
# This is intended for Python 3 only, hence also no Python version in the name.
|
||||
%__pytest /usr/bin/pytest%(test %{python3_pkgversion} == 3 || echo -%{python3_version})
|
||||
%pytest %py3_test_envvars %__pytest
|
199
pathfix.py
199
pathfix.py
@ -1,199 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
from stat import *
|
||||
import getopt
|
||||
|
||||
err = sys.stderr.write
|
||||
dbg = err
|
||||
rep = sys.stdout.write
|
||||
|
||||
new_interpreter = None
|
||||
preserve_timestamps = False
|
||||
create_backup = True
|
||||
keep_flags = False
|
||||
add_flags = b''
|
||||
|
||||
|
||||
def main():
|
||||
global new_interpreter
|
||||
global preserve_timestamps
|
||||
global create_backup
|
||||
global keep_flags
|
||||
global add_flags
|
||||
|
||||
usage = ('usage: %s -i /interpreter -p -n -k -a file-or-directory ...\n' %
|
||||
sys.argv[0])
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'i:a:kpn')
|
||||
except getopt.error as msg:
|
||||
err(str(msg) + '\n')
|
||||
err(usage)
|
||||
sys.exit(2)
|
||||
for o, a in opts:
|
||||
if o == '-i':
|
||||
new_interpreter = a.encode()
|
||||
if o == '-p':
|
||||
preserve_timestamps = True
|
||||
if o == '-n':
|
||||
create_backup = False
|
||||
if o == '-k':
|
||||
keep_flags = True
|
||||
if o == '-a':
|
||||
add_flags = a.encode()
|
||||
if b' ' in add_flags:
|
||||
err("-a option doesn't support whitespaces")
|
||||
sys.exit(2)
|
||||
if not new_interpreter or not new_interpreter.startswith(b'/') or \
|
||||
not args:
|
||||
err('-i option or file-or-directory missing\n')
|
||||
err(usage)
|
||||
sys.exit(2)
|
||||
bad = 0
|
||||
for arg in args:
|
||||
if os.path.isdir(arg):
|
||||
if recursedown(arg): bad = 1
|
||||
elif os.path.islink(arg):
|
||||
err(arg + ': will not process symbolic links\n')
|
||||
bad = 1
|
||||
else:
|
||||
if fix(arg): bad = 1
|
||||
sys.exit(bad)
|
||||
|
||||
|
||||
def ispython(name):
|
||||
return name.endswith('.py')
|
||||
|
||||
|
||||
def recursedown(dirname):
|
||||
dbg('recursedown(%r)\n' % (dirname,))
|
||||
bad = 0
|
||||
try:
|
||||
names = os.listdir(dirname)
|
||||
except OSError as msg:
|
||||
err('%s: cannot list directory: %r\n' % (dirname, msg))
|
||||
return 1
|
||||
names.sort()
|
||||
subdirs = []
|
||||
for name in names:
|
||||
if name in (os.curdir, os.pardir): continue
|
||||
fullname = os.path.join(dirname, name)
|
||||
if os.path.islink(fullname): pass
|
||||
elif os.path.isdir(fullname):
|
||||
subdirs.append(fullname)
|
||||
elif ispython(name):
|
||||
if fix(fullname): bad = 1
|
||||
for fullname in subdirs:
|
||||
if recursedown(fullname): bad = 1
|
||||
return bad
|
||||
|
||||
|
||||
def fix(filename):
|
||||
## dbg('fix(%r)\n' % (filename,))
|
||||
try:
|
||||
f = open(filename, 'rb')
|
||||
except IOError as msg:
|
||||
err('%s: cannot open: %r\n' % (filename, msg))
|
||||
return 1
|
||||
with f:
|
||||
line = f.readline()
|
||||
fixed = fixline(line)
|
||||
if line == fixed:
|
||||
rep(filename+': no change\n')
|
||||
return
|
||||
head, tail = os.path.split(filename)
|
||||
tempname = os.path.join(head, '@' + tail)
|
||||
try:
|
||||
g = open(tempname, 'wb')
|
||||
except IOError as msg:
|
||||
err('%s: cannot create: %r\n' % (tempname, msg))
|
||||
return 1
|
||||
with g:
|
||||
rep(filename + ': updating\n')
|
||||
g.write(fixed)
|
||||
BUFSIZE = 8*1024
|
||||
while 1:
|
||||
buf = f.read(BUFSIZE)
|
||||
if not buf: break
|
||||
g.write(buf)
|
||||
|
||||
# Finishing touch -- move files
|
||||
|
||||
mtime = None
|
||||
atime = None
|
||||
# First copy the file's mode to the temp file
|
||||
try:
|
||||
statbuf = os.stat(filename)
|
||||
mtime = statbuf.st_mtime
|
||||
atime = statbuf.st_atime
|
||||
os.chmod(tempname, statbuf[ST_MODE] & 0o7777)
|
||||
except OSError as msg:
|
||||
err('%s: warning: chmod failed (%r)\n' % (tempname, msg))
|
||||
# Then make a backup of the original file as filename~
|
||||
if create_backup:
|
||||
try:
|
||||
os.rename(filename, filename + '~')
|
||||
except OSError as msg:
|
||||
err('%s: warning: backup failed (%r)\n' % (filename, msg))
|
||||
else:
|
||||
try:
|
||||
os.remove(filename)
|
||||
except OSError as msg:
|
||||
err('%s: warning: removing failed (%r)\n' % (filename, msg))
|
||||
# Now move the temp file to the original file
|
||||
try:
|
||||
os.rename(tempname, filename)
|
||||
except OSError as msg:
|
||||
err('%s: rename failed (%r)\n' % (filename, msg))
|
||||
return 1
|
||||
if preserve_timestamps:
|
||||
if atime and mtime:
|
||||
try:
|
||||
os.utime(filename, (atime, mtime))
|
||||
except OSError as msg:
|
||||
err('%s: reset of timestamp failed (%r)\n' % (filename, msg))
|
||||
return 1
|
||||
# Return success
|
||||
return 0
|
||||
|
||||
|
||||
def parse_shebang(shebangline):
|
||||
shebangline = shebangline.rstrip(b'\n')
|
||||
start = shebangline.find(b' -')
|
||||
if start == -1:
|
||||
return b''
|
||||
return shebangline[start:]
|
||||
|
||||
|
||||
def populate_flags(shebangline):
|
||||
old_flags = b''
|
||||
if keep_flags:
|
||||
old_flags = parse_shebang(shebangline)
|
||||
if old_flags:
|
||||
old_flags = old_flags[2:]
|
||||
if not (old_flags or add_flags):
|
||||
return b''
|
||||
# On Linux, the entire string following the interpreter name
|
||||
# is passed as a single argument to the interpreter.
|
||||
# e.g. "#! /usr/bin/python3 -W Error -s" runs "/usr/bin/python3 "-W Error -s"
|
||||
# so shebang should have single '-' where flags are given and
|
||||
# flag might need argument for that reasons adding new flags is
|
||||
# between '-' and original flags
|
||||
# e.g. #! /usr/bin/python3 -sW Error
|
||||
return b' -' + add_flags + old_flags
|
||||
|
||||
|
||||
def fixline(line):
|
||||
if not line.startswith(b'#!'):
|
||||
return line
|
||||
|
||||
if b"python" not in line:
|
||||
return line
|
||||
|
||||
flags = populate_flags(line)
|
||||
return b'#! ' + new_interpreter + flags + b'\n'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -1,589 +0,0 @@
|
||||
Name: python-rpm-macros
|
||||
Summary: The common Python RPM macros
|
||||
|
||||
URL: https://src.fedoraproject.org/rpms/python-rpm-macros/
|
||||
|
||||
# Macros:
|
||||
Source101: macros.python
|
||||
Source102: macros.python-srpm
|
||||
Source104: macros.python3
|
||||
Source105: macros.pybytecompile
|
||||
|
||||
# Lua files
|
||||
Source201: python.lua
|
||||
|
||||
# Python code
|
||||
%global compileall2_version 0.7.1
|
||||
Source301: https://github.com/fedora-python/compileall2/raw/v%{compileall2_version}/compileall2.py
|
||||
Source302: import_all_modules.py
|
||||
%global pathfix_version 1.0.0
|
||||
Source303: https://github.com/fedora-python/pathfix/raw/v%{pathfix_version}/pathfix.py
|
||||
Source304: clamp_source_mtime.py
|
||||
|
||||
# BRP scripts
|
||||
# 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, clamp_source_mtime.py: PSF-2.0
|
||||
# pathfix.py: PSF-2.0
|
||||
# brp scripts: GPL-2.0-or-later
|
||||
License: MIT AND PSF-2.0 AND GPL-2.0-or-later
|
||||
|
||||
# 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.
|
||||
# The macro is defined in python-srpm-macros.
|
||||
%{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}
|
||||
Release: 9.1%{?dist}
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
# For %%__default_python3_pkgversion used in %%python_provide
|
||||
# For python.lua
|
||||
# For compileall2.py
|
||||
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
|
||||
This package contains the unversioned Python RPM macros, that most
|
||||
implementations should rely on.
|
||||
|
||||
You should not need to install this package manually as the various
|
||||
python?-devel packages require it. So install a python-devel package instead.
|
||||
|
||||
|
||||
%package -n python-srpm-macros
|
||||
Summary: RPM macros for building Python source packages
|
||||
|
||||
# For directory structure and flags macros
|
||||
# Versions before 190 contained some brp scripts moved into python-srpm-macros
|
||||
Requires: redhat-rpm-config >= 190
|
||||
|
||||
# We bundle our own software here :/
|
||||
Provides: bundled(python3dist(compileall2)) = %{compileall2_version}
|
||||
|
||||
%description -n python-srpm-macros
|
||||
RPM macros for building Python source packages.
|
||||
|
||||
|
||||
%package -n python3-rpm-macros
|
||||
Summary: RPM macros for building Python 3 packages
|
||||
|
||||
# For %%__python3 and %%python3
|
||||
Requires: python-srpm-macros = %{version}-%{release}
|
||||
|
||||
# For %%py_setup and import_all_modules.py
|
||||
Requires: python-rpm-macros = %{version}-%{release}
|
||||
|
||||
%description -n python3-rpm-macros
|
||||
RPM macros for building Python 3 packages.
|
||||
|
||||
|
||||
%prep
|
||||
%autosetup -c -T
|
||||
cp -a %{sources} .
|
||||
|
||||
# We want to have shebang in the script upstream but not here so
|
||||
# the package with macros does not depend on Python.
|
||||
sed -i '1s=^#!/usr/bin/env python3==' pathfix.py
|
||||
|
||||
|
||||
%install
|
||||
mkdir -p %{buildroot}%{rpmmacrodir}
|
||||
install -m 644 macros.* %{buildroot}%{rpmmacrodir}/
|
||||
|
||||
mkdir -p %{buildroot}%{_rpmluadir}/fedora/srpm
|
||||
install -p -m 644 -t %{buildroot}%{_rpmluadir}/fedora/srpm python.lua
|
||||
|
||||
mkdir -p %{buildroot}%{_rpmconfigdir}/redhat
|
||||
install -m 644 compileall2.py %{buildroot}%{_rpmconfigdir}/redhat/
|
||||
install -m 644 clamp_source_mtime.py %{buildroot}%{_rpmconfigdir}/redhat/
|
||||
install -m 644 import_all_modules.py %{buildroot}%{_rpmconfigdir}/redhat/
|
||||
install -m 644 pathfix.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
|
||||
%define add_buildroot() %{lua:print((macros[macros[1]]:gsub(macros._rpmconfigdir, macros.buildroot .. macros._rpmconfigdir)))}
|
||||
%global __brp_python_bytecompile %{add_buildroot __brp_python_bytecompile}
|
||||
%global __brp_python_hardlink %{add_buildroot __brp_python_hardlink}
|
||||
%global __brp_fix_pyc_reproducibility %{add_buildroot __brp_fix_pyc_reproducibility}
|
||||
|
||||
|
||||
%check
|
||||
# no macros in comments
|
||||
grep -E '^#[^%%]*%%[^%%]' %{buildroot}%{rpmmacrodir}/macros.* && exit 1 || true
|
||||
|
||||
|
||||
%files
|
||||
%{rpmmacrodir}/macros.python
|
||||
%{rpmmacrodir}/macros.pybytecompile
|
||||
%{_rpmconfigdir}/redhat/import_all_modules.py
|
||||
%{_rpmconfigdir}/redhat/pathfix.py
|
||||
|
||||
%files -n python-srpm-macros
|
||||
%{rpmmacrodir}/macros.python-srpm
|
||||
%{_rpmconfigdir}/redhat/compileall2.py
|
||||
%{_rpmconfigdir}/redhat/clamp_source_mtime.py
|
||||
%{_rpmconfigdir}/redhat/brp-python-bytecompile
|
||||
%{_rpmconfigdir}/redhat/brp-python-hardlink
|
||||
%{_rpmconfigdir}/redhat/brp-fix-pyc-reproducibility
|
||||
%{_rpmluadir}/fedora/srpm/python.lua
|
||||
|
||||
%files -n python3-rpm-macros
|
||||
%{rpmmacrodir}/macros.python3
|
||||
|
||||
|
||||
%changelog
|
||||
* Tue Oct 29 2024 Troy Dawson <tdawson@redhat.com>
|
||||
- Bump release for October 2024 mass rebuild:
|
||||
Resolves: RHEL-64018
|
||||
|
||||
* Tue Jun 25 2024 Cristian Le <fedora@lecris.me> - 3.12-8.1
|
||||
- %%python_extras_subpkg: Add option -a to include BuildArch: noarch
|
||||
|
||||
* Mon Jun 24 2024 Troy Dawson <tdawson@redhat.com> - 3.12-8
|
||||
- Bump release for June 2024 mass rebuild
|
||||
|
||||
* Thu Jan 25 2024 Miro Hrončok <mhroncok@redhat.com> - 3.12-7
|
||||
- %%py3_test_envvars: Only set $PYTEST_XDIST_AUTO_NUM_WORKERS if not already set
|
||||
|
||||
* Mon Jan 22 2024 Fedora Release Engineering <releng@fedoraproject.org> - 3.12-6
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
|
||||
|
||||
* Mon Oct 09 2023 Maxwell G <maxwell@gtmx.me> - 3.12-5
|
||||
- Fix python macro memoizing to account for changing %%__python3
|
||||
|
||||
* Tue Sep 05 2023 Maxwell G <maxwell@gtmx.me> - 3.12-4
|
||||
- Remove %%py3_build_egg and %%py3_install_egg macros.
|
||||
|
||||
* Wed Aug 09 2023 Karolina Surma <ksurma@redhat.com> - 3.12-3
|
||||
- Declare the license as an SPDX expression
|
||||
|
||||
* Fri Jul 21 2023 Fedora Release Engineering <releng@fedoraproject.org> - 3.12-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
|
||||
|
||||
* Tue Jun 13 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12-1
|
||||
- Update main Python to Python 3.12
|
||||
- https://fedoraproject.org/wiki/Changes/Python3.12
|
||||
|
||||
* Thu Mar 16 2023 Miro Hrončok <mhroncok@redhat.com> - 3.11-10
|
||||
- Don't assume %%_smp_mflags only ever contains -jX, use -j%%_smp_build_ncpus directly
|
||||
- Fixes: rhbz#2179149
|
||||
|
||||
* Fri Jan 20 2023 Miro Hrončok <mhroncok@redhat.com> - 3.11-9
|
||||
- Memoize values of macros that execute python to get their value
|
||||
- Fixes: rhbz#2155505
|
||||
|
||||
* Fri Jan 20 2023 Fedora Release Engineering <releng@fedoraproject.org> - 3.11-8
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
|
||||
|
||||
* Mon Dec 19 2022 Miro Hrončok <mhroncok@redhat.com> - 3.11-7
|
||||
- Bytecompilation: Unset $SOURCE_DATE_EPOCH when %%clamp_mtime_to_source_date_epoch is not set
|
||||
- Bytecompilation: Pass --invalidation-mode=timestamp to compileall (on Python 3.7+)
|
||||
- Bytecompilation: Clamp source mtime: https://fedoraproject.org/wiki/Changes/ReproducibleBuildsClampMtimes
|
||||
- Bytecompilation: Compile Python files in parallel, according to %%_smp_mflags
|
||||
|
||||
* Sun Nov 13 2022 Miro Hrončok <mhroncok@redhat.com> - 3.11-6
|
||||
- Set PYTEST_XDIST_AUTO_NUM_WORKERS=%%{_smp_build_ncpus} from %%pytest
|
||||
- pytest-xdist 3+ respects this value when -n auto is used
|
||||
- Expose the environment variables used by %%pytest via %%{py3_test_envvars}
|
||||
|
||||
* Tue Oct 25 2022 Lumír Balhar <lbalhar@redhat.com> - 3.11-5
|
||||
- Include pathfix.py in this package
|
||||
|
||||
* 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
|
||||
- Allow commas as argument separator for extras names in %%python_extras_subpkg
|
||||
- Fixes: rhbz#1936486
|
||||
|
||||
* Sat Feb 20 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-35
|
||||
- Fix %%python_extras_subpkg with underscores in extras names
|
||||
|
||||
* Mon Feb 08 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-34
|
||||
- Remove python2-rpm-macros
|
||||
- https://fedoraproject.org/wiki/Changes/Disable_Python_2_Dist_RPM_Generators_and_Freeze_Python_2_Macros
|
||||
|
||||
* Fri Feb 05 2021 Miro Hrončok <mhroncok@redhat.com> - 3.9-13
|
||||
- Automatically word-wrap the description of extras subpackages
|
||||
- Fixes: rhbz#1922442
|
||||
|
||||
* Wed Jan 27 2021 Fedora Release Engineering <releng@fedoraproject.org> - 3.9-12
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
|
||||
|
||||
* Tue Dec 08 2020 Miro Hrončok <mhroncok@redhat.com> - 3.9-11
|
||||
- Support defining %%py3_shebang_flags to %%nil
|
||||
|
||||
* Mon Sep 14 2020 Miro Hrončok <mhroncok@redhat.com> - 3.9-10
|
||||
- Add %%python3_platform_triplet and %%python3_ext_suffix
|
||||
- https://fedoraproject.org/wiki/Changes/Python_Upstream_Architecture_Names
|
||||
|
||||
* Fri Jul 24 2020 Lumír Balhar <lbalhar@redhat.com> - 3.9-9
|
||||
- Adapt %%py[3]_shebang_fix to use versioned pathfixX.Y.py
|
||||
|
||||
* Fri Jul 24 2020 Lumír Balhar <lbalhar@redhat.com> - 3.9-8
|
||||
- Disable Python hash seed randomization in %%py_byte_compile
|
||||
|
||||
* Tue Jul 21 2020 Lumír Balhar <lbalhar@redhat.com> - 3.9-7
|
||||
- Make %%py3_dist respect %%python3_pkgversion
|
||||
|
||||
* Thu Jul 16 2020 Miro Hrončok <mhroncok@redhat.com> - 3.9-6
|
||||
- Make the unversioned %%__python macro error
|
||||
- https://fedoraproject.org/wiki/Changes/PythonMacroError
|
||||
- Make %%python macros more consistent with %%python3 macros
|
||||
- Define %%python_platform (as a Python version agnostic option to %%python3_platform)
|
||||
- Add --no-index --no-warn-script-location pip options to %%pyX_install_wheel
|
||||
|
||||
* Wed Jul 08 2020 Miro Hrončok <mhroncok@redhat.com> - 3.9-5
|
||||
- Introduce %%python_extras_subpkg
|
||||
- Adapt %%py_dist_name to keep square brackets
|
||||
- https://fedoraproject.org/wiki/Changes/PythonExtras
|
||||
|
||||
* Tue Jun 16 2020 Lumír Balhar <lbalhar@redhat.com> - 3.9-4
|
||||
- Use compileall from stdlib for Python >= 3.9
|
||||
|
||||
* Thu Jun 11 2020 Miro Hrončok <mhroncok@redhat.com> - 3.9-3
|
||||
- Allow to combine %%pycached with other macros (e.g. %%exclude or %%ghost) (#1838992)
|
||||
|
||||
* Sat May 30 2020 Miro Hrončok <mhroncok@redhat.com> - 3.9-2
|
||||
- Require the exact same version-release of other subpackages of this package
|
||||
|
||||
* Thu May 21 2020 Miro Hrončok <mhroncok@redhat.com> - 3.9-1
|
||||
- https://fedoraproject.org/wiki/Changes/Python3.9
|
||||
- Switch the %%py_dist_name macro to convert dots (".") into dashes as defined in PEP 503 (#1791530)
|
||||
|
||||
* Mon May 11 2020 Miro Hrončok <mhroncok@redhat.com> - 3.8-8
|
||||
- Implement %%pytest
|
||||
- Implement %%pyX_shebang_fix
|
||||
- Strip tildes from %%version in %%pypi_source by default
|
||||
|
||||
* Thu May 07 2020 Miro Hrončok <mhroncok@redhat.com> - 3.8-7
|
||||
- Change %%__default_python3_pkgversion from 38 to 3.8
|
||||
|
||||
* Tue May 05 2020 Miro Hrončok <mhroncok@redhat.com> - 3.8-6
|
||||
- Require recent enough SRPM macros from RPM macros, to prevent missing Lua files
|
||||
|
||||
* Tue May 05 2020 Miro Hrončok <mhroncok@redhat.com> - 3.8-5
|
||||
- Implement %%py_provides
|
||||
|
||||
* Mon May 04 2020 Tomas Hrnciar <thrnciar@redhat.com> - 3.8-4
|
||||
- Make %%py3_install_wheel macro remove direct_url.json file created by PEP 610.
|
||||
- https://discuss.python.org/t/pep-610-usage-guidelines-for-linux-distributions/4012
|
||||
|
||||
* Mon Apr 27 2020 Miro Hrončok <mhroncok@redhat.com> - 3.8-3
|
||||
- Make pythonX-rpm-macros depend on python-rpm-macros (#1827811)
|
||||
|
||||
* Tue Mar 31 2020 Lumír Balhar <lbalhar@redhat.com> - 3.8-2
|
||||
- Update of bundled compileall2 module to 0.7.1 (bugfix release)
|
||||
|
||||
* Mon Mar 23 2020 Miro Hrončok <mhroncok@redhat.com> - 3.8-1
|
||||
- Hardcode the default Python 3 version in the SRPM macros (#1812087)
|
||||
- Provide python38-foo for python3-foo and the other way around (future RHEL compatibility)
|
||||
- %%python_provide: Allow any names starting with "python" or "pypy"
|
||||
|
||||
* Mon Feb 10 2020 Miro Hrončok <mhroncok@redhat.com> - 3-54
|
||||
- Update of bundled compileall2 module to 0.7.0
|
||||
Adds the optional --hardlink-dupes flag for compileall2 for pyc deduplication
|
||||
|
||||
* Thu Feb 06 2020 Miro Hrončok <mhroncok@redhat.com> - 3-53
|
||||
- Define %%py(2|3)?_shbang_opts_nodash to be used with pathfix.py -a
|
||||
|
||||
* Thu Jan 30 2020 Fedora Release Engineering <releng@fedoraproject.org> - 3-52
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
|
||||
|
||||
* Sat Dec 28 2019 Miro Hrončok <mhroncok@redhat.com> - 3-51
|
||||
- Define %%python, but make it work only if %%__python is redefined
|
||||
- Add the %%pycached macro
|
||||
- Remove stray __pycache__ directory from /usr/bin when running %%py_install,
|
||||
%%py_install_wheel and %%py_build_wheel macros
|
||||
|
||||
* Tue Nov 26 2019 Lumír Balhar <lbalhar@redhat.com> - 3-50
|
||||
- Update of bundled compileall2 module
|
||||
|
||||
* Fri Sep 27 2019 Miro Hrončok <mhroncok@redhat.com> - 3-49
|
||||
- Define %%python2 and %%python3
|
||||
|
||||
* Mon Aug 26 2019 Miro Hrončok <mhroncok@redhat.com> - 3-48
|
||||
- Drop --strip-file-prefix option from %%pyX_install_wheel macros, it is not needed
|
||||
|
||||
* Fri Jul 26 2019 Fedora Release Engineering <releng@fedoraproject.org> - 3-47
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
|
||||
|
||||
* Fri Jul 12 2019 Miro Hrončok <mhroncok@redhat.com> - 3-46
|
||||
- %%python_provide: Switch python2 and python3 behavior
|
||||
- https://fedoraproject.org/wiki/Changes/Python_means_Python3
|
||||
- Use compileall2 module for byte-compilation with Python >= 3.4
|
||||
- Do not allow passing arguments to Python during byte-compilation
|
||||
- Use `-s` argument for Python during byte-compilation
|
||||
|
||||
* Tue Jul 09 2019 Miro Hrončok <mhroncok@redhat.com> - 3-45
|
||||
- %%python_provide: Don't try to obsolete %%_isa provides
|
||||
|
||||
* Mon Jun 17 2019 Miro Hrončok <mhroncok@redhat.com> - 3-44
|
||||
- Make %%__python /usr/bin/python once again until we are ready
|
||||
|
||||
* Mon Jun 10 2019 Miro Hrončok <mhroncok@redhat.com> - 3-43
|
||||
- Define %%python_sitelib, %%python_sitearch, %%python_version, %%python_version_nodots,
|
||||
in rpm 4.15 those are no longer defined, the meaning of python is derived from %%__python.
|
||||
- Usage of %%__python or the above-mentioned macros will error unless user defined.
|
||||
- The %%python_provide macro no longer gives the arched provide for arched packages (#1705656)
|
||||
|
||||
* Sat Feb 02 2019 Fedora Release Engineering <releng@fedoraproject.org> - 3-42
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
|
||||
|
||||
* Thu Dec 20 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 3-41
|
||||
- Add %%python_disable_dependency_generator
|
||||
|
||||
* Wed Dec 05 2018 Miro Hrončok <mhroncok@redhat.com> - 3-40
|
||||
- Workaround leaking buildroot PATH in %%py_byte_compile (#1647212)
|
||||
|
||||
* Thu Nov 01 2018 Petr Viktorin <pviktori@redhat.com> - 3-39
|
||||
- Move "sleep 1" workaround from py3_build to py2_build (#1644923)
|
||||
|
||||
* Thu Sep 20 2018 Tomas Orsava <torsava@redhat.com> - 3-38
|
||||
- Move the __python2/3 macros to the python-srpm-macros subpackage
|
||||
- This facilitates using the %%{__python2/3} in Build/Requires
|
||||
|
||||
* Wed Aug 15 2018 Miro Hrončok <mhroncok@redhat.com> - 3-37
|
||||
- Make %%py_byte_compile terminate build on SyntaxErrors (#1616219)
|
||||
|
||||
* Wed Aug 15 2018 Miro Hrončok <mhroncok@redhat.com> - 3-36
|
||||
- Make %%py_build wokr if %%__python is defined to custom value
|
||||
|
||||
* Sat Jul 28 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 3-35
|
||||
- Change way how enabling-depgen works internally
|
||||
|
||||
* Sat Jul 14 2018 Tomas Orsava <torsava@redhat.com> - 3-34
|
||||
- macros.pybytecompile: Detect Python version through sys.version_info instead
|
||||
of guessing from the executable name
|
||||
|
||||
* Sat Jul 14 2018 Fedora Release Engineering <releng@fedoraproject.org> - 3-33
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
|
||||
|
||||
* Tue Jul 10 2018 Tomas Orsava <torsava@redhat.com> - 3-32
|
||||
- Fix %%py_byte_compile macro: when invoked with a Python 2 binary it also
|
||||
mistakenly ran py3_byte_compile
|
||||
|
||||
* Tue Jul 03 2018 Miro Hrončok <mhroncok@redhat.com> - 3-31
|
||||
- Add %%python3_platform useful for PYTHONPATH on arched builds
|
||||
|
||||
* Mon Jun 18 2018 Jason L Tibbitts III <tibbs@math.uh.edu> - 3-30
|
||||
- Add %%pypi_source macro, as well as %%__pypi_url and
|
||||
%%_pypi_default_extension.
|
||||
|
||||
* Wed Apr 18 2018 Miro Hrončok <mhroncok@redhat.com> - 3-29
|
||||
- move macros.pybytecompile from python3-devel
|
||||
|
||||
* Fri Apr 06 2018 Tomas Orsava <torsava@redhat.com> - 3-28
|
||||
- Fix the %%py_dist_name macro to not convert dots (".") into dashes, so that
|
||||
submodules can be addressed as well
|
||||
Resolves: rhbz#1564095
|
||||
|
||||
* Fri Mar 23 2018 Miro Hrončok <mhroncok@redhat.com> - 3-27
|
||||
- make LDFLAGS propagated whenever CFLAGS are
|
||||
|
||||
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 3-26
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
|
||||
|
||||
* Fri Jan 19 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 3-25
|
||||
- Add %%python_enable_dependency_generator
|
||||
|
||||
* Tue Nov 28 2017 Tomas Orsava <torsava@redhat.com> - 3-24
|
||||
- Remove platform-python macros (https://fedoraproject.org/wiki/Changes/Platform_Python_Stack)
|
||||
|
||||
* Thu Oct 26 2017 Ville Skyttä <ville.skytta@iki.fi> - 3-23
|
||||
- Use -Es/-I to invoke macro scriptlets (#1506355)
|
||||
|
||||
* Wed Aug 02 2017 Tomas Orsava <torsava@redhat.com> - 3-22
|
||||
- Add platform-python macros (https://fedoraproject.org/wiki/Changes/Platform_Python_Stack)
|
||||
|
||||
* Thu Jul 27 2017 Fedora Release Engineering <releng@fedoraproject.org> - 3-21
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
|
||||
|
||||
* Fri Mar 03 2017 Michal Cyprian <mcyprian@redhat.com> - 3-20
|
||||
- Revert "Switch %%__python3 to /usr/libexec/system-python"
|
||||
after the Fedora Change https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe
|
||||
was postponed
|
||||
|
||||
* Fri Feb 17 2017 Michal Cyprian <mcyprian@redhat.com> - 3-19
|
||||
- Switch %%__python3 to /usr/libexec/system-python
|
||||
|
||||
* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 3-18
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
|
||||
|
||||
* Mon Jan 23 2017 Michal Cyprian <mcyprian@redhat.com> - 3-17
|
||||
- Add --no-deps option to py_install_wheel macros
|
||||
|
||||
* Tue Jan 17 2017 Tomas Orsava <torsava@redhat.com> - 3-16
|
||||
- Added macros for Build/Requires tags using Python dist tags:
|
||||
https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages
|
||||
|
||||
* Thu Nov 24 2016 Orion Poplawski <orion@cora.nwra.com> 3-15
|
||||
- Make expanded macros start on the same line as the macro
|
||||
|
||||
* Wed Nov 16 2016 Orion Poplawski <orion@cora.nwra.com> 3-14
|
||||
- Fix %%py3_install_wheel (bug #1395953)
|
||||
|
||||
* Wed Nov 16 2016 Orion Poplawski <orion@cora.nwra.com> 3-13
|
||||
- Add missing sleeps to other build macros
|
||||
- Fix build_egg macros
|
||||
- Add %%py_build_wheel and %%py_install_wheel macros
|
||||
|
||||
* Tue Nov 15 2016 Orion Poplawski <orion@cora.nwra.com> 3-12
|
||||
- Add %%py_build_egg and %%py_install_egg macros
|
||||
- Allow multiple args to %%py_build/install macros
|
||||
- Tidy up macro formatting
|
||||
|
||||
* Wed Aug 24 2016 Orion Poplawski <orion@cora.nwra.com> 3-11
|
||||
- Use %%rpmmacrodir
|
||||
|
||||
* Tue Jul 12 2016 Orion Poplawski <orion@cora.nwra.com> 3-10
|
||||
- Do not generate useless Obsoletes with %%{?_isa}
|
||||
|
||||
* Fri May 13 2016 Orion Poplawski <orion@cora.nwra.com> 3-9
|
||||
- Make python-rpm-macros require python-srpm-macros (bug #1335860)
|
||||
|
||||
* Thu May 12 2016 Jason L Tibbitts III <tibbs@math.uh.edu> - 3-8
|
||||
- Add single-second sleeps to work around setuptools bug.
|
||||
|
||||
* Thu Feb 04 2016 Fedora Release Engineering <releng@fedoraproject.org> - 3-7
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
|
||||
|
||||
* Thu Jan 14 2016 Orion Poplawski <orion@cora.nwra.com> 3-6
|
||||
- Fix typo in %%python_provide
|
||||
|
||||
* Thu Jan 14 2016 Orion Poplawski <orion@cora.nwra.com> 3-5
|
||||
- Handle noarch python sub-packages (bug #1290900)
|
||||
|
||||
* Wed Jan 13 2016 Orion Poplawski <orion@cora.nwra.com> 3-4
|
||||
- Fix python2/3-rpm-macros package names
|
||||
|
||||
* Thu Jan 7 2016 Orion Poplawski <orion@cora.nwra.com> 3-3
|
||||
- Add empty %%prep and %%build
|
||||
|
||||
* Mon Jan 4 2016 Orion Poplawski <orion@cora.nwra.com> 3-2
|
||||
- Combined package
|
||||
|
||||
* Wed Dec 30 2015 Orion Poplawski <orion@cora.nwra.com> 3-1
|
||||
- Initial package
|
101
python.lua
101
python.lua
@ -1,101 +0,0 @@
|
||||
-- Convenience Lua functions that can be used within Python srpm/rpm macros
|
||||
|
||||
-- Determine alternate names provided from the given name.
|
||||
-- Used in pythonname provides generator, python_provide and py_provides.
|
||||
-- If only_3_to_3_X is false/nil/unused there are 2 rules:
|
||||
-- python3-foo -> python-foo, python3.X-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.
|
||||
-- Returns a table/array with strings. Empty when no rule matched.
|
||||
local function python_altnames(name, only_3_to_3_X)
|
||||
local xy = rpm.expand('%{__default_python3_pkgversion}')
|
||||
local altnames = {}
|
||||
local replaced
|
||||
-- NB: dash needs to be escaped!
|
||||
if name:match('^python3%-') then
|
||||
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)
|
||||
table.insert(altnames, replaced)
|
||||
end
|
||||
elseif name:match('^python' .. xy .. '%-') and not only_3_to_3_X then
|
||||
for i, prefix in ipairs({'python-', 'python3-'}) do
|
||||
replaced = name:gsub('^python' .. xy .. '%-', prefix)
|
||||
table.insert(altnames, replaced)
|
||||
end
|
||||
end
|
||||
return altnames
|
||||
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.
|
||||
-- Uses python_altnames under the hood
|
||||
-- Returns a table/array with strings.
|
||||
local function python_altprovides(name, evr)
|
||||
return __python_alttags(name, evr, "provides")
|
||||
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.
|
||||
-- For each argument can only be used once, returns nil otherwise.
|
||||
-- Previous usage of python_altprovides counts as well.
|
||||
local function python_altprovides_once(name, evr)
|
||||
return __python_alttags_once(name, evr, "provides")
|
||||
end
|
||||
|
||||
-- Like python_altobsoletes but only return something once.
|
||||
-- For each argument can only be used once, returns nil otherwise.
|
||||
-- Previous usage of python_altobsoletes counts as well.
|
||||
local function python_altobsoletes_once(name, evr)
|
||||
return __python_alttags_once(name, evr, "obsoletes")
|
||||
end
|
||||
|
||||
|
||||
return {
|
||||
python_altnames = python_altnames,
|
||||
python_altprovides = python_altprovides,
|
||||
python_altobsoletes = python_altobsoletes,
|
||||
python_altprovides_once = python_altprovides_once,
|
||||
python_altobsoletes_once = python_altobsoletes_once,
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
# 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
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@ -1 +0,0 @@
|
||||
__*__/
|
@ -1,61 +0,0 @@
|
||||
%global basedir /opt/test/byte_compilation
|
||||
|
||||
Name: pythontest
|
||||
Version: 0
|
||||
Release: 0%{?dist}
|
||||
Summary: ...
|
||||
License: MIT
|
||||
BuildRequires: python3-devel
|
||||
|
||||
%description
|
||||
...
|
||||
|
||||
%install
|
||||
mkdir -p %{buildroot}%{basedir}/directory/to/test/recursion
|
||||
|
||||
echo "print()" > %{buildroot}%{basedir}/file.py
|
||||
echo "print()" > %{buildroot}%{basedir}/directory/to/test/recursion/file_in_dir.py
|
||||
|
||||
%py_byte_compile %{python3} %{buildroot}%{basedir}/file.py
|
||||
%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
|
||||
|
||||
%check
|
||||
LOCATIONS="
|
||||
%{buildroot}%{basedir}
|
||||
%{buildroot}%{python3_sitelib}/directory/
|
||||
"
|
||||
|
||||
# Count .py and .pyc files
|
||||
PY=$(find $LOCATIONS -name "*.py" | wc -l)
|
||||
PYC=$(find $LOCATIONS -name "*.pyc" | wc -l)
|
||||
|
||||
# We should have 3 .py files
|
||||
test $PY -eq 3
|
||||
|
||||
# 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
|
||||
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 "*.pyc") | sort -u | wc -l)
|
||||
test $PY -ge $INODES
|
||||
|
||||
|
||||
%files
|
||||
%pycached %{basedir}/file.py
|
||||
%pycached %{basedir}/directory/to/test/recursion/file_in_dir.py
|
||||
%pycached %{python3_sitelib}/directory/file.py
|
||||
|
||||
|
||||
%changelog
|
||||
* Thu Jan 01 2015 Fedora Packager <nobody@fedoraproject.org> - 0-0
|
||||
- This changelog entry exists and is deliberately set in the past
|
@ -1,960 +0,0 @@
|
||||
import os
|
||||
import subprocess
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
import pytest
|
||||
|
||||
X_Y = f'{sys.version_info[0]}.{sys.version_info[1]}'
|
||||
XY = f'{sys.version_info[0]}{sys.version_info[1]}'
|
||||
|
||||
# Handy environment variable you can use to run the tests
|
||||
# with modified macros files. Multiple files should be
|
||||
# separated by colon.
|
||||
# You can use * if you escape it from your Shell:
|
||||
# TESTED_FILES='macros.*' pytest -v
|
||||
# Remember that some tests might need more macros files than just
|
||||
# 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)
|
||||
|
||||
|
||||
def rpm_eval(expression, fails=False, **kwargs):
|
||||
if isinstance(expression, str):
|
||||
expression = [expression]
|
||||
cmd = ['rpmbuild']
|
||||
if TESTED_FILES:
|
||||
cmd += ['--macros', TESTED_FILES]
|
||||
for var, value in kwargs.items():
|
||||
if value is None:
|
||||
cmd += ['--undefine', var]
|
||||
else:
|
||||
cmd += ['--define', f'{var} {value}']
|
||||
for e in expression:
|
||||
cmd += ['--eval', e]
|
||||
cp = subprocess.run(cmd, text=True, env={**os.environ, 'LANG': 'C.utf-8'},
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if fails:
|
||||
assert cp.returncode != 0, cp.stdout
|
||||
elif fails is not None:
|
||||
assert cp.returncode == 0, cp.stdout
|
||||
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):
|
||||
return subprocess.check_output(script,
|
||||
env={**os.environ, 'LANG': 'C.utf-8'},
|
||||
text=True,
|
||||
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', [
|
||||
('a', 'a'),
|
||||
('a-a', 'a-a'),
|
||||
('a_a', 'a-a'),
|
||||
('a.a', 'a-a'),
|
||||
('a---a', 'a-a'),
|
||||
('a-_-a', 'a-a'),
|
||||
('a-_-a', 'a-a'),
|
||||
('a[b]', 'a[b]'),
|
||||
('Aha[Boom]', 'aha[boom]'),
|
||||
('a.a[b.b]', 'a-a[b-b]'),
|
||||
])
|
||||
def test_pydist_name(argument, result):
|
||||
assert rpm_eval(f'%py_dist_name {argument}') == [result]
|
||||
|
||||
|
||||
def test_py2_dist():
|
||||
assert rpm_eval(f'%py2_dist Aha[Boom] a') == ['python2dist(aha[boom]) python2dist(a)']
|
||||
|
||||
|
||||
def test_py3_dist():
|
||||
assert rpm_eval(f'%py3_dist Aha[Boom] a') == ['python3dist(aha[boom]) python3dist(a)']
|
||||
|
||||
|
||||
def test_py3_dist_with_python3_pkgversion_redefined(alt_x_y):
|
||||
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():
|
||||
assert rpm_eval('%python_provide python-foo') == []
|
||||
|
||||
|
||||
def test_python_provide_python3():
|
||||
lines = rpm_eval('%python_provide python3-foo', version='6', release='1.fc66')
|
||||
assert 'Obsoletes: 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 len(lines) == 3
|
||||
|
||||
|
||||
def test_python_provide_python3_epoched():
|
||||
lines = rpm_eval('%python_provide python3-foo', epoch='1', version='6', release='1.fc66')
|
||||
assert 'Obsoletes: 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 len(lines) == 3
|
||||
|
||||
|
||||
def test_python_provide_python3X():
|
||||
lines = rpm_eval(f'%python_provide python{X_Y}-foo', version='6', release='1.fc66')
|
||||
assert 'Obsoletes: 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 len(lines) == 3
|
||||
|
||||
|
||||
def test_python_provide_python3X_epoched():
|
||||
lines = rpm_eval(f'%python_provide python{X_Y}-foo', epoch='1', version='6', release='1.fc66')
|
||||
assert 'Obsoletes: 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 len(lines) == 3
|
||||
|
||||
|
||||
def test_python_provide_doubleuse():
|
||||
lines = rpm_eval('%{python_provide python3-foo}%{python_provide python3-foo}',
|
||||
version='6', release='1.fc66')
|
||||
assert 'Obsoletes: 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 len(lines) == 6
|
||||
assert len(set(lines)) == 3
|
||||
|
||||
|
||||
@pytest.mark.parametrize('rhel', [None, 10])
|
||||
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 len(lines) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize('rhel', [None, 12])
|
||||
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 len(lines) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize('rhel', [None, 9])
|
||||
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: python-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
|
||||
|
||||
|
||||
@pytest.mark.parametrize('rhel', [None, 9])
|
||||
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: python-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
|
||||
|
||||
|
||||
@pytest.mark.parametrize('rhel', [None, 13])
|
||||
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 'Provides: python-foo = 6-1.fc66' in lines
|
||||
assert 'Provides: python3-foo = 6-1.fc66' in lines
|
||||
assert len(lines) == 3
|
||||
|
||||
|
||||
@pytest.mark.parametrize('rhel', [None, 27])
|
||||
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 'Provides: python-foo = 1:6-1.fc66' in lines
|
||||
assert 'Provides: python3-foo = 1:6-1.fc66' in lines
|
||||
assert len(lines) == 3
|
||||
|
||||
|
||||
@pytest.mark.parametrize('rhel', [None, 2])
|
||||
def test_py_provides_doubleuse(rhel):
|
||||
lines = rpm_eval('%{py_provides python3-foo}%{py_provides python3-foo}',
|
||||
version='6', release='1.fc66', rhel=rhel)
|
||||
assert 'Provides: python3-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
|
||||
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(set(lines)) == 3
|
||||
|
||||
|
||||
@pytest.mark.parametrize('rhel', [None, 2])
|
||||
def test_py_provides_with_evr(rhel):
|
||||
lines = rpm_eval('%py_provides python3-foo 123',
|
||||
version='6', release='1.fc66', rhel=rhel)
|
||||
assert 'Provides: python3-foo = 123' in lines
|
||||
assert 'Provides: python-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
|
||||
|
||||
|
||||
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():
|
||||
lines = rpm_eval('%pytest -k foo')
|
||||
assert '/usr/bin/pytest -k foo' in lines[-1]
|
||||
|
||||
|
||||
def test_pytest_different_command():
|
||||
lines = rpm_eval('%pytest', __pytest='pytest-3')
|
||||
assert 'pytest-3' in lines[-1]
|
||||
|
||||
|
||||
def test_pytest_command_suffix():
|
||||
lines = rpm_eval('%pytest -v')
|
||||
assert '/usr/bin/pytest -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_sets_pytest_xdist_auto_num_workers():
|
||||
lines = rpm_eval('%pytest', _smp_build_ncpus=2)
|
||||
assert 'PYTEST_XDIST_AUTO_NUM_WORKERS="${PYTEST_XDIST_AUTO_NUM_WORKERS:-2}"' in '\n'.join(lines)
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.parametrize('__pytest_addopts', ['-X', None])
|
||||
def test_py3_test_envvars(lib, __pytest_addopts):
|
||||
lines = rpm_eval('%{py3_test_envvars}\\\n%{python3} -m unittest',
|
||||
buildroot='BUILDROOT',
|
||||
_smp_build_ncpus='3',
|
||||
__pytest_addopts=__pytest_addopts)
|
||||
assert all(l.endswith('\\') for l in lines[:-1])
|
||||
stripped_lines = [l.strip(' \\') for l in lines]
|
||||
sitearch = f'BUILDROOT/usr/{lib}/python{X_Y}/site-packages'
|
||||
sitelib = f'BUILDROOT/usr/lib/python{X_Y}/site-packages'
|
||||
assert f'PYTHONPATH="${{PYTHONPATH:-{sitearch}:{sitelib}}}"' in stripped_lines
|
||||
assert 'PATH="BUILDROOT/usr/bin:$PATH"' in stripped_lines
|
||||
assert 'CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}"' in stripped_lines
|
||||
assert 'PYTHONDONTWRITEBYTECODE=1' in stripped_lines
|
||||
assert 'PYTEST_XDIST_AUTO_NUM_WORKERS="${PYTEST_XDIST_AUTO_NUM_WORKERS:-3}"' in stripped_lines
|
||||
if __pytest_addopts:
|
||||
assert f'PYTEST_ADDOPTS="${{PYTEST_ADDOPTS:-}} {__pytest_addopts}"' in stripped_lines
|
||||
else:
|
||||
assert 'PYTEST_ADDOPTS' not in ''.join(lines)
|
||||
assert stripped_lines[-1] == '/usr/bin/python3 -m unittest'
|
||||
|
||||
|
||||
def test_pypi_source_default_name():
|
||||
urls = rpm_eval('%pypi_source',
|
||||
name='foo', version='6')
|
||||
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz']
|
||||
|
||||
|
||||
def test_pypi_source_default_srcname():
|
||||
urls = rpm_eval('%pypi_source',
|
||||
name='python-foo', srcname='foo', version='6')
|
||||
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz']
|
||||
|
||||
|
||||
def test_pypi_source_default_pypi_name():
|
||||
urls = rpm_eval('%pypi_source',
|
||||
name='python-foo', pypi_name='foo', version='6')
|
||||
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz']
|
||||
|
||||
|
||||
def test_pypi_source_default_name_uppercase():
|
||||
urls = rpm_eval('%pypi_source',
|
||||
name='Foo', version='6')
|
||||
assert urls == ['https://files.pythonhosted.org/packages/source/F/Foo/Foo-6.tar.gz']
|
||||
|
||||
|
||||
def test_pypi_source_provided_name():
|
||||
urls = rpm_eval('%pypi_source foo',
|
||||
name='python-bar', pypi_name='bar', version='6')
|
||||
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz']
|
||||
|
||||
|
||||
def test_pypi_source_provided_name_version():
|
||||
urls = rpm_eval('%pypi_source foo 6',
|
||||
name='python-bar', pypi_name='bar', version='3')
|
||||
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6.tar.gz']
|
||||
|
||||
|
||||
def test_pypi_source_provided_name_version_ext():
|
||||
url = rpm_eval('%pypi_source foo 6 zip',
|
||||
name='python-bar', pypi_name='bar', version='3')
|
||||
assert url == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6.zip']
|
||||
|
||||
|
||||
def test_pypi_source_prerelease():
|
||||
urls = rpm_eval('%pypi_source',
|
||||
name='python-foo', pypi_name='foo', version='6~b2')
|
||||
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6b2.tar.gz']
|
||||
|
||||
|
||||
def test_pypi_source_explicit_tilde():
|
||||
urls = rpm_eval('%pypi_source foo 6~6',
|
||||
name='python-foo', pypi_name='foo', version='6')
|
||||
assert urls == ['https://files.pythonhosted.org/packages/source/f/foo/foo-6~6.tar.gz']
|
||||
|
||||
|
||||
def test_py3_shebang_fix():
|
||||
cmd = rpm_eval('%py3_shebang_fix arg1 arg2 arg3')[-1].strip()
|
||||
assert cmd == '/usr/bin/python3 -B /usr/lib/rpm/redhat/pathfix.py -pni /usr/bin/python3 $shebang_flags arg1 arg2 arg3'
|
||||
|
||||
|
||||
def test_py3_shebang_fix_default_shebang_flags():
|
||||
lines = rpm_eval('%py3_shebang_fix arg1 arg2')
|
||||
lines[-1] = 'echo $shebang_flags'
|
||||
assert shell_stdout('\n'.join(lines)) == f'-kas{safe_path_flag(X_Y)}'
|
||||
|
||||
|
||||
def test_py3_shebang_fix_custom_shebang_flags():
|
||||
lines = rpm_eval('%py3_shebang_fix arg1 arg2', py3_shebang_flags='Es')
|
||||
lines[-1] = 'echo $shebang_flags'
|
||||
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}'])
|
||||
def test_py3_shebang_fix_no_shebang_flags(flags):
|
||||
lines = rpm_eval('%py3_shebang_fix arg1 arg2', py3_shebang_flags=flags)
|
||||
lines[-1] = 'echo $shebang_flags'
|
||||
assert shell_stdout('\n'.join(lines)) == '-k'
|
||||
|
||||
|
||||
def test_py_shebang_fix_custom_python():
|
||||
cmd = rpm_eval('%py_shebang_fix arg1 arg2 arg3', __python='/usr/bin/pypy')[-1].strip()
|
||||
assert cmd == '/usr/bin/pypy -B /usr/lib/rpm/redhat/pathfix.py -pni /usr/bin/pypy $shebang_flags arg1 arg2 arg3'
|
||||
|
||||
|
||||
def test_pycached_in_sitelib():
|
||||
lines = rpm_eval('%pycached %{python3_sitelib}/foo*.py')
|
||||
assert lines == [
|
||||
f'/usr/lib/python{X_Y}/site-packages/foo*.py',
|
||||
f'/usr/lib/python{X_Y}/site-packages/__pycache__/foo*.cpython-{XY}{{,.opt-?}}.pyc'
|
||||
]
|
||||
|
||||
|
||||
def test_pycached_in_sitearch(lib):
|
||||
lines = rpm_eval('%pycached %{python3_sitearch}/foo*.py')
|
||||
assert lines == [
|
||||
f'/usr/{lib}/python{X_Y}/site-packages/foo*.py',
|
||||
f'/usr/{lib}/python{X_Y}/site-packages/__pycache__/foo*.cpython-{XY}{{,.opt-?}}.pyc'
|
||||
]
|
||||
|
||||
|
||||
# this test does not require alternate Pythons to be installed
|
||||
@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 == [
|
||||
f'/usr/lib/python{version}/site-packages/foo*.py',
|
||||
f'/usr/lib/python{version}/site-packages/__pycache__/foo*.cpython-{version_nodot}{{,.opt-?}}.pyc'
|
||||
]
|
||||
|
||||
|
||||
def test_pycached_in_custom_dir():
|
||||
lines = rpm_eval('%pycached /bar/foo*.py')
|
||||
assert lines == [
|
||||
'/bar/foo*.py',
|
||||
'/bar/__pycache__/foo*.cpython-3*{,.opt-?}.pyc'
|
||||
]
|
||||
|
||||
|
||||
def test_pycached_with_exclude():
|
||||
lines = rpm_eval('%pycached %exclude %{python3_sitelib}/foo*.py')
|
||||
assert lines == [
|
||||
f'%exclude /usr/lib/python{X_Y}/site-packages/foo*.py',
|
||||
f'%exclude /usr/lib/python{X_Y}/site-packages/__pycache__/foo*.cpython-{XY}{{,.opt-?}}.pyc'
|
||||
]
|
||||
|
||||
|
||||
def test_pycached_fails_with_extension_glob():
|
||||
lines = rpm_eval('%pycached %{python3_sitelib}/foo.py*', fails=True)
|
||||
assert lines[0] == 'error: %pycached can only be used with paths explicitly ending with .py'
|
||||
|
||||
|
||||
def test_python_extras_subpkg_i():
|
||||
lines = rpm_eval('%python_extras_subpkg -n python3-setuptools_scm -i %{python3_sitelib}/*.egg-info toml yaml',
|
||||
version='6', release='7')
|
||||
expected = textwrap.dedent(f"""
|
||||
%package -n python3-setuptools_scm+toml
|
||||
Summary: Metapackage for python3-setuptools_scm: toml extras
|
||||
Requires: python3-setuptools_scm = 6-7
|
||||
%description -n python3-setuptools_scm+toml
|
||||
This is a metapackage bringing in toml extras requires for
|
||||
python3-setuptools_scm.
|
||||
It makes sure the dependencies are installed.
|
||||
|
||||
%files -n python3-setuptools_scm+toml
|
||||
%ghost /usr/lib/python{X_Y}/site-packages/*.egg-info
|
||||
|
||||
%package -n python3-setuptools_scm+yaml
|
||||
Summary: Metapackage for python3-setuptools_scm: yaml extras
|
||||
Requires: python3-setuptools_scm = 6-7
|
||||
%description -n python3-setuptools_scm+yaml
|
||||
This is a metapackage bringing in yaml extras requires for
|
||||
python3-setuptools_scm.
|
||||
It makes sure the dependencies are installed.
|
||||
|
||||
%files -n python3-setuptools_scm+yaml
|
||||
%ghost /usr/lib/python{X_Y}/site-packages/*.egg-info
|
||||
""").lstrip().splitlines()
|
||||
assert lines == expected
|
||||
|
||||
|
||||
def test_python_extras_subpkg_f():
|
||||
lines = rpm_eval('%python_extras_subpkg -n python3-setuptools_scm -f ghost_filelist toml yaml',
|
||||
version='6', release='7')
|
||||
expected = textwrap.dedent(f"""
|
||||
%package -n python3-setuptools_scm+toml
|
||||
Summary: Metapackage for python3-setuptools_scm: toml extras
|
||||
Requires: python3-setuptools_scm = 6-7
|
||||
%description -n python3-setuptools_scm+toml
|
||||
This is a metapackage bringing in toml extras requires for
|
||||
python3-setuptools_scm.
|
||||
It makes sure the dependencies are installed.
|
||||
|
||||
%files -n python3-setuptools_scm+toml -f ghost_filelist
|
||||
|
||||
%package -n python3-setuptools_scm+yaml
|
||||
Summary: Metapackage for python3-setuptools_scm: yaml extras
|
||||
Requires: python3-setuptools_scm = 6-7
|
||||
%description -n python3-setuptools_scm+yaml
|
||||
This is a metapackage bringing in yaml extras requires for
|
||||
python3-setuptools_scm.
|
||||
It makes sure the dependencies are installed.
|
||||
|
||||
%files -n python3-setuptools_scm+yaml -f ghost_filelist
|
||||
""").lstrip().splitlines()
|
||||
assert lines == expected
|
||||
|
||||
|
||||
def test_python_extras_subpkg_F():
|
||||
lines = rpm_eval('%python_extras_subpkg -n python3-setuptools_scm -F toml yaml',
|
||||
version='6', release='7')
|
||||
expected = textwrap.dedent(f"""
|
||||
%package -n python3-setuptools_scm+toml
|
||||
Summary: Metapackage for python3-setuptools_scm: toml extras
|
||||
Requires: python3-setuptools_scm = 6-7
|
||||
%description -n python3-setuptools_scm+toml
|
||||
This is a metapackage bringing in toml extras requires for
|
||||
python3-setuptools_scm.
|
||||
It makes sure the dependencies are installed.
|
||||
|
||||
|
||||
|
||||
%package -n python3-setuptools_scm+yaml
|
||||
Summary: Metapackage for python3-setuptools_scm: yaml extras
|
||||
Requires: python3-setuptools_scm = 6-7
|
||||
%description -n python3-setuptools_scm+yaml
|
||||
This is a metapackage bringing in yaml extras requires for
|
||||
python3-setuptools_scm.
|
||||
It makes sure the dependencies are installed.
|
||||
""").lstrip().splitlines()
|
||||
assert lines == expected
|
||||
|
||||
|
||||
def test_python_extras_subpkg_a():
|
||||
lines = rpm_eval('%python_extras_subpkg -n python3-setuptools_scm -a -F toml',
|
||||
version='6', release='7')
|
||||
expected = textwrap.dedent(f"""
|
||||
%package -n python3-setuptools_scm+toml
|
||||
Summary: Metapackage for python3-setuptools_scm: toml extras
|
||||
Requires: python3-setuptools_scm = 6-7
|
||||
BuildArch: noarch
|
||||
%description -n python3-setuptools_scm+toml
|
||||
This is a metapackage bringing in toml extras requires for
|
||||
python3-setuptools_scm.
|
||||
It makes sure the dependencies are installed.
|
||||
""").lstrip().splitlines()
|
||||
assert lines == expected
|
||||
|
||||
|
||||
def test_python_extras_subpkg_A():
|
||||
lines = rpm_eval('%python_extras_subpkg -n python3-setuptools_scm -A -F toml',
|
||||
version='6', release='7')
|
||||
expected = textwrap.dedent(f"""
|
||||
%package -n python3-setuptools_scm+toml
|
||||
Summary: Metapackage for python3-setuptools_scm: toml extras
|
||||
Requires: python3-setuptools_scm = 6-7
|
||||
%description -n python3-setuptools_scm+toml
|
||||
This is a metapackage bringing in toml extras requires for
|
||||
python3-setuptools_scm.
|
||||
It makes sure the dependencies are installed.
|
||||
""").lstrip().splitlines()
|
||||
assert lines == expected
|
||||
|
||||
|
||||
def test_python_extras_subpkg_aA():
|
||||
lines = rpm_eval('%python_extras_subpkg -n python3-setuptools_scm -a -A -F toml',
|
||||
version='6', release='7', fails=True)
|
||||
assert lines[0] == ('error: %python_extras_subpkg: simultaneous -a '
|
||||
'(insert BuildArch: noarch) and -A (do not insert '
|
||||
'BuildArch: noarch (default)) options are not possible')
|
||||
|
||||
|
||||
def test_python_extras_subpkg_underscores():
|
||||
lines = rpm_eval('%python_extras_subpkg -n python3-webscrapbook -F adhoc_ssl',
|
||||
version='0.33.3', release='1.fc33')
|
||||
expected = textwrap.dedent(f"""
|
||||
%package -n python3-webscrapbook+adhoc_ssl
|
||||
Summary: Metapackage for python3-webscrapbook: adhoc_ssl extras
|
||||
Requires: python3-webscrapbook = 0.33.3-1.fc33
|
||||
%description -n python3-webscrapbook+adhoc_ssl
|
||||
This is a metapackage bringing in adhoc_ssl extras requires for
|
||||
python3-webscrapbook.
|
||||
It makes sure the dependencies are installed.
|
||||
""").lstrip().splitlines()
|
||||
assert lines == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize('sep', [pytest.param(('', ' ', ' ', ''), id='spaces'),
|
||||
pytest.param(('', ',', ',', ''), id='commas'),
|
||||
pytest.param(('', ',', ',', ','), id='commas-trailing'),
|
||||
pytest.param((',', ',', ',', ''), id='commas-leading'),
|
||||
pytest.param((',', ',', ',', ','), id='commas-trailing-leading'),
|
||||
pytest.param(('', ',', ' ', ''), id='mixture'),
|
||||
pytest.param((' ', ' ', '\t\t, ', '\t'), id='chaotic-good'),
|
||||
pytest.param(('', '\t ,, \t\r ', ',,\t , ', ',,'), id='chaotic-evil')])
|
||||
def test_python_extras_subpkg_arg_separators(sep):
|
||||
lines = rpm_eval('%python_extras_subpkg -n python3-hypothesis -F {}cli{}ghostwriter{}pytz{}'.format(*sep),
|
||||
version='6.6.0', release='1.fc35')
|
||||
expected = textwrap.dedent(f"""
|
||||
%package -n python3-hypothesis+cli
|
||||
Summary: Metapackage for python3-hypothesis: cli extras
|
||||
Requires: python3-hypothesis = 6.6.0-1.fc35
|
||||
%description -n python3-hypothesis+cli
|
||||
This is a metapackage bringing in cli extras requires for python3-hypothesis.
|
||||
It makes sure the dependencies are installed.
|
||||
|
||||
|
||||
|
||||
%package -n python3-hypothesis+ghostwriter
|
||||
Summary: Metapackage for python3-hypothesis: ghostwriter extras
|
||||
Requires: python3-hypothesis = 6.6.0-1.fc35
|
||||
%description -n python3-hypothesis+ghostwriter
|
||||
This is a metapackage bringing in ghostwriter extras requires for
|
||||
python3-hypothesis.
|
||||
It makes sure the dependencies are installed.
|
||||
|
||||
|
||||
|
||||
%package -n python3-hypothesis+pytz
|
||||
Summary: Metapackage for python3-hypothesis: pytz extras
|
||||
Requires: python3-hypothesis = 6.6.0-1.fc35
|
||||
%description -n python3-hypothesis+pytz
|
||||
This is a metapackage bringing in pytz extras requires for python3-hypothesis.
|
||||
It makes sure the dependencies are installed.
|
||||
""").lstrip().splitlines()
|
||||
assert lines == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize('basename_len', [1, 10, 30, 45, 78])
|
||||
@pytest.mark.parametrize('extra_len', [1, 13, 28, 52, 78])
|
||||
def test_python_extras_subpkg_description_wrapping(basename_len, extra_len):
|
||||
basename = 'x' * basename_len
|
||||
extra = 'y' * extra_len
|
||||
lines = rpm_eval(f'%python_extras_subpkg -n {basename} -F {extra}',
|
||||
version='6', release='7')
|
||||
for idx, line in enumerate(lines):
|
||||
if line.startswith('%description'):
|
||||
start = idx + 1
|
||||
lines = lines[start:]
|
||||
assert all(len(l) < 80 for l in lines)
|
||||
assert len(lines) < 6
|
||||
if len(" ".join(lines[:-1])) < 80:
|
||||
assert len(lines) == 2
|
||||
expected_singleline = (f"This is a metapackage bringing in {extra} extras "
|
||||
f"requires for {basename}. "
|
||||
f"It makes sure the dependencies are installed.")
|
||||
description_singleline = " ".join(lines)
|
||||
assert description_singleline == expected_singleline
|
||||
|
||||
|
||||
unversioned_macros = pytest.mark.parametrize('macro', [
|
||||
'%__python',
|
||||
'%python',
|
||||
'%python_version',
|
||||
'%python_version_nodots',
|
||||
'%python_sitelib',
|
||||
'%python_sitearch',
|
||||
'%python_platform',
|
||||
'%python_platform_triplet',
|
||||
'%python_ext_suffix',
|
||||
'%python_cache_tag',
|
||||
'%py_shebang_fix',
|
||||
'%py_build',
|
||||
'%py_build_wheel',
|
||||
'%py_install',
|
||||
'%py_install_wheel',
|
||||
'%py_check_import',
|
||||
'%py_test_envvars',
|
||||
])
|
||||
|
||||
|
||||
@unversioned_macros
|
||||
def test_unversioned_python_errors(macro):
|
||||
lines = rpm_eval(macro, fails=True)
|
||||
assert lines[0] == (
|
||||
'error: attempt to use unversioned python, '
|
||||
'define %__python to /usr/bin/python2 or /usr/bin/python3 explicitly'
|
||||
)
|
||||
# when the macros are %global, the error is longer
|
||||
# we deliberately allow this extra line to be optional
|
||||
if len(lines) > 1 and "error: lua script failed" not in lines[1]:
|
||||
# the failed macro is not unnecessarily our tested macro
|
||||
pattern = r'error: Macro %\S+ failed to expand'
|
||||
assert re.match(pattern, lines[1])
|
||||
# but there should be no more lines
|
||||
assert len(lines) < 3
|
||||
|
||||
|
||||
@unversioned_macros
|
||||
def test_unversioned_python_works_when_defined(macro):
|
||||
macro3 = macro.replace('python', 'python3').replace('py_', 'py3_')
|
||||
assert rpm_eval(macro, __python='/usr/bin/python3') == rpm_eval(macro3)
|
||||
|
||||
|
||||
# we could rework the test for multiple architectures, but the Fedora CI currently only runs on x86_64
|
||||
x86_64_only = pytest.mark.skipif(platform.machine() != "x86_64", reason="works on x86_64 only")
|
||||
|
||||
|
||||
@x86_64_only
|
||||
def test_platform_triplet():
|
||||
assert rpm_eval("%python3_platform_triplet") == ["x86_64-linux-gnu"]
|
||||
|
||||
|
||||
@x86_64_only
|
||||
def test_ext_suffix():
|
||||
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
|
||||
|
||||
|
||||
def test_multi_python(alt_x_y):
|
||||
"""
|
||||
Ensure memoized %python_version works when switching %__python back
|
||||
and forth.
|
||||
"""
|
||||
versions = ['3', alt_x_y, X_Y, '3']
|
||||
evals = []
|
||||
for version in versions:
|
||||
evals.extend((f'%global __python /usr/bin/python{version}', '%python_version'))
|
||||
lines = rpm_eval(evals)
|
||||
lines = [l for l in lines if l] # strip empty lines generated by %global
|
||||
assert lines == [X_Y, alt_x_y, X_Y, X_Y]
|
||||
|
||||
|
||||
def test_multi_python3(alt_x_y):
|
||||
"""
|
||||
Ensure memoized %python3_version works when switching %__python3 back
|
||||
and forth.
|
||||
"""
|
||||
versions = ['3', alt_x_y, X_Y, '3']
|
||||
evals = []
|
||||
for version in versions:
|
||||
evals.extend((f'%global __python3 /usr/bin/python{version}', '%python3_version'))
|
||||
lines = rpm_eval(evals)
|
||||
lines = [l for l in lines if l] # strip empty lines generated by %global
|
||||
assert lines == [X_Y, alt_x_y, X_Y, X_Y]
|
@ -1,426 +0,0 @@
|
||||
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\ncsv\n')
|
||||
|
||||
# Make sure the tested modules are not already in sys.modules
|
||||
for m in ('math', 'wave', 'csv'):
|
||||
sys.modules.pop(m, None)
|
||||
|
||||
modules_main(['-f', str(test_file)])
|
||||
|
||||
assert 'csv' 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('csv\npathlib\n')
|
||||
test_file_3.write_text('logging\ncsv\n')
|
||||
|
||||
# Make sure the tested modules are not already in sys.modules
|
||||
for m in ('math', 'wave', 'csv', '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 ('csv', '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'
|
@ -1,37 +0,0 @@
|
||||
---
|
||||
- hosts: localhost
|
||||
tags:
|
||||
- classic
|
||||
tasks:
|
||||
- dnf:
|
||||
name: "*"
|
||||
state: latest
|
||||
|
||||
- hosts: localhost
|
||||
roles:
|
||||
- role: standard-test-basic
|
||||
tags:
|
||||
- classic
|
||||
tests:
|
||||
- pytest:
|
||||
dir: .
|
||||
run: PYTHONPATH=/usr/lib/rpm/redhat ALTERNATE_PYTHON_VERSION=SKIP pytest -v
|
||||
- manual_byte_compilation_clamp_mtime_off:
|
||||
dir: .
|
||||
run: rpmbuild --define 'dist .clamp0' --define 'clamp_mtime_to_source_date_epoch 0' -ba pythontest.spec
|
||||
- manual_byte_compilation_clamp_mtime_on:
|
||||
dir: .
|
||||
run: rpmbuild --define 'dist .clamp1' --define 'clamp_mtime_to_source_date_epoch 1' -ba pythontest.spec
|
||||
- rpmlint_clamp_mtime_off:
|
||||
dir: .
|
||||
run: rpmlint ~/rpmbuild/RPMS/x86_64/pythontest-0-0.clamp0.x86_64.rpm | grep python-bytecode-inconsistent-mtime || exit 0 && exit 1
|
||||
- rpmlint_clamp_mtime_on:
|
||||
dir: .
|
||||
run: rpmlint ~/rpmbuild/RPMS/x86_64/pythontest-0-0.clamp1.x86_64.rpm | grep python-bytecode-inconsistent-mtime || exit 0 && exit 1
|
||||
required_packages:
|
||||
- rpm-build
|
||||
- rpmlint
|
||||
- python-rpm-macros
|
||||
- python3-rpm-macros
|
||||
- python3-devel
|
||||
- python3-pytest
|
Loading…
Reference in New Issue
Block a user