Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-flit-core for
openSUSE:Factory checked in at 2021-04-18 21:44:20
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-flit-core (Old)
and /work/SRC/openSUSE:Factory/.python-flit-core.new.12324 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-flit-core"
Sun Apr 18 21:44:20 2021 rev:6 rq:885474 version:3.2.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-flit-core/python-flit-core.changes
2020-10-27 19:01:21.978848945 +0100
+++
/work/SRC/openSUSE:Factory/.python-flit-core.new.12324/python-flit-core.changes
2021-04-18 21:44:28.096656680 +0200
@@ -1,0 +2,12 @@
+Wed Apr 14 19:29:23 UTC 2021 - Matthias Bach <[email protected]>
+
+- Update to version 3.2
+ * Experimental support for specifying metadata in a [project] in
+ pyproject.toml table as specified by PEP-621.
+ * Fix writing METADATA file with multi-line information in
+ certain fields such as Author.
+ * Fix building wheel when a directory such as LICENSES appears
+ in the project root directory.
+ * Switch from the deprecated pytoml package to toml.
+
+-------------------------------------------------------------------
Old:
----
flit_core-3.0.0.tar.gz
New:
----
flit_core-3.2.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-flit-core.spec ++++++
--- /var/tmp/diff_new_pack.FgdRZk/_old 2021-04-18 21:44:28.484657336 +0200
+++ /var/tmp/diff_new_pack.FgdRZk/_new 2021-04-18 21:44:28.488657342 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-flit-core
#
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -16,10 +16,9 @@
#
-%{?!python_module:%define python_module() python3-%{**}}
%define skip_python2 1
Name: python-flit-core
-Version: 3.0.0
+Version: 3.2.0
Release: 0
Summary: Distribution-building parts of Flit
License: BSD-3-Clause
@@ -27,11 +26,11 @@
Source:
https://files.pythonhosted.org/packages/source/f/flit-core/flit_core-%{version}.tar.gz
BuildRequires: %{python_module pip}
BuildRequires: %{python_module pytest}
-BuildRequires: %{python_module pytoml}
BuildRequires: %{python_module testpath}
+BuildRequires: %{python_module toml}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
-Requires: python-pytoml
+Requires: python-toml
BuildArch: noarch
%python_subpackages
++++++ flit_core-3.0.0.tar.gz -> flit_core-3.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/PKG-INFO new/flit_core-3.2.0/PKG-INFO
--- old/flit_core-3.0.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.2.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: flit_core
-Version: 3.0.0
+Version: 3.2.0
Summary: Distribution-building parts of Flit. See flit package for more
information
Home-page: https://github.com/takluyver/flit
Author: Thomas Kluyver & contributors
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/flit_core/__init__.py
new/flit_core-3.2.0/flit_core/__init__.py
--- old/flit_core-3.0.0/flit_core/__init__.py 2020-09-06 12:29:28.066011700
+0200
+++ new/flit_core-3.2.0/flit_core/__init__.py 2021-03-15 23:45:58.347866000
+0100
@@ -4,4 +4,4 @@
All the convenient development features live in the main 'flit' package.
"""
-__version__ = '3.0.0'
+__version__ = '3.2.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/flit_core/build_thyself.py
new/flit_core-3.2.0/flit_core/build_thyself.py
--- old/flit_core-3.0.0/flit_core/build_thyself.py 2020-05-23
20:40:28.575257500 +0200
+++ new/flit_core-3.2.0/flit_core/build_thyself.py 2021-01-23
13:24:58.122672800 +0100
@@ -25,7 +25,7 @@
'summary': ('Distribution-building parts of Flit. '
'See flit package for more information'),
'requires_dist': [
- 'pytoml',
+ 'toml',
],
'requires_python': '>=3.4',
'classifiers': [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/flit_core/buildapi.py
new/flit_core-3.2.0/flit_core/buildapi.py
--- old/flit_core-3.0.0/flit_core/buildapi.py 2020-08-25 19:07:58.613150000
+0200
+++ new/flit_core-3.2.0/flit_core/buildapi.py 2021-03-15 23:45:58.348866200
+0100
@@ -21,12 +21,17 @@
def get_requires_for_build_wheel(config_settings=None):
"""Returns a list of requirements for building, as strings"""
info = read_flit_config(pyproj_toml)
- # If we can get the module info from the AST, we don't need any extra
+ # If we can get version & description from pyproject.toml (PEP 621), or
+ # by parsing the module (_via_ast), we don't need any extra
# dependencies. If not, we'll need to try importing it, so report any
# runtime dependencies as build dependencies.
+ want_summary = 'description' in info.dynamic_metadata
+ want_version = 'version' in info.dynamic_metadata
+
module = Module(info.module, Path.cwd())
docstring, version = get_docstring_and_version_via_ast(module)
- if (docstring is None) or (version is None):
+
+ if (want_summary and not docstring) or (want_version and not version):
return info.metadata.get('requires_dist', [])
else:
return []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/flit_core/common.py
new/flit_core-3.2.0/flit_core/common.py
--- old/flit_core-3.0.0/flit_core/common.py 2020-07-14 22:41:21.759879400
+0200
+++ new/flit_core-3.2.0/flit_core/common.py 2021-03-21 13:02:58.410992100
+0100
@@ -143,15 +143,24 @@
return ast.get_docstring(node), version
+# To ensure we're actually loading the specified file, give it a unique name to
+# avoid any cached import. In normal use we'll only load one module per
process,
+# so it should only matter for the tests, but we'll do it anyway.
+_import_i = 0
+
+
def get_docstring_and_version_via_import(target):
"""
Return a tuple like (docstring, version) for the given module,
extracted by importing the module and pulling __doc__ & __version__
from it.
"""
+ global _import_i
+ _import_i += 1
+
log.debug("Loading module %s", target.file)
from importlib.machinery import SourceFileLoader
- sl = SourceFileLoader(target.name, str(target.file))
+ sl = SourceFileLoader('flit_core.dummy.import%d' % _import_i,
str(target.file))
with _module_load_ctx():
m = sl.load_module()
docstring = m.__dict__.get('__doc__', None)
@@ -159,9 +168,16 @@
return docstring, version
-def get_info_from_module(target):
+def get_info_from_module(target, for_fields=('version', 'description')):
"""Load the module/package, get its docstring and __version__
"""
+ if not for_fields:
+ return {}
+
+ # What core metadata calls Summary, PEP 621 calls description
+ want_summary = 'description' in for_fields
+ want_version = 'version' in for_fields
+
log.debug("Loading module %s", target.file)
# Attempt to extract our docstring & version by parsing our target's
@@ -169,19 +185,23 @@
# build without necessarily requiring that our built package's
# requirements are installed.
docstring, version = get_docstring_and_version_via_ast(target)
- if not (docstring and version):
+ if (want_summary and not docstring) or (want_version and not version):
docstring, version = get_docstring_and_version_via_import(target)
- if (not docstring) or not docstring.strip():
- raise NoDocstringError('Flit cannot package module without docstring, '
- 'or empty docstring. Please add a docstring to your module '
- '({}).'.format(target.file))
-
- version = check_version(version)
-
- docstring_lines = docstring.lstrip().splitlines()
- return {'summary': docstring_lines[0],
- 'version': version}
+ res = {}
+
+ if want_summary:
+ if (not docstring) or not docstring.strip():
+ raise NoDocstringError(
+ 'Flit cannot package module without docstring, or empty
docstring. '
+ 'Please add a docstring to your module
({}).'.format(target.file)
+ )
+ res['summary'] = docstring.lstrip().splitlines()[0]
+
+ if want_version:
+ res['version'] = check_version(version)
+
+ return res
def check_version(version):
"""
@@ -269,6 +289,7 @@
class Metadata(object):
+ summary = None
home_page = None
author = None
author_email = None
@@ -297,9 +318,9 @@
metadata_version = "2.1"
def __init__(self, data):
+ data = data.copy()
self.name = data.pop('name')
self.version = data.pop('version')
- self.summary = data.pop('summary')
for k, v in data.items():
assert hasattr(self, k), "data does not have attribute
'{}'".format(k)
@@ -314,11 +335,11 @@
'Metadata-Version',
'Name',
'Version',
+ ]
+ optional_fields = [
'Summary',
'Home-page',
'License',
- ]
- optional_fields = [
'Keywords',
'Author',
'Author-email',
@@ -330,11 +351,16 @@
for field in fields:
value = getattr(self, self._normalise_name(field))
- fp.write(u"{}: {}\n".format(field, value or 'UNKNOWN'))
+ fp.write(u"{}: {}\n".format(field, value))
for field in optional_fields:
value = getattr(self, self._normalise_name(field))
if value is not None:
+ # TODO: verify which fields can be multiline
+ # The spec has multiline examples for Author, Maintainer &
+ # License (& Description, but we put that in the body)
+ # Indent following lines with 8 spaces:
+ value = '\n '.join(value.splitlines())
fp.write(u"{}: {}\n".format(field, value))
for clsfr in self.classifiers:
@@ -363,20 +389,26 @@
def make_metadata(module, ini_info):
md_dict = {'name': module.name, 'provides': [module.name]}
- md_dict.update(get_info_from_module(module))
+ md_dict.update(get_info_from_module(module, ini_info.dynamic_metadata))
md_dict.update(ini_info.metadata)
return Metadata(md_dict)
-def metadata_and_module_from_ini_path(ini_path):
- from .config import read_flit_config
- ini_path = str(ini_path)
- ini_info = read_flit_config(ini_path)
- module = Module(ini_info.module, osp.dirname(ini_path))
- metadata = make_metadata(module, ini_info)
- return metadata,module
+
+
+def normalize_dist_name(name: str, version: str) -> str:
+ """Normalizes a name and a PEP 440 version
+
+ The resulting string is valid as dist-info folder name
+ and as first part of a wheel filename
+
+ See
https://packaging.python.org/specifications/binary-distribution-format/#escaping-and-unicode
+ """
+ normalized_name = re.sub(r'[-_.]+', '_', name, flags=re.UNICODE)
+ assert check_version(version) == version
+ assert '-' not in version, 'Normalized versions can???t have dashes'
+ return '{}-{}'.format(normalized_name, version)
+
def dist_info_name(distribution, version):
"""Get the correct name of the .dist-info folder"""
- escaped_name = re.sub(r"[^\w\d.]+", "_", distribution, flags=re.UNICODE)
- escaped_version = re.sub(r"[^\w\d.]+", "_", version, flags=re.UNICODE)
- return u'{}-{}.dist-info'.format(escaped_name, escaped_version)
+ return normalize_dist_name(distribution, version) + '.dist-info'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/flit_core/config.py
new/flit_core-3.2.0/flit_core/config.py
--- old/flit_core-3.0.0/flit_core/config.py 2020-05-23 20:40:28.576257700
+0200
+++ new/flit_core-3.2.0/flit_core/config.py 2021-03-21 22:16:35.799428000
+0100
@@ -1,11 +1,15 @@
import difflib
+from email.headerregistry import Address
import errno
import logging
import os
import os.path as osp
-import pytoml as toml
+from pathlib import Path
+import toml
import re
+from .versionno import normalise_version
+
log = logging.getLogger(__name__)
@@ -38,6 +42,26 @@
'author',
}
+pep621_allowed_fields = {
+ 'name',
+ 'version',
+ 'description',
+ 'readme',
+ 'requires-python',
+ 'license',
+ 'authors',
+ 'maintainers',
+ 'keywords',
+ 'classifiers',
+ 'urls',
+ 'scripts',
+ 'gui-scripts',
+ 'entry-points',
+ 'dependencies',
+ 'optional-dependencies',
+ 'dynamic',
+}
+
def read_flit_config(path):
"""Read and check the `pyproject.toml` file with data about the package.
@@ -57,39 +81,66 @@
Returns a LoadedConfig object.
"""
- if ('tool' not in d) or ('flit' not in d['tool']) \
- or (not isinstance(d['tool']['flit'], dict)):
- raise ConfigError("TOML file missing [tool.flit] table.")
+ dtool = d.get('tool', {}).get('flit', {})
- d = d['tool']['flit']
- unknown_sections = set(d) - {'metadata', 'scripts', 'entrypoints', 'sdist'}
- unknown_sections = [s for s in unknown_sections if not
s.lower().startswith('x-')]
- if unknown_sections:
- raise ConfigError('Unknown sections: ' + ', '.join(unknown_sections))
+ if 'project' in d:
+ # Metadata in [project] table (PEP 621)
+ if 'metadata' in dtool:
+ raise ConfigError(
+ "Use [project] table for metadata or [tool.flit.metadata], not
both."
+ )
+ if ('scripts' in dtool) or ('entrypoints' in dtool):
+ raise ConfigError(
+ "Don't mix [project] metadata with [tool.flit.scripts] or "
+ "[tool.flit.entrypoints]. Use [project.scripts],"
+ "[project.gui-scripts] or [project.entry-points] as
replacements."
+ )
+ loaded_cfg = read_pep621_metadata(d['project'], path)
- if 'metadata' not in d:
- raise ConfigError('[tool.flit.metadata] section is required')
+ module_tbl = dtool.get('module', {})
+ if 'name' in module_tbl:
+ loaded_cfg.module = module_tbl['name']
+ elif 'metadata' in dtool:
+ # Metadata in [tool.flit.metadata] (pre PEP 621 format)
+ if 'module' in dtool:
+ raise ConfigError(
+ "Use [tool.flit.module] table with new-style [project]
metadata, "
+ "not [tool.flit.metadata]"
+ )
+ loaded_cfg = _prep_metadata(dtool['metadata'], path)
+ loaded_cfg.dynamic_metadata = ['version', 'description']
- loaded_cfg = _prep_metadata(d['metadata'], path)
+ if 'entrypoints' in dtool:
+ loaded_cfg.entrypoints = flatten_entrypoints(dtool['entrypoints'])
- if 'entrypoints' in d:
- loaded_cfg.entrypoints = flatten_entrypoints(d['entrypoints'])
+ if 'scripts' in dtool:
+ loaded_cfg.add_scripts(dict(dtool['scripts']))
+ else:
+ raise ConfigError(
+ "Neither [project] nor [tool.flit.metadata] found in
pyproject.toml"
+ )
- if 'scripts' in d:
- loaded_cfg.add_scripts(dict(d['scripts']))
+ unknown_sections = set(dtool) - {
+ 'metadata', 'module', 'scripts', 'entrypoints', 'sdist'
+ }
+ unknown_sections = [s for s in unknown_sections if not
s.lower().startswith('x-')]
+ if unknown_sections:
+ raise ConfigError('Unexpected tables in pyproject.toml: ' + ', '.join(
+ '[tool.flit.{}]'.format(s) for s in unknown_sections
+ ))
- if 'sdist' in d:
- unknown_keys = set(d['sdist']) - {'include', 'exclude'}
+ if 'sdist' in dtool:
+ unknown_keys = set(dtool['sdist']) - {'include', 'exclude'}
if unknown_keys:
raise ConfigError(
"Unknown keys in [tool.flit.sdist]:" + ", ".join(unknown_keys)
)
loaded_cfg.sdist_include_patterns = _check_glob_patterns(
- d['sdist'].get('include', []), 'include'
+ dtool['sdist'].get('include', []), 'include'
)
loaded_cfg.sdist_exclude_patterns = _check_glob_patterns(
- d['sdist'].get('exclude', []), 'exclude'
+ dtool['sdist'].get('exclude', []), 'exclude'
)
return loaded_cfg
@@ -176,6 +227,7 @@
self.referenced_files = []
self.sdist_include_patterns = []
self.sdist_exclude_patterns = []
+ self.dynamic_metadata = []
def add_scripts(self, scripts_dict):
if scripts_dict:
@@ -191,6 +243,36 @@
}
+def description_from_file(rel_path: str, proj_dir: Path, guess_mimetype=True):
+ if osp.isabs(rel_path):
+ raise ConfigError("Readme path must be relative")
+
+ desc_path = proj_dir / rel_path
+ try:
+ with desc_path.open('r', encoding='utf-8') as f:
+ raw_desc = f.read()
+ except IOError as e:
+ if e.errno == errno.ENOENT:
+ raise ConfigError(
+ "Description file {} does not exist".format(desc_path)
+ )
+ raise
+
+ if guess_mimetype:
+ ext = desc_path.suffix.lower()
+ try:
+ mimetype = readme_ext_to_content_type[ext]
+ except KeyError:
+ log.warning("Unknown extension %r for description file.", ext)
+ log.warning(" Recognised extensions: %s",
+ " ".join(readme_ext_to_content_type))
+ mimetype = None
+ else:
+ mimetype = None
+
+ return raw_desc, mimetype
+
+
def _prep_metadata(md_sect, path):
"""Process & verify the metadata from a config file
@@ -215,26 +297,8 @@
if 'description-file' in md_sect:
desc_path = md_sect.get('description-file')
res.referenced_files.append(desc_path)
- description_file = path.parent / desc_path
- try:
- with description_file.open('r', encoding='utf-8') as f:
- raw_desc = f.read()
- except IOError as e:
- if e.errno == errno.ENOENT:
- raise ConfigError(
- "Description file {} does not
exist".format(description_file)
- )
- raise
- ext = description_file.suffix
- try:
- mimetype = readme_ext_to_content_type[ext]
- except KeyError:
- log.warning("Unknown extension %r for description file.", ext)
- log.warning(" Recognised extensions: %s",
- " ".join(readme_ext_to_content_type))
- mimetype = None
-
- md_dict['description'] = raw_desc
+ desc_content, mimetype = description_from_file(desc_path, path.parent)
+ md_dict['description'] = desc_content
md_dict['description_content_type'] = mimetype
if 'urls' in md_sect:
@@ -318,3 +382,249 @@
yield '{} ; extra == "{}" and ({})'.format(name, extra,
envmark)
else:
yield '{} ; extra == "{}"'.format(req, extra)
+
+
+def _check_type(d, field_name, cls):
+ if not isinstance(d[field_name], cls):
+ raise ConfigError(
+ "{} field should be {}, not {}".format(field_name, cls,
type(d[field_name]))
+ )
+
+def _check_list_of_str(d, field_name):
+ if not isinstance(d[field_name], list) or not all(
+ isinstance(e, str) for e in d[field_name]
+ ):
+ raise ConfigError(
+ "{} field should be a list of strings".format(field_name)
+ )
+
+def read_pep621_metadata(proj, path) -> LoadedConfig:
+ lc = LoadedConfig()
+ md_dict = lc.metadata
+
+ if 'name' not in proj:
+ raise ConfigError('name must be specified in [project] table')
+ _check_type(proj, 'name', str)
+ lc.module = md_dict['name'] = proj['name']
+
+ unexpected_keys = proj.keys() - pep621_allowed_fields
+ if unexpected_keys:
+ log.warning("Unexpected names under [project]: %s", ',
'.join(unexpected_keys))
+
+ if 'version' in proj:
+ _check_type(proj, 'version', str)
+ md_dict['version'] = normalise_version(proj['version'])
+ if 'description' in proj:
+ _check_type(proj, 'description', str)
+ md_dict['summary'] = proj['description']
+ if 'readme' in proj:
+ readme = proj['readme']
+ if isinstance(readme, str):
+ lc.referenced_files.append(readme)
+ desc_content, mimetype = description_from_file(readme, path.parent)
+
+ elif isinstance(readme, dict):
+ unrec_keys = set(readme.keys()) - {'text', 'file', 'content-type'}
+ if unrec_keys:
+ raise ConfigError(
+ "Unrecognised keys in [project.readme]:
{}".format(unrec_keys)
+ )
+ if 'content-type' in readme:
+ mimetype = readme['content-type']
+ mtype_base = mimetype.split(';')[0].strip() # e.g. text/x-rst
+ if mtype_base not in readme_ext_to_content_type.values():
+ raise ConfigError(
+ "Unrecognised readme content-type:
{!r}".format(mtype_base)
+ )
+ # TODO: validate content-type parameters (charset, md variant)?
+ else:
+ raise ConfigError(
+ "content-type field required in [project.readme] table"
+ )
+ if 'file' in readme:
+ if 'text' in readme:
+ raise ConfigError(
+ "[project.readme] should specify file or text, not
both"
+ )
+ lc.referenced_files.append(readme['file'])
+ desc_content, _ = description_from_file(
+ readme['file'], path.parent, guess_mimetype=False
+ )
+ elif 'text' in readme:
+ desc_content = readme['text']
+ else:
+ raise ConfigError(
+ "file or text field required in [project.readme] table"
+ )
+ else:
+ raise ConfigError(
+ "project.readme should be a string or a table"
+ )
+
+ md_dict['description'] = desc_content
+ md_dict['description_content_type'] = mimetype
+
+ if 'requires-python' in proj:
+ md_dict['requires_python'] = proj['requires-python']
+
+ if 'license' in proj:
+ _check_type(proj, 'license', dict)
+ license_tbl = proj['license']
+ unrec_keys = set(license_tbl.keys()) - {'text', 'file'}
+ if unrec_keys:
+ raise ConfigError(
+ "Unrecognised keys in [project.license]: {}".format(unrec_keys)
+ )
+
+ # TODO: Do something with license info.
+ # The 'License' field in packaging metadata is a brief description of
+ # a license, not the full text or a file path. PEP 639 will improve on
+ # how licenses are recorded.
+ if 'file' in license_tbl:
+ if 'text' in license_tbl:
+ raise ConfigError(
+ "[project.license] should specify file or text, not both"
+ )
+ lc.referenced_files.append(license_tbl['file'])
+ elif 'text' in license_tbl:
+ pass
+ else:
+ raise ConfigError(
+ "file or text field required in [project.license] table"
+ )
+
+ if 'authors' in proj:
+ _check_type(proj, 'authors', list)
+ md_dict.update(pep621_people(proj['authors']))
+
+ if 'maintainers' in proj:
+ _check_type(proj, 'maintainers', list)
+ md_dict.update(pep621_people(proj['maintainers'],
group_name='maintainer'))
+
+ if 'keywords' in proj:
+ _check_list_of_str(proj, 'keywords')
+ md_dict['keywords'] = ",".join(proj['keywords'])
+
+ if 'classifiers' in proj:
+ _check_list_of_str(proj, 'classifiers')
+ md_dict['classifiers'] = proj['classifiers']
+
+ if 'urls' in proj:
+ _check_type(proj, 'urls', dict)
+ project_urls = md_dict['project_urls'] = []
+ for label, url in sorted(proj['urls'].items()):
+ project_urls.append("{}, {}".format(label, url))
+
+ if 'entry-points' in proj:
+ _check_type(proj, 'entry-points', dict)
+ for grp in proj['entry-points'].values():
+ if not isinstance(grp, dict):
+ raise ConfigError(
+ "projects.entry-points should only contain sub-tables"
+ )
+ if not all(isinstance(k, str) for k in grp.values()):
+ raise ConfigError(
+ "[projects.entry-points.*] tables should have string
values"
+ )
+ if set(proj['entry-points'].keys()) & {'console_scripts',
'gui_scripts'}:
+ raise ConfigError(
+ "Scripts should be specified in [project.scripts] or "
+ "[project.gui-scripts], not under [project.entry-points]"
+ )
+ lc.entrypoints = proj['entry-points']
+
+ if 'scripts' in proj:
+ _check_type(proj, 'scripts', dict)
+ if not all(isinstance(k, str) for k in proj['scripts'].values()):
+ raise ConfigError(
+ "[projects.scripts] table should have string values"
+ )
+ lc.entrypoints['console_scripts'] = proj['scripts']
+
+ if 'gui-scripts' in proj:
+ _check_type(proj, 'gui-scripts', dict)
+ if not all(isinstance(k, str) for k in proj['gui-scripts'].values()):
+ raise ConfigError(
+ "[projects.gui-scripts] table should have string values"
+ )
+ lc.entrypoints['gui_scripts'] = proj['gui-scripts']
+
+ if 'dependencies' in proj:
+ _check_list_of_str(proj, 'dependencies')
+ md_dict['requires_dist'] = proj['dependencies']
+
+ if 'optional-dependencies' in proj:
+ _check_type(proj, 'optional-dependencies', dict)
+ optdeps = proj['optional-dependencies']
+ if not all(isinstance(e, list) for e in optdeps.values()):
+ raise ConfigError(
+ 'Expected a dict of lists in optional-dependencies field'
+ )
+ for e, reqs in optdeps.items():
+ if not all(isinstance(a, str) for a in reqs):
+ raise ConfigError(
+ 'Expected a string list for optional-dependencies
({})'.format(e)
+ )
+
+ reqs_noextra = md_dict.pop('requires_dist', [])
+ lc.reqs_by_extra = optdeps.copy()
+
+ # Add optional-dependencies into requires_dist
+ md_dict['requires_dist'] = \
+ reqs_noextra + list(_expand_requires_extra(lc.reqs_by_extra))
+
+ md_dict['provides_extra'] = sorted(lc.reqs_by_extra.keys())
+
+ # For internal use, record the main requirements as a '.none' extra.
+ lc.reqs_by_extra['.none'] = reqs_noextra
+
+ if 'dynamic' in proj:
+ _check_list_of_str(proj, 'dynamic')
+ dynamic = set(proj['dynamic'])
+ unrec_dynamic = dynamic - {'version', 'description'}
+ if unrec_dynamic:
+ raise ConfigError(
+ "flit only supports dynamic metadata for 'version' &
'description'"
+ )
+ if dynamic.intersection(proj):
+ raise ConfigError(
+ "keys listed in project.dynamic must not be in [project] table"
+ )
+ lc.dynamic_metadata = dynamic
+
+ if ('version' not in proj) and ('version' not in lc.dynamic_metadata):
+ raise ConfigError(
+ "version must be specified under [project] or listed as a dynamic
field"
+ )
+ if ('description' not in proj) and ('description' not in
lc.dynamic_metadata):
+ raise ConfigError(
+ "description must be specified under [project] or listed as a
dynamic field"
+ )
+
+ return lc
+
+def pep621_people(people, group_name='author') -> dict:
+ """Convert authors/maintainers from PEP 621 to core metadata fields"""
+ names, emails = [], []
+ for person in people:
+ if not isinstance(person, dict):
+ raise ConfigError("{} info must be list of
dicts".format(group_name))
+ unrec_keys = set(person.keys()) - {'name', 'email'}
+ if unrec_keys:
+ raise ConfigError(
+ "Unrecognised keys in {} info: {}".format(group_name,
unrec_keys)
+ )
+ if 'email' in person:
+ email = person['email']
+ if 'name' in person:
+ email = str(Address(person['name'], addr_spec=email))
+ emails.append(email)
+ elif 'name' in person:
+ names.append(person['name'])
+
+ res = {}
+ if names:
+ res[group_name] = ", ".join(names)
+ if emails:
+ res[group_name + '_email'] = ", ".join(emails)
+ return res
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/flit_core/sdist.py
new/flit_core-3.2.0/flit_core/sdist.py
--- old/flit_core-3.0.0/flit_core/sdist.py 2020-05-23 20:40:28.576257700
+0200
+++ new/flit_core-3.2.0/flit_core/sdist.py 2021-01-23 13:24:58.122672800
+0100
@@ -95,7 +95,7 @@
@classmethod
def from_ini_path(cls, ini_path: Path):
- # Local import so bootstrapping doesn't try to load pytoml
+ # Local import so bootstrapping doesn't try to load toml
from .config import read_flit_config
ini_info = read_flit_config(ini_path)
srcdir = ini_path.parent
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/inclusion/LICENSES/README
new/flit_core-3.2.0/flit_core/tests/samples/inclusion/LICENSES/README
--- old/flit_core-3.0.0/flit_core/tests/samples/inclusion/LICENSES/README
1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.2.0/flit_core/tests/samples/inclusion/LICENSES/README
2021-03-21 11:25:46.340291500 +0100
@@ -0,0 +1,2 @@
+This directory will match the LICENSE* glob which Flit uses to add license
+files to wheel metadata.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/pep517/pyproject.toml
new/flit_core-3.2.0/flit_core/tests/samples/pep517/pyproject.toml
--- old/flit_core-3.0.0/flit_core/tests/samples/pep517/pyproject.toml
2020-01-26 23:11:13.888440000 +0100
+++ new/flit_core-3.2.0/flit_core/tests/samples/pep517/pyproject.toml
2021-03-15 23:45:58.351866200 +0100
@@ -1,6 +1,6 @@
[build-system]
-requires = ["flit"]
-build-backend = "flit.buildapi"
+requires = ["flit_core >=2,<4"]
+build-backend = "flit_core.buildapi"
[tool.flit.metadata]
module = "module1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/pep621/LICENSE
new/flit_core-3.2.0/flit_core/tests/samples/pep621/LICENSE
--- old/flit_core-3.0.0/flit_core/tests/samples/pep621/LICENSE 1970-01-01
01:00:00.000000000 +0100
+++ new/flit_core-3.2.0/flit_core/tests/samples/pep621/LICENSE 2021-03-15
23:45:58.352866200 +0100
@@ -0,0 +1 @@
+This file should be added to wheels
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/pep621/README.rst
new/flit_core-3.2.0/flit_core/tests/samples/pep621/README.rst
--- old/flit_core-3.0.0/flit_core/tests/samples/pep621/README.rst
1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.2.0/flit_core/tests/samples/pep621/README.rst
2021-03-15 23:45:58.352866200 +0100
@@ -0,0 +1 @@
+This contains a n??n-ascii character
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/pep621/module1a.py
new/flit_core-3.2.0/flit_core/tests/samples/pep621/module1a.py
--- old/flit_core-3.0.0/flit_core/tests/samples/pep621/module1a.py
1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.2.0/flit_core/tests/samples/pep621/module1a.py
2021-03-15 23:45:58.352866200 +0100
@@ -0,0 +1,3 @@
+"""Example module"""
+
+__version__ = '0.1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/pep621/pyproject.toml
new/flit_core-3.2.0/flit_core/tests/samples/pep621/pyproject.toml
--- old/flit_core-3.0.0/flit_core/tests/samples/pep621/pyproject.toml
1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.2.0/flit_core/tests/samples/pep621/pyproject.toml
2021-03-15 23:45:58.353866000 +0100
@@ -0,0 +1,39 @@
+[build-system]
+requires = ["flit_core >=3.2,<4"]
+build-backend = "flit_core.buildapi"
+
+[project]
+name = "module1"
+authors = [
+ {name = "Sir R??bin", email = "[email protected]"}
+]
+maintainers = [
+ {name = "Sir Galahad"}
+]
+readme = "README.rst"
+license = {file = "LICENSE"}
+requires-python = ">=3.7"
+dependencies = [
+ "requests >= 2.18",
+ "docutils",
+]
+keywords = ["example", "test"]
+dynamic = [
+ "version",
+ "description",
+]
+
+[project.optional-dependencies]
+test = [
+ "pytest",
+ "mock; python_version<'3.6'"
+]
+
+[project.urls]
+homepage = "http://github.com/sirrobin/module1"
+
+[project.entry-points.flit_test_example]
+foo = "module1:main"
+
+[tool.flit.module]
+name = "module1a"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/.gitignore
new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/.gitignore
---
old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/.gitignore
1970-01-01 01:00:00.000000000 +0100
+++
new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/.gitignore
2021-02-27 14:14:47.680864800 +0100
@@ -0,0 +1,2 @@
+# Created by pytest automatically.
+*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/CACHEDIR.TAG
new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/CACHEDIR.TAG
---
old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/CACHEDIR.TAG
1970-01-01 01:00:00.000000000 +0100
+++
new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/CACHEDIR.TAG
2021-02-27 14:14:47.680864800 +0100
@@ -0,0 +1,4 @@
+Signature: 8a477f597d28d172789f06886806bc55
+# This file is a cache directory tag created by pytest.
+# For information about cache directory tags, see:
+# http://www.bford.info/cachedir/spec.html
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/README.md
new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/README.md
---
old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/README.md
1970-01-01 01:00:00.000000000 +0100
+++
new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/README.md
2021-02-27 14:14:47.680864800 +0100
@@ -0,0 +1,8 @@
+# pytest cache directory #
+
+This directory contains data from the pytest's cache plugin,
+which provides the `--lf` and `--ff` options, as well as the `cache` fixture.
+
+**Do not** commit this to version control.
+
+See [the docs](https://docs.pytest.org/en/stable/cache.html) for more
information.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/v/cache/nodeids
new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/v/cache/nodeids
---
old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/v/cache/nodeids
1970-01-01 01:00:00.000000000 +0100
+++
new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/v/cache/nodeids
2021-02-27 14:14:52.008859600 +0100
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/v/cache/stepwise
new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/v/cache/stepwise
---
old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/v/cache/stepwise
1970-01-01 01:00:00.000000000 +0100
+++
new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/.pytest_cache/v/cache/stepwise
2021-02-27 14:14:52.007859700 +0100
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/README.rst
new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/README.rst
--- old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/README.rst
1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/README.rst
2021-03-15 23:45:58.354866300 +0100
@@ -0,0 +1 @@
+This contains a n??n-ascii character
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/pyproject.toml
new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/pyproject.toml
--- old/flit_core-3.0.0/flit_core/tests/samples/pep621_nodynamic/pyproject.toml
1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.2.0/flit_core/tests/samples/pep621_nodynamic/pyproject.toml
2021-03-15 23:45:58.354866300 +0100
@@ -0,0 +1,28 @@
+[build-system]
+requires = ["flit_core >=3.2,<4"]
+build-backend = "flit_core.buildapi"
+
+[project]
+name = "module1"
+version = "0.03"
+description = "Statically specified description"
+authors = [
+ {name = "Sir Robin", email = "[email protected]"}
+]
+readme = {file = "README.rst", content-type = "text/x-rst"}
+classifiers = [
+ "Topic :: Internet :: WWW/HTTP",
+]
+dependencies = [
+ "requests >= 2.18",
+ "docutils",
+]
+
+[project.urls]
+homepage = "http://github.com/sirrobin/module1"
+
+[project.scripts]
+foo = "module1:main"
+
+[project.gui-scripts]
+foo-gui = "module1:main"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/flit_core/tests/test_buildapi.py
new/flit_core-3.2.0/flit_core/tests/test_buildapi.py
--- old/flit_core-3.0.0/flit_core/tests/test_buildapi.py 2020-08-25
19:07:58.614150000 +0200
+++ new/flit_core-3.2.0/flit_core/tests/test_buildapi.py 2021-03-15
23:45:58.355866200 +0100
@@ -26,6 +26,13 @@
assert buildapi.get_requires_for_build_wheel() == []
assert buildapi.get_requires_for_build_sdist() == []
+def test_get_build_requires_pep621_nodynamic():
+ # This module isn't inspected because version & description are specified
+ # as static metadata in pyproject.toml, so there are no build dependencies
+ with cwd(osp.join(samples_dir, 'pep621_nodynamic')):
+ assert buildapi.get_requires_for_build_wheel() == []
+ assert buildapi.get_requires_for_build_sdist() == []
+
def test_get_build_requires_import():
# This one has to be imported, so its runtime dependencies are also
# build dependencies.
@@ -39,6 +46,13 @@
filename = buildapi.build_wheel(td)
assert filename.endswith('.whl'), filename
assert_isfile(osp.join(td, filename))
+ assert zipfile.is_zipfile(osp.join(td, filename))
+
+def test_build_wheel_pep621():
+ with TemporaryDirectory() as td, cwd(osp.join(samples_dir, 'pep621')):
+ filename = buildapi.build_wheel(td)
+ assert filename.endswith('.whl'), filename
+ assert_isfile(osp.join(td, filename))
assert zipfile.is_zipfile(osp.join(td, filename))
def test_build_sdist():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/flit_core/tests/test_common.py
new/flit_core-3.2.0/flit_core/tests/test_common.py
--- old/flit_core-3.0.0/flit_core/tests/test_common.py 2020-08-25
19:07:58.614150000 +0200
+++ new/flit_core-3.2.0/flit_core/tests/test_common.py 2021-03-21
13:02:58.410992100 +0100
@@ -1,10 +1,14 @@
+import email.parser
+import email.policy
+from io import StringIO
from pathlib import Path
import pytest
from unittest import TestCase
+from flit_core import config
from flit_core.common import (
Module, get_info_from_module, InvalidVersion, NoVersionError,
check_version,
- normalize_file_permissions, Metadata
+ normalize_file_permissions, Metadata, make_metadata,
)
samples_dir = Path(__file__).parent / 'samples'
@@ -40,10 +44,17 @@
'version': '7.0'}
)
- info = get_info_from_module(Module('package1', samples_dir))
+ pkg1 = Module('package1', samples_dir)
+ info = get_info_from_module(pkg1)
self.assertEqual(info, {'summary': 'A sample package',
'version': '0.1'}
)
+ info = get_info_from_module(pkg1, for_fields=['version'])
+ self.assertEqual(info, {'version': '0.1'})
+ info = get_info_from_module(pkg1, for_fields=['description'])
+ self.assertEqual(info, {'summary': 'A sample package'})
+ info = get_info_from_module(pkg1, for_fields=[])
+ self.assertEqual(info, {})
info = get_info_from_module(Module('moduleunimportable', samples_dir))
self.assertEqual(info, {'summary': 'A sample unimportable module',
@@ -95,3 +106,31 @@
metadata.requires_python = requires_python
result = metadata.supports_py2
assert result == expected_result
+
+def test_make_metadata():
+ project_dir = samples_dir / 'pep621_nodynamic'
+ ini_info = config.read_flit_config(project_dir / 'pyproject.toml')
+ module = Module(ini_info.module, project_dir)
+ print(module.file)
+ md = make_metadata(module, ini_info)
+ assert md.version == '0.3'
+ assert md.summary == "Statically specified description"
+
+def test_metadata_multiline(tmp_path):
+ d = {
+ 'name': 'foo',
+ 'version': '1.0',
+ # Example from:
https://packaging.python.org/specifications/core-metadata/#author
+ 'author': ('C. Schultz, Universal Features Syndicate\n'
+ 'Los Angeles, CA <[email protected]>'),
+ }
+ md = Metadata(d)
+ sio = StringIO()
+ md.write_metadata_file(sio)
+ sio.seek(0)
+
+ msg = email.parser.Parser(policy=email.policy.compat32).parse(sio)
+ assert msg['Name'] == d['name']
+ assert msg['Version'] == d['version']
+ assert [l.lstrip() for l in msg['Author'].splitlines()] ==
d['author'].splitlines()
+ assert not msg.defects
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/flit_core/tests/test_config.py
new/flit_core-3.2.0/flit_core/tests/test_config.py
--- old/flit_core-3.0.0/flit_core/tests/test_config.py 2020-05-23
20:40:28.577257600 +0200
+++ new/flit_core-3.2.0/flit_core/tests/test_config.py 2021-03-21
22:14:40.833671800 +0100
@@ -15,6 +15,30 @@
assert inf.module == 'module1'
assert inf.metadata['home_page'] == 'http://github.com/sirrobin/module1'
+def test_load_pep621():
+ inf = config.read_flit_config(samples_dir / 'pep621' / 'pyproject.toml')
+ assert inf.module == 'module1a'
+ assert inf.metadata['name'] == 'module1'
+ assert inf.metadata['description_content_type'] == 'text/x-rst'
+ # Remove all whitespace from requirements so we don't check exact format:
+ assert {r.replace(' ', '') for r in inf.metadata['requires_dist']} == {
+ 'docutils',
+ 'requests>=2.18',
+ 'pytest;extra=="test"', # from [project.optional-dependencies]
+ 'mock;extra=="test"and(python_version<\'3.6\')',
+ }
+ assert inf.metadata['author_email'] == "Sir R??bin <[email protected]>"
+ assert inf.entrypoints['flit_test_example']['foo'] == 'module1:main'
+ assert set(inf.dynamic_metadata) == {'version', 'description'}
+
+def test_load_pep621_nodynamic():
+ inf = config.read_flit_config(samples_dir / 'pep621_nodynamic' /
'pyproject.toml')
+ assert inf.module == 'module1'
+ assert inf.metadata['name'] == 'module1'
+ assert inf.metadata['version'] == '0.3'
+ assert inf.metadata['summary'] == 'Statically specified description'
+ assert set(inf.dynamic_metadata) == set()
+
def test_misspelled_key():
with pytest.raises(config.ConfigError) as e_info:
config.read_flit_config(samples_dir / 'misspelled-key.toml')
@@ -85,3 +109,44 @@
with pytest.raises(config.ConfigError, match=err_match):
config.prep_toml_config(toml_cfg, None)
+
[email protected](('proj_bad', 'err_match'), [
+ ({'version': 1}, r'\bstr\b'),
+ ({'license': {'fromage': 2}}, '[Uu]nrecognised'),
+ ({'license': {'file': 'LICENSE', 'text': 'xyz'}}, 'both'),
+ ({'license': {}}, 'required'),
+ ({'keywords': 'foo'}, 'list'),
+ ({'keywords': ['foo', 7]}, 'strings'),
+ ({'entry-points': {'foo': 'module1:main'}}, 'entry-point.*tables'),
+ ({'entry-points': {'group': {'foo': 7}}}, 'entry-point.*string'),
+ ({'entry-points': {'gui_scripts': {'foo': 'a:b'}}},
r'\[project\.gui-scripts\]'),
+ ({'scripts': {'foo': 7}}, 'scripts.*string'),
+ ({'gui-scripts': {'foo': 7}}, 'gui-scripts.*string'),
+ ({'optional-dependencies': {'test': 'requests'}}, 'list.*optional-dep'),
+ ({'optional-dependencies': {'test': [7]}}, 'string.*optional-dep'),
+ ({'dynamic': ['classifiers']}, 'dynamic'),
+ ({'dynamic': ['version']}, r'dynamic.*\[project\]'),
+ ({'authors': ['thomas']}, r'author.*\bdict'),
+ ({'maintainers': [{'title': 'Dr'}]}, r'maintainer.*title'),
+])
+def test_bad_pep621_info(proj_bad, err_match):
+ proj = {'name': 'module1', 'version': '1.0', 'description': 'x'}
+ proj.update(proj_bad)
+ with pytest.raises(config.ConfigError, match=err_match):
+ config.read_pep621_metadata(proj, samples_dir / 'pep621')
+
[email protected](('readme', 'err_match'), [
+ ({'file': 'README.rst'}, 'required'),
+ ({'file': 'README.rst', 'content-type': 'text/x-python'}, 'content-type'),
+ ('/opt/README.rst', 'relative'),
+ ({'file': 'README.rst', 'text': '', 'content-type': 'text/x-rst'}, 'both'),
+ ({'content-type': 'text/x-rst'}, 'required'),
+ ({'file': 'README.rst', 'content-type': 'text/x-rst', 'a': 'b'},
'[Uu]nrecognised'),
+ (5, r'readme.*string'),
+])
+def test_bad_pep621_readme(readme, err_match):
+ proj = {
+ 'name': 'module1', 'version': '1.0', 'description': 'x', 'readme':
readme
+ }
+ with pytest.raises(config.ConfigError, match=err_match):
+ config.read_pep621_metadata(proj, samples_dir / 'pep621')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/flit_core/tests/test_sdist.py
new/flit_core-3.2.0/flit_core/tests/test_sdist.py
--- old/flit_core-3.0.0/flit_core/tests/test_sdist.py 2020-05-23
20:40:28.577257600 +0200
+++ new/flit_core-3.2.0/flit_core/tests/test_sdist.py 2021-03-15
23:45:58.357866300 +0100
@@ -15,6 +15,22 @@
assert_isfile(tmp_path / 'package1-0.1.tar.gz')
+def test_make_sdist_pep621(tmp_path):
+ builder = sdist.SdistBuilder.from_ini_path(samples_dir / 'pep621' /
'pyproject.toml')
+ path = builder.build(tmp_path)
+ assert path == tmp_path / 'module1-0.1.tar.gz'
+ assert_isfile(path)
+
+
+def test_make_sdist_pep621_nodynamic(tmp_path):
+ builder = sdist.SdistBuilder.from_ini_path(
+ samples_dir / 'pep621_nodynamic' / 'pyproject.toml'
+ )
+ path = builder.build(tmp_path)
+ assert path == tmp_path / 'module1-0.3.tar.gz'
+ assert_isfile(path)
+
+
def test_clean_tarinfo():
with tarfile.open(mode='w', fileobj=BytesIO()) as tf:
ti = tf.gettarinfo(str(samples_dir / 'module1.py'))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/flit_core/tests/test_wheel.py
new/flit_core-3.2.0/flit_core/tests/test_wheel.py
--- old/flit_core-3.0.0/flit_core/tests/test_wheel.py 1970-01-01
01:00:00.000000000 +0100
+++ new/flit_core-3.2.0/flit_core/tests/test_wheel.py 2021-03-21
11:25:46.340291500 +0100
@@ -0,0 +1,12 @@
+from pathlib import Path
+
+from testpath import assert_isfile
+
+from flit_core.wheel import make_wheel_in
+
+samples_dir = Path(__file__).parent / 'samples'
+
+def test_licenses_dir(tmp_path):
+ # Smoketest for https://github.com/takluyver/flit/issues/399
+ info = make_wheel_in(samples_dir / 'inclusion' / 'pyproject.toml',
tmp_path)
+ assert_isfile(info.file)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/flit_core/wheel.py
new/flit_core-3.2.0/flit_core/wheel.py
--- old/flit_core-3.0.0/flit_core/wheel.py 2020-08-25 19:07:58.614150000
+0200
+++ new/flit_core-3.2.0/flit_core/wheel.py 2021-03-21 11:25:46.340291500
+0100
@@ -7,7 +7,6 @@
import logging
import os
import os.path as osp
-import re
import stat
import sys
import tempfile
@@ -83,7 +82,7 @@
@classmethod
def from_ini_path(cls, ini_path, target_fp):
- # Local import so bootstrapping doesn't try to load pytoml
+ # Local import so bootstrapping doesn't try to load toml
from .config import read_flit_config
directory = ini_path.parent
ini_info = read_flit_config(ini_path)
@@ -98,11 +97,9 @@
@property
def wheel_filename(self):
+ dist_name = common.normalize_dist_name(self.metadata.name,
self.metadata.version)
tag = ('py2.' if self.metadata.supports_py2 else '') + 'py3-none-any'
- return '{}-{}-{}.whl'.format(
- re.sub(r"[^\w\d.]+", "_", self.metadata.name,
flags=re.UNICODE),
- re.sub(r"[^\w\d.]+", "_", self.metadata.version,
flags=re.UNICODE),
- tag)
+ return '{}-{}.whl'.format(dist_name, tag)
def _add_file_old(self, full_path, rel_path):
log.debug("Adding %s to zip file", full_path)
@@ -200,8 +197,9 @@
common.write_entry_points(self.entrypoints, f)
for base in ('COPYING', 'LICENSE'):
- for path in sorted(glob(str(self.directory / (base + '*')))):
- self._add_file(path, '%s/%s' % (self.dist_info,
osp.basename(path)))
+ for path in sorted(self.directory.glob(base + '*')):
+ if path.is_file():
+ self._add_file(path, '%s/%s' % (self.dist_info, path.name))
with self._write_to_zip(self.dist_info + '/WHEEL') as f:
_write_wheel_file(f, supports_py2=self.metadata.supports_py2)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flit_core-3.0.0/pyproject.toml
new/flit_core-3.2.0/pyproject.toml
--- old/flit_core-3.0.0/pyproject.toml 2020-03-01 14:13:02.429710900 +0100
+++ new/flit_core-3.2.0/pyproject.toml 2020-11-11 09:56:38.525969700 +0100
@@ -1,4 +1,4 @@
[build-system]
requires = []
build-backend = "flit_core.build_thyself"
-backend-path = "."
+backend-path = ["."]