contrib/python3-pyproject2setuppy/pep621.patch

437 lines
11 KiB
Diff

From 5bfaee154cd713252adae4b12e7a6ec83c7ae6c0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= <mgorny@gentoo.org>
Date: Mon, 17 May 2021 19:29:48 +0200
Subject: [PATCH] Add support for PEP 621 metadata in flit
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Closes: https://github.com/mgorny/pyproject2setuppy/issues/16
Signed-off-by: Michał Górny <mgorny@gentoo.org>
---
pyproject2setuppy/flit.py | 83 +++++++----
tests/test_flit_pep621.py | 305 ++++++++++++++++++++++++++++++++++++++
2 files changed, 356 insertions(+), 32 deletions(-)
create mode 100644 tests/test_flit_pep621.py
diff --git a/pyproject2setuppy/flit.py b/pyproject2setuppy/flit.py
index 72418fd..08e0fff 100644
--- a/pyproject2setuppy/flit.py
+++ b/pyproject2setuppy/flit.py
@@ -1,6 +1,6 @@
# pyproject2setup.py -- flit support
# vim:se fileencoding=utf-8 :
-# (c) 2019-2020 Michał Górny
+# (c) 2019-2021 Michał Górny
# 2-clause BSD license
from __future__ import absolute_import
@@ -13,6 +13,7 @@
import sys
from pyproject2setuppy.common import auto_find_packages
+from pyproject2setuppy.pep621 import get_pep621_metadata
def handle_flit(data):
@@ -21,39 +22,57 @@ def handle_flit(data):
system.
"""
- topdata = data['tool']['flit']
- metadata = topdata['metadata']
- modname = metadata['module']
- sys.path.insert(0, '.')
- mod = importlib.import_module(modname, '')
-
- entry_points = defaultdict(list)
- if 'scripts' in topdata:
- for name, content in topdata['scripts'].items():
- entry_points['console_scripts'].append(
- '{} = {}'.format(name, content)
- )
-
- if 'entrypoints' in topdata:
- for group_name, group_content in topdata['entrypoints'].items():
- for name, path in group_content.items():
- entry_points[group_name].append(
- '{} = {}'.format(name, path)
+ # try PEP 621 first
+ setup_metadata = get_pep621_metadata(data, ['version', 'description'])
+ if setup_metadata is not None:
+ if 'flit' in data.get('tool', {}):
+ raise ValueError('[project] and [tool.flit] cannot be present '
+ 'simultaneously')
+ else:
+ # tool.flit fallback
+ topdata = data['tool']['flit']
+ metadata = topdata['metadata']
+
+ entry_points = defaultdict(list)
+ if 'scripts' in topdata:
+ for name, content in topdata['scripts'].items():
+ entry_points['console_scripts'].append(
+ '{} = {}'.format(name, content)
)
- package_args = auto_find_packages(modname)
-
- setup(name=modname,
- version=mod.__version__,
- description=mod.__doc__.strip(),
- author=metadata['author'],
- author_email=metadata['author-email'],
- url=metadata.get('home-page'),
- classifiers=metadata.get('classifiers', []),
- entry_points=dict(entry_points),
- # hack stolen from flit
- package_data={'': ['*']},
- **package_args)
+ if 'entrypoints' in topdata:
+ for group_name, group_content in topdata['entrypoints'].items():
+ for name, path in group_content.items():
+ entry_points[group_name].append(
+ '{} = {}'.format(name, path)
+ )
+
+ setup_metadata = {
+ 'name': metadata['module'],
+ # use None to match PEP 621 return value for dynamic
+ 'version': None,
+ 'description': None,
+ 'author': metadata['author'],
+ 'author_email': metadata['author-email'],
+ 'url': metadata.get('home-page'),
+ 'classifiers': metadata.get('classifiers', []),
+ 'entry_points': dict(entry_points),
+ }
+
+ # handle dynamic metadata if necessary
+ modname = setup_metadata['name']
+ if None in [setup_metadata[x] for x in ('version', 'description')]:
+ sys.path.insert(0, '.')
+ mod = importlib.import_module(modname, '')
+ if setup_metadata['version'] is None:
+ setup_metadata['version'] = mod.__version__
+ if setup_metadata['description'] is None:
+ setup_metadata['description'] = mod.__doc__.strip()
+
+ setup_metadata.update(auto_find_packages(modname))
+
+ setup(package_data={'': ['*']}, # hack stolen from flit
+ **setup_metadata)
def handle_flit_thyself(data):
diff --git a/tests/test_flit_pep621.py b/tests/test_flit_pep621.py
new file mode 100644
index 0000000..ad3852e
--- /dev/null
+++ b/tests/test_flit_pep621.py
@@ -0,0 +1,305 @@
+# vim:se fileencoding=utf-8 :
+# (c) 2019-2021 Michał Górny
+# 2-clause BSD license
+
+import unittest
+
+from pyproject2setuppy.flit import handle_flit, handle_flit_thyself
+
+from tests.base import BuildSystemTestCase
+
+
+class FlitTestCase(BuildSystemTestCase):
+ """
+ Tests for the flit build system.
+ """
+
+ toml_base = '''
+[build-system]
+requires = ["flit"]
+build-backend = "flit.buildapi"
+
+[project]
+name = "test_module"
+authors = [
+ {name="Some Guy", email="guy@example.com"},
+]
+dynamic = ["version", "description"]
+'''
+
+ expected_base = {
+ 'name': 'test_module',
+ 'version': '0',
+ 'description': 'documentation.',
+ 'author': 'Some Guy',
+ 'author_email': 'guy@example.com',
+ 'classifiers': [],
+ 'entry_points': {},
+ 'package_data': {'': ['*']},
+ }
+
+ package_files = ['test_module.py']
+
+ handler = staticmethod(handle_flit)
+
+ def make_package(self):
+ """
+ Make a flit-compatible packags. Adds docstring and version
+ to the first .py file in package_files.
+ """
+
+ d = super(FlitTestCase, self).make_package()
+ with open(self.package_files[0], 'w') as f:
+ f.write('''
+""" documentation. """
+__version__ = '0'
+''')
+ return d
+
+
+class FlitBasicTest(unittest.TestCase, FlitTestCase):
+ """
+ Test handling a simple flit package.
+ """
+
+ expected_extra = {
+ 'py_modules': ['test_module'],
+ }
+
+
+class FlitVersionTest(unittest.TestCase, FlitTestCase):
+ """
+ Test handling a package with non-dynamic version.
+ """
+
+ toml_base = '''
+[build-system]
+requires = ["flit"]
+build-backend = "flit.buildapi"
+
+[project]
+name = "test_module"
+version = "0"
+authors = [
+ {name="Some Guy", email="guy@example.com"},
+]
+dynamic = ["description"]
+'''
+
+ expected_extra = {
+ 'py_modules': ['test_module'],
+ }
+
+
+class FlitDescriptionTest(unittest.TestCase, FlitTestCase):
+ """
+ Test handling a package with non-dynamic description.
+ """
+
+ toml_base = '''
+[build-system]
+requires = ["flit"]
+build-backend = "flit.buildapi"
+
+[project]
+name = "test_module"
+description = "documentation."
+authors = [
+ {name="Some Guy", email="guy@example.com"},
+]
+dynamic = ["version"]
+'''
+
+ expected_extra = {
+ 'py_modules': ['test_module'],
+ }
+
+
+class FlitVersionDescriptionTest(unittest.TestCase, FlitTestCase):
+ """
+ Test handling a package with non-dynamic version and description.
+ """
+
+ toml_base = '''
+[build-system]
+requires = ["flit"]
+build-backend = "flit.buildapi"
+
+[project]
+name = "test_module"
+version = "0"
+description = "documentation."
+authors = [
+ {name="Some Guy", email="guy@example.com"},
+]
+'''
+
+ expected_extra = {
+ 'py_modules': ['test_module'],
+ }
+
+
+class FlitClassifiersTest(unittest.TestCase, FlitTestCase):
+ """
+ Test handling a flit package with trove classifiers.
+ """
+
+ toml_extra = '''
+classifiers = [
+ "License :: OSI Approved :: MIT License",
+ "Programming Language :: Python :: 2",
+ "Programming Language :: Python :: 3"
+]
+'''
+
+ expected_extra = {
+ 'py_modules': ['test_module'],
+ 'classifiers': [
+ "License :: OSI Approved :: MIT License",
+ "Programming Language :: Python :: 2",
+ "Programming Language :: Python :: 3"
+ ],
+ }
+
+
+class FlitPackageTest(unittest.TestCase, FlitTestCase):
+ """
+ Test handling a flit package containing a package instead of module.
+ """
+
+ package_files = ['test_module/__init__.py']
+
+ expected_extra = {
+ 'packages': ['test_module']
+ }
+
+
+class FlitExtraFilesTest(unittest.TestCase, FlitTestCase):
+ """
+ Test handling a flit package with non-python files.
+ """
+
+ package_files = ['test_module/__init__.py',
+ 'test_module/VERSION']
+
+ expected_extra = {
+ 'packages': ['test_module'],
+ }
+ expected_extra_files = [
+ 'test_module/VERSION',
+ ]
+
+
+class FlitNestedPackageTest(unittest.TestCase, FlitTestCase):
+ """
+ Test handling a flit package containing nested packages.
+ """
+
+ package_files = [
+ 'test_module/__init__.py',
+ 'test_module/sub_module/__init__.py',
+ 'test_module/sub_module/subsub/__init__.py',
+ ]
+
+ expected_extra = {
+ 'packages': [
+ 'test_module',
+ 'test_module.sub_module',
+ 'test_module.sub_module.subsub',
+ ]
+ }
+
+
+class FlitCoreTest(FlitTestCase):
+ """Test for using flit_core backend"""
+
+ toml_base = '''
+[build-system]
+requires = ["flit_core"]
+build-backend = "flit_core.buildapi"
+
+[project]
+name = "test_module"
+authors = [
+ {name="Some Guy", email="guy@example.com"},
+]
+dynamic = ["version", "description"]
+'''
+
+
+class FlitScriptsTest(unittest.TestCase, FlitTestCase):
+ """Test handling scripts"""
+
+ toml_extra = '''
+[project.scripts]
+test-tool = "testlib:main"
+'''
+
+ expected_extra = {
+ 'entry_points': {
+ 'console_scripts': [
+ 'test-tool = testlib:main',
+ ]
+ },
+ 'py_modules': ['test_module'],
+ }
+
+
+class FlitGUIScriptsTest(unittest.TestCase, FlitTestCase):
+ """Test handling scripts"""
+
+ toml_extra = '''
+[project.gui-scripts]
+test-tool = "testlib:main"
+'''
+
+ expected_extra = {
+ 'entry_points': {
+ 'gui_scripts': [
+ 'test-tool = testlib:main',
+ ]
+ },
+ 'py_modules': ['test_module'],
+ }
+
+
+class FlitEntryPointsTest(unittest.TestCase, FlitTestCase):
+ """Test handling entry points"""
+
+ toml_extra = '''
+[project.entrypoints."blogtool.parsers"]
+".rst" = "some_module:SomeClass"
+'''
+
+ expected_extra = {
+ 'entry_points': {
+ 'blogtool.parsers': [
+ '.rst = some_module:SomeClass',
+ ]
+ },
+ 'py_modules': ['test_module'],
+ }
+
+
+class FlitPluginsAndScriptsTest(unittest.TestCase, FlitTestCase):
+ """Test handling plugins and scripts"""
+
+ toml_extra = '''
+[project.scripts]
+test-tool = "testlib:main"
+
+[project.entrypoints."blogtool.parsers"]
+".rst" = "some_module:SomeClass"
+'''
+
+ expected_extra = {
+ 'entry_points': {
+ 'console_scripts': [
+ 'test-tool = testlib:main',
+ ],
+ 'blogtool.parsers': [
+ '.rst = some_module:SomeClass',
+ ]
+ },
+ 'py_modules': ['test_module'],
+ }