return config
+class TestBasics(base.BaseTestCase):
+
+ def test_basics(self):
+ self.maxDiff = None
+ config_text = """
+ [metadata]
+ name = foo
+ version = 1.0
+ author = John Doe
+ author_email = jd@example.com
+ maintainer = Jim Burke
+ maintainer_email = jb@example.com
+ home_page = http://example.com
+ summary = A foobar project.
+ description = Hello, world. This is a long description.
+ download_url = http://opendev.org/x/pbr
+ classifier =
+ Development Status :: 5 - Production/Stable
+ Programming Language :: Python
+ platform =
+ any
+ license = Apache 2.0
+ requires_dist =
+ Sphinx
+ requests
+ setup_requires_dist =
+ docutils
+ python_requires = >=3.6
+ provides_dist =
+ bax
+ provides_extras =
+ bar
+ obsoletes_dist =
+ baz
+
+ [files]
+ packages_root = src
+ packages =
+ foo
+ package_data =
+ "" = *.txt, *.rst
+ foo = *.msg
+ namespace_packages =
+ hello
+ data_files =
+ bitmaps =
+ bm/b1.gif
+ bm/b2.gif
+ config =
+ cfg/data.cfg
+ scripts =
+ scripts/hello-world.py
+ modules =
+ mod1
+ """
+ expected = {
+ 'name': u'foo',
+ 'version': u'1.0',
+ 'author': u'John Doe',
+ 'author_email': u'jd@example.com',
+ 'maintainer': u'Jim Burke',
+ 'maintainer_email': u'jb@example.com',
+ 'url': u'http://example.com',
+ 'description': u'A foobar project.',
+ 'long_description': u'Hello, world. This is a long description.',
+ 'download_url': u'http://opendev.org/x/pbr',
+ 'classifiers': [
+ u'Development Status :: 5 - Production/Stable',
+ u'Programming Language :: Python',
+ ],
+ 'platforms': [u'any'],
+ 'license': u'Apache 2.0',
+ 'install_requires': [
+ u'Sphinx',
+ u'requests',
+ ],
+ 'setup_requires': [u'docutils'],
+ 'python_requires': u'>=3.6',
+ 'provides': [u'bax'],
+ 'provides_extras': [u'bar'],
+ 'obsoletes': [u'baz'],
+ 'extras_require': {},
+
+ 'package_dir': {'': u'src'},
+ 'packages': [u'foo'],
+ 'package_data': {
+ '': ['*.txt,', '*.rst'],
+ 'foo': ['*.msg'],
+ },
+ 'namespace_packages': [u'hello'],
+ 'data_files': [
+ ('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),
+ ('config', ['cfg/data.cfg']),
+ ],
+ 'scripts': [u'scripts/hello-world.py'],
+ 'py_modules': [u'mod1'],
+ }
+ config = config_from_ini(config_text)
+ actual = util.setup_cfg_to_setup_kwargs(config)
+ self.assertDictEqual(expected, actual)
+
+
class TestExtrasRequireParsingScenarios(base.BaseTestCase):
scenarios = [
config = config_from_ini(self.config_text)
kwargs = util.setup_cfg_to_setup_kwargs(config)
- self.assertEqual(self.data_files,
- list(kwargs['data_files']))
+ self.assertEqual(self.data_files, kwargs['data_files'])
class TestUTF8DescriptionFile(base.BaseTestCase):
# Mappings from setup() keyword arguments to setup.cfg options;
# The values are (section, option) tuples, or simply (section,) tuples if
# the option has the same name as the setup() argument
-D1_D2_SETUP_ARGS = {
- "name": ("metadata",),
- "version": ("metadata",),
- "author": ("metadata",),
- "author_email": ("metadata",),
- "maintainer": ("metadata",),
- "maintainer_email": ("metadata",),
- "url": ("metadata", "home_page"),
- "project_urls": ("metadata",),
- "description": ("metadata", "summary"),
- "keywords": ("metadata",),
- "long_description": ("metadata", "description"),
- "long_description_content_type": ("metadata", "description_content_type"),
- "download_url": ("metadata",),
- "classifiers": ("metadata", "classifier"),
- "platforms": ("metadata", "platform"), # **
- "license": ("metadata",),
+CFG_TO_PY_SETUP_ARGS = (
+ (('metadata', 'name'), 'name'),
+ (('metadata', 'version'), 'version'),
+ (('metadata', 'author'), 'author'),
+ (('metadata', 'author_email'), 'author_email'),
+ (('metadata', 'maintainer'), 'maintainer'),
+ (('metadata', 'maintainer_email'), 'maintainer_email'),
+ (('metadata', 'home_page'), 'url'),
+ (('metadata', 'project_urls'), 'project_urls'),
+ (('metadata', 'summary'), 'description'),
+ (('metadata', 'keywords'), 'keywords'),
+ (('metadata', 'description'), 'long_description'),
+ (
+ ('metadata', 'description_content_type'),
+ 'long_description_content_type',
+ ),
+ (('metadata', 'download_url'), 'download_url'),
+ (('metadata', 'classifier'), 'classifiers'),
+ (('metadata', 'platform'), 'platforms'), # **
+ (('metadata', 'license'), 'license'),
# Use setuptools install_requires, not
# broken distutils requires
- "install_requires": ("metadata", "requires_dist"),
- "setup_requires": ("metadata", "setup_requires_dist"),
- "python_requires": ("metadata",),
- "requires_python": ("metadata", "python_requires"),
- "provides": ("metadata", "provides_dist"), # **
- "provides_extras": ("metadata",),
- "obsoletes": ("metadata", "obsoletes_dist"), # **
- "package_dir": ("files", 'packages_root'),
- "packages": ("files",),
- "package_data": ("files",),
- "namespace_packages": ("files",),
- "data_files": ("files",),
- "scripts": ("files",),
- "py_modules": ("files", "modules"), # **
- "cmdclass": ("global", "commands"),
+ (('metadata', 'requires_dist'), 'install_requires'),
+ (('metadata', 'setup_requires_dist'), 'setup_requires'),
+ (('metadata', 'python_requires'), 'python_requires'),
+ (('metadata', 'requires_python'), 'python_requires'),
+ (('metadata', 'provides_dist'), 'provides'), # **
+ (('metadata', 'provides_extras'), 'provides_extras'),
+ (('metadata', 'obsoletes_dist'), 'obsoletes'), # **
+ (('files', 'packages_root'), 'package_dir'),
+ (('files', 'packages'), 'packages'),
+ (('files', 'package_data'), 'package_data'),
+ (('files', 'namespace_packages'), 'namespace_packages'),
+ (('files', 'data_files'), 'data_files'),
+ (('files', 'scripts'), 'scripts'),
+ (('files', 'modules'), 'py_modules'), # **
+ (('global', 'commands'), 'cmdclass'),
# Not supported in distutils2, but provided for
# backwards compatibility with setuptools
- "zip_safe": ("backwards_compat", "zip_safe"),
- "tests_require": ("backwards_compat", "tests_require"),
- "dependency_links": ("backwards_compat",),
- "include_package_data": ("backwards_compat",),
-}
+ (('backwards_compat', 'zip_safe'), 'zip_safe'),
+ (('backwards_compat', 'tests_require'), 'tests_require'),
+ (('backwards_compat', 'dependency_links'), 'dependency_links'),
+ (('backwards_compat', 'include_package_data'), 'include_package_data'),
+)
# setup() arguments that can have multiple values in setup.cfg
MULTI_FIELDS = ("classifiers",
# parse env_markers.
all_requirements = {}
- for arg in D1_D2_SETUP_ARGS:
- if len(D1_D2_SETUP_ARGS[arg]) == 2:
- # The distutils field name is different than distutils2's.
- section, option = D1_D2_SETUP_ARGS[arg]
-
- elif len(D1_D2_SETUP_ARGS[arg]) == 1:
- # The distutils field name is the same thant distutils2's.
- section = D1_D2_SETUP_ARGS[arg][0]
- option = arg
+ for alias, arg in CFG_TO_PY_SETUP_ARGS:
+ section, option = alias
in_cfg_value = has_get_option(config, section, option)
+ if not in_cfg_value and arg == "long_description":
+ in_cfg_value = has_get_option(config, section, "description_file")
+ if in_cfg_value:
+ in_cfg_value = split_multiline(in_cfg_value)
+ value = ''
+ for filename in in_cfg_value:
+ description_file = io.open(filename, encoding='utf-8')
+ try:
+ value += description_file.read().strip() + '\n\n'
+ finally:
+ description_file.close()
+ in_cfg_value = value
+
if not in_cfg_value:
- # There is no such option in the setup.cfg
- if arg == "long_description":
- in_cfg_value = has_get_option(config, section,
- "description_file")
- if in_cfg_value:
- in_cfg_value = split_multiline(in_cfg_value)
- value = ''
- for filename in in_cfg_value:
- description_file = io.open(filename, encoding='utf-8')
- try:
- value += description_file.read().strip() + '\n\n'
- finally:
- description_file.close()
- in_cfg_value = value
- else:
- continue
+ continue
if arg in CSV_FIELDS:
in_cfg_value = split_csv(in_cfg_value)
if arg == 'data_files':
# the data_files value is a pointlessly different structure
# from the package_data value
- data_files = data_files.items()
+ data_files = sorted(data_files.items())
in_cfg_value = data_files
elif arg == 'cmdclass':
cmdclass = {}