Minor improvement to extensions in setup.cfg: check parent package

This commit is contained in:
Éric Araujo 2011-09-01 07:01:13 +02:00
parent 336b4e4ff3
commit d9299e97ab
3 changed files with 50 additions and 5 deletions

View File

@ -769,7 +769,9 @@ needs to have its options defined in a dedicated section. Here's an example::
The section name must start with ``extension:``; the right-hand part is used as
the full name (including a parent package, if any) of the extension. Whitespace
around the extension name is allowed.
around the extension name is allowed. If the extension module is not standalone
(e.g. ``_bisect``) but part of a package (e.g. ``thing._speedups``), the parent
package must be listed in the ``packages`` field.
Valid fields and their values are listed in the documentation of the
:class:`packaging.compiler.extension.Extension` class; values documented as
Python lists translate to multi-line values in the configuration file. In

View File

@ -16,6 +16,19 @@ from packaging.command import set_command
from packaging.markers import interpret
def _check_name(name, packages):
if '.' not in name:
return
parts = name.split('.')
modname = parts[-1]
parent = '.'.join(parts[:-1])
if parent not in packages:
# we could log a warning instead of raising, but what's the use
# of letting people build modules they can't import?
raise PackagingOptionError(
'parent package for extension %r not found' % name)
def _pop_values(values_dct, key):
"""Remove values from the dictionary and convert them as a list"""
vals_str = values_dct.pop(key, '')
@ -142,7 +155,8 @@ class Config:
try:
hook = resolve_name(line)
except ImportError as e:
logger.warning('cannot find setup hook: %s', e.args[0])
logger.warning('cannot find setup hook: %s',
e.args[0])
else:
self.setup_hooks.append(hook)
self.run_hooks(content)
@ -259,8 +273,10 @@ class Config:
raise PackagingOptionError(
'extension name should be given as [extension: name], '
'not as key')
name = labels[1].strip()
_check_name(name, self.dist.packages)
ext_modules.append(Extension(
labels[1].strip(),
name,
_pop_values(values_dct, 'sources'),
_pop_values(values_dct, 'include_dirs'),
_pop_values(values_dct, 'define_macros'),

View File

@ -105,6 +105,7 @@ EXT_SETUP_CFG = """
[files]
packages = one
two
parent.undeclared
[extension:one.speed_coconuts]
sources = c_src/speed_coconuts.c
@ -122,6 +123,11 @@ extra_compile_args = -fPIC -O2
-DGECODE_VERSION=$(./gecode_version) -- sys.platform != 'win32'
/DGECODE_VERSION='win32' -- sys.platform == 'win32'
language = cxx
# corner case: if the parent package of an extension is declared but
# not its grandparent, it's legal
[extension: parent.undeclared._speed]
sources = parent/undeclared/_speed.c
"""
EXT_SETUP_CFG_BUGGY_1 = """
@ -129,6 +135,21 @@ EXT_SETUP_CFG_BUGGY_1 = """
name = crash_here
"""
EXT_SETUP_CFG_BUGGY_2 = """
[files]
packages = ham
[extension: spam.eggs]
"""
EXT_SETUP_CFG_BUGGY_3 = """
[files]
packages = ok
ok.works
[extension: ok.works.breaks._ext]
"""
HOOKS_MODULE = """
import logging
@ -314,7 +335,7 @@ class ConfigTestCase(support.TempdirManager,
dist = self.get_dist()
ext_modules = dict((mod.name, mod) for mod in dist.ext_modules)
self.assertEqual(len(ext_modules), 2)
self.assertEqual(len(ext_modules), 3)
ext = ext_modules.get('one.speed_coconuts')
self.assertEqual(ext.sources, ['c_src/speed_coconuts.c'])
self.assertEqual(ext.define_macros, ['HAVE_CAIRO', 'HAVE_GTK2'])
@ -341,6 +362,12 @@ class ConfigTestCase(support.TempdirManager,
self.write_file('setup.cfg', EXT_SETUP_CFG_BUGGY_1)
self.assertRaises(PackagingOptionError, self.get_dist)
self.write_file('setup.cfg', EXT_SETUP_CFG_BUGGY_2)
self.assertRaises(PackagingOptionError, self.get_dist)
self.write_file('setup.cfg', EXT_SETUP_CFG_BUGGY_3)
self.assertRaises(PackagingOptionError, self.get_dist)
def test_project_setup_hook_works(self):
# Bug #11637: ensure the project directory is on sys.path to allow
# project-specific hooks
@ -364,7 +391,7 @@ class ConfigTestCase(support.TempdirManager,
self.write_setup({
'setup-hooks': '\n packaging.tests.test_config.first_hook'
'\n packaging.tests.test_config.missing_hook'
'\n packaging.tests.test_config.third_hook'
'\n packaging.tests.test_config.third_hook',
})
self.write_file('README', 'yeah')
dist = self.get_dist()