From 7134521c327f522c9d378949cf32460bfbcaccb5 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Wed, 8 Jun 2022 20:15:45 +0200 Subject: Improve handling if runtime_library_dirs is set with cygwin/mingw On Windows there is nothing like rpath, so when CygwinCCompiler() tries to link it will assume unix and pass rpath flags to the linker, which will fail. In cygwin this is currently patched away: https://cygwin.com/git-cygwin-packages/?p=git/cygwin-packages/python39.git;a=blob;f=3.1-enable-new-dtags.patch;h=716af3b14d3483e5a4 It is taking some macos fallback branch that is equal to library_dirs, which doesn't add much if library_dirs is set, so in theory it should just return [] there. This patch tries to bring it a bit closer to MSVCCompiler() which warns if runtime_library_dirs is passed and raises if runtime_library_dir_option() is called. In the case of cygwin we only warn if runtime_library_dir_option() is called and return nothing, so runtime_library_dirs is ignored. It's debatable if it should fail here, but since cygwin is used to build unix software that might not be aware of this limitation a warning seems more fitting. In the mingw case we assume the user knows that they are targeting Windows and so we can be more strict and error out like MSVCCompiler(). In both cases we warn if runtime_library_dirs is passed to the compiler, like with MSVC. --- distutils/cygwinccompiler.py | 19 +++++++++++++++++++ distutils/tests/test_cygwinccompiler.py | 6 ++++++ 2 files changed, 25 insertions(+) diff --git a/distutils/cygwinccompiler.py b/distutils/cygwinccompiler.py index 931b3661..445e2e51 100644 --- a/distutils/cygwinccompiler.py +++ b/distutils/cygwinccompiler.py @@ -58,6 +58,7 @@ from distutils.unixccompiler import UnixCCompiler from distutils.file_util import write_file from distutils.errors import ( DistutilsExecError, + DistutilsPlatformError, CCompilerError, CompileError, UnknownFileError, @@ -197,6 +198,12 @@ class CygwinCCompiler(UnixCCompiler): libraries = copy.copy(libraries or []) objects = copy.copy(objects or []) + if runtime_library_dirs: + self.warn( + "I don't know what to do with 'runtime_library_dirs': " + + str(runtime_library_dirs) + ) + # Additional libraries libraries.extend(self.dll_libraries) @@ -265,6 +272,13 @@ class CygwinCCompiler(UnixCCompiler): target_lang, ) + def runtime_library_dir_option(self, dir): + # cygwin doesn't support rpath. While in theory we could error + # out like MSVC does, code might expect it to work like on Unix, so + # just warn and hope for the best. + self.warn("don't know how to set runtime library search path on Windows") + return [] + # -- Miscellaneous methods ----------------------------------------- def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): @@ -325,6 +339,11 @@ class Mingw32CCompiler(CygwinCCompiler): # with MSVC 7.0 or later. self.dll_libraries = get_msvcr() + def runtime_library_dir_option(self, dir): + raise DistutilsPlatformError( + "don't know how to set runtime library search path on Windows" + ) + # Because these compilers aren't configured in Python's pyconfig.h file by # default, we should at least warn the user if he is using an unmodified diff --git a/distutils/tests/test_cygwinccompiler.py b/distutils/tests/test_cygwinccompiler.py index b3c164ed..7760436a 100644 --- a/distutils/tests/test_cygwinccompiler.py +++ b/distutils/tests/test_cygwinccompiler.py @@ -48,6 +48,12 @@ class CygwinCCompilerTestCase(support.TempdirManager, unittest.TestCase): self.assertTrue(os.path.exists(linkable_file)) self.assertEquals(linkable_file, "/usr/lib/lib{:s}.dll.a".format(link_name)) + @unittest.skipIf(sys.platform != "cygwin", "Not running on Cygwin") + def test_runtime_library_dir_option(self): + from distutils.cygwinccompiler import CygwinCCompiler + compiler = CygwinCCompiler() + self.assertEqual(compiler.runtime_library_dir_option('/foo'), []) + def test_check_config_h(self): # check_config_h looks for "GCC" in sys.version first -- cgit v1.2.1 From 7f1b23d57e7199a3f1cc826b4d94f0c66be3574d Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Fri, 10 Jun 2022 21:45:11 +0100 Subject: Add test capturing expectations --- distutils/tests/test_build_py.py | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/distutils/tests/test_build_py.py b/distutils/tests/test_build_py.py index 4585d799..eb01d81a 100644 --- a/distutils/tests/test_build_py.py +++ b/distutils/tests/test_build_py.py @@ -7,6 +7,7 @@ import unittest from distutils.command.build_py import build_py from distutils.core import Distribution from distutils.errors import DistutilsFileError +from unittest.mock import patch from distutils.tests import support from test.support import run_unittest @@ -167,6 +168,47 @@ class BuildPyTestCase( self.assertIn('byte-compiling is disabled', self.logs[0][1] % self.logs[0][2]) + @patch("distutils.command.build_py.log.warn") + def test_namespace_package_does_not_warn(self, log_warn): + """ + Originally distutils implementation did not account for PEP 420 + and included warns for package directories that did not contain + ``__init__.py`` files. + After the acceptance of PEP 420, these warnings don't make more sense + so we want to ensure there are not displayed to not confuse the users. + """ + # Create a fake project structure with a package namespace: + tmp = self.mkdtemp() + os.chdir(tmp) + os.makedirs("ns/pkg") + open("ns/pkg/module.py", "w").close() + + # Set up a trap if the undesirable effect is observed: + def _trap(msg, *args): + if "package init file" in msg and "not found" in msg: + raise AssertionError(f"Undesired warning: {msg!r} {args!r}") + + log_warn.side_effect = _trap + + # Configure the package: + attrs = { + "name": "ns.pkg", + "packages": ["ns", "ns.pkg"], + "script_name": "setup.py", + } + dist = Distribution(attrs) + + # Run code paths that would trigger the trap: + cmd = dist.get_command_obj("build_py") + cmd.finalize_options() + modules = cmd.find_all_modules() + assert len(modules) == 1 + module_path = modules[0][-1] + assert module_path.replace(os.sep, "/") == "ns/pkg/module.py" + + cmd.run() + # Test should complete successfully with no exception + def test_suite(): return unittest.TestLoader().loadTestsFromTestCase(BuildPyTestCase) -- cgit v1.2.1 From 27350b0b0cf11313509160542f435bfe59782afa Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Fri, 10 Jun 2022 21:03:03 +0100 Subject: Remove warnings on namespace packages --- distutils/command/build_py.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/distutils/command/build_py.py b/distutils/command/build_py.py index 1b22004e..7723d359 100644 --- a/distutils/command/build_py.py +++ b/distutils/command/build_py.py @@ -201,16 +201,11 @@ class build_py(Command): "but is not a directory" % package_dir ) - # Require __init__.py for all but the "root package" + # Directories without __init__.py are namespace packages (PEP 420). if package: init_py = os.path.join(package_dir, "__init__.py") if os.path.isfile(init_py): return init_py - else: - log.warn( - ("package init file '%s' not found " + "(or not a regular file)"), - init_py, - ) # Either not in a package at all (__init__.py not expected), or # __init__.py doesn't exist -- so don't return the filename. -- cgit v1.2.1 From 949193ffe6385b4823bc954ac7e317df5403578f Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 2 Jul 2022 11:52:07 -0400 Subject: Add support for Homebrew on Python 3.9 instead of relying on distutils.cfg as found in the stdlib. Fixes pypa/distutils#152. --- distutils/command/_framework_compat.py | 52 ++++++++++++++++++++++++++++++++++ distutils/command/install.py | 9 ++++-- 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 distutils/command/_framework_compat.py diff --git a/distutils/command/_framework_compat.py b/distutils/command/_framework_compat.py new file mode 100644 index 00000000..e032603a --- /dev/null +++ b/distutils/command/_framework_compat.py @@ -0,0 +1,52 @@ +""" +Backward compatibility for homebrew builds on macOS. +""" + + +import sys +import os +import functools +import subprocess + + +@functools.lru_cache() +def enabled(): + """ + Only enabled for Python 3.9 framework builds except ensurepip and venv. + """ + PY39 = (3, 9) < sys.version_info < (3, 10) + framework = sys.platform == 'darwin' and sys._framework + venv = sys.prefix != sys.base_prefix + ensurepip = os.environ.get("ENSUREPIP_OPTIONS") + return PY39 and framework and not venv and not ensurepip + + +schemes = dict( + osx_framework_library=dict( + stdlib='{installed_base}/{platlibdir}/python{py_version_short}', + platstdlib='{platbase}/{platlibdir}/python{py_version_short}', + purelib='{homebrew_prefix}/lib/python{py_version_short}/site-packages', + platlib='{homebrew_prefix}/{platlibdir}/python{py_version_short}/site-packages', + include='{installed_base}/include/python{py_version_short}{abiflags}', + platinclude='{installed_platbase}/include/python{py_version_short}{abiflags}', + scripts='{homebrew_prefix}/bin', + data='{homebrew_prefix}', + ) +) + + +@functools.lru_cache() +def vars(): + if not enabled(): + return {} + homebrew_prefix = subprocess.check_output(['brew', '--prefix'], text=True).strip() + return locals() + + +def scheme(name): + """ + Override the selected scheme for posix_prefix. + """ + if not enabled() or not name.endswith('_prefix'): + return name + return 'osx_framework_library' diff --git a/distutils/command/install.py b/distutils/command/install.py index 0660406f..7d9054e3 100644 --- a/distutils/command/install.py +++ b/distutils/command/install.py @@ -17,6 +17,7 @@ from distutils.file_util import write_file from distutils.util import convert_path, subst_vars, change_root from distutils.util import get_platform from distutils.errors import DistutilsOptionError +from . import _framework_compat as fw from .. import _collections from site import USER_BASE @@ -82,6 +83,10 @@ if HAS_USER_SITE: 'data': '{userbase}', } + +INSTALL_SCHEMES.update(fw.schemes) + + # The keys to an installation scheme; if any new types of files are to be # installed, be sure to add an entry to every installation scheme above, # and to SCHEME_KEYS here. @@ -136,7 +141,7 @@ def _resolve_scheme(name): try: resolved = sysconfig.get_preferred_scheme(key) except Exception: - resolved = _pypy_hack(name) + resolved = fw.scheme(_pypy_hack(name)) return resolved @@ -426,7 +431,7 @@ class install(Command): local_vars['usersite'] = self.install_usersite self.config_vars = _collections.DictStack( - [compat_vars, sysconfig.get_config_vars(), local_vars] + [fw.vars(), compat_vars, sysconfig.get_config_vars(), local_vars] ) self.expand_basedirs() -- cgit v1.2.1