diff --git a/Lib/packaging/config.py b/Lib/packaging/config.py index 21bbcf8567a..43263f7eead 100644 --- a/Lib/packaging/config.py +++ b/Lib/packaging/config.py @@ -134,15 +134,20 @@ class Config: if 'setup_hooks' in content['global']: setup_hooks = split_multiline(content['global']['setup_hooks']) - for line in setup_hooks: - try: - hook = resolve_name(line) - except ImportError as e: - logger.warning('cannot find setup hook: %s', e.args[0]) - else: - self.setup_hooks.append(hook) - - self.run_hooks(content) + # add project directory to sys.path, to allow hooks to be + # distributed with the project + sys.path.insert(0, cfg_directory) + try: + for line in setup_hooks: + try: + hook = resolve_name(line) + except ImportError as e: + logger.warning('cannot find setup hook: %s', e.args[0]) + else: + self.setup_hooks.append(hook) + self.run_hooks(content) + finally: + sys.path.pop(0) metadata = self.dist.metadata diff --git a/Lib/packaging/tests/test_config.py b/Lib/packaging/tests/test_config.py index 6be63ebbeb7..43ab2c85b4c 100644 --- a/Lib/packaging/tests/test_config.py +++ b/Lib/packaging/tests/test_config.py @@ -126,6 +126,15 @@ language = cxx """ +HOOKS_MODULE = """ +import logging + +logger = logging.getLogger('packaging') + +def logging_hook(config): + logger.warning('logging_hook called') +""" + class DCompiler: name = 'd' @@ -326,10 +335,21 @@ class ConfigTestCase(support.TempdirManager, self.assertEqual(ext.extra_compile_args, cargs) self.assertEqual(ext.language, 'cxx') + def test_project_setup_hook_works(self): + # Bug #11637: ensure the project directory is on sys.path to allow + # project-specific hooks + self.write_setup({'setup-hooks': 'hooks.logging_hook'}) + self.write_file('README', 'yeah') + self.write_file('hooks.py', HOOKS_MODULE) + self.get_dist() + logs = self.get_logs(logging.WARNING) + self.assertEqual(['logging_hook called'], logs) + self.assertIn('hooks', sys.modules) + def test_missing_setup_hook_warns(self): self.write_setup({'setup-hooks': 'this.does._not.exist'}) self.write_file('README', 'yeah') - dist = self.get_dist() + self.get_dist() logs = self.get_logs(logging.WARNING) self.assertEqual(1, len(logs)) self.assertIn('cannot find setup hook', logs[0]) diff --git a/Misc/NEWS b/Misc/NEWS index c05a32ade81..89eab0efe98 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -193,7 +193,10 @@ Core and Builtins Library ------- -- Issue #6771: moved the curses.wrapper function from the single-function +- Issue #11637: Fix support for importing packaging setup hooks from the + project directory. + +- Issue #6771: Moved the curses.wrapper function from the single-function wrapper module into __init__, eliminating the module. Since __init__ was already importing the function to curses.wrapper, there is no API change.