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 2022-01-09 22:49:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-flit-core (Old)
 and      /work/SRC/openSUSE:Factory/.python-flit-core.new.1892 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-flit-core"

Sun Jan  9 22:49:51 2022 rev:8 rq:945129 version:3.6.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-flit-core/python-flit-core.changes        
2021-10-25 15:17:33.165680110 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-flit-core.new.1892/python-flit-core.changes  
    2022-01-09 22:49:55.635270832 +0100
@@ -1,0 +2,38 @@
+Sun Jan  9 14:53:21 UTC 2022 - Ben Greiner <[email protected]>
+
+- Back to bootstrap without pip
+
+-------------------------------------------------------------------
+Sun Jan  9 11:38:59 UTC 2022 - Ben Greiner <[email protected]>
+
+- Update to version 3.6
+  * flit_core now bundles the tomli TOML parser library (version
+    1.2.3) to avoid a circular dependency between flit_core and
+    tomli (:ghpull:`492`). This means flit_core now has no
+    dependencies except Python itself, both at build time and at
+    runtime, simplifying :doc:`bootstrapping <bootstrap>`.
+- The above is not fully applicale to openSUSE, we debundle.
+- Release notes for Version 3.5.1
+  * Fix development installs with flit install --symlink and
+    --pth-file, which were broken in 3.5.0, especially for packages
+    using a src folder (:ghpull:`472`).
+- Release notes for Version 3.5
+  * You can now use Flit to distribute a module or package inside a
+    namespace package (as defined by PEP 420). To do this, specify
+    the import name of the concrete, inner module you are packaging
+    - e.g. name = "sphinxcontrib.foo" - either in the [project]
+    table, or under [tool.flit.module] if you want to use a
+    different name on PyPI (:ghpull:`468`).
+  * Flit no longer generates a setup.py file in sdists (.tar.gz
+    packages) by default (:ghpull:`462`). Modern packaging tools
+    don't need this. You can use the --setup-py flag to keep adding
+    it for now, but this will probably be removed at some point in
+    the future.
+  * Fixed how flit init handles authors' names with non-ASCII
+    characters (:ghpull:`460`).
+  * When flit init generates a LICENSE file, the new pyproject.toml
+    now references it (:ghpull:`467`).
+- Do not package tests
+- Make it work with old python-rpm-macros
+
+-------------------------------------------------------------------

Old:
----
  flit_core-3.4.0.tar.gz

New:
----
  build_dists.py
  flit_core-3.6.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-flit-core.spec ++++++
--- /var/tmp/diff_new_pack.fErFr2/_old  2022-01-09 22:49:56.883271945 +0100
+++ /var/tmp/diff_new_pack.fErFr2/_new  2022-01-09 22:49:56.887271948 +0100
@@ -1,7 +1,7 @@
 #
 # spec file
 #
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -27,17 +27,18 @@
 %{?!python_module:%define python_module() python3-%{**}}
 %define skip_python2 1
 Name:           python-flit-core%{psuffix}
-Version:        3.4.0
+Version:        3.6.0
 Release:        0
 Summary:        Distribution-building parts of Flit
 License:        BSD-3-Clause
-URL:            https://github.com/takluyver/flit
-Source:         
https://files.pythonhosted.org/packages/source/f/flit-core/flit_core-%{version}.tar.gz
+URL:            https://github.com/pypa/flit
+Source0:        
https://files.pythonhosted.org/packages/source/f/flit-core/flit_core-%{version}.tar.gz
+Source1:        
https://github.com/pypa/flit/raw/%{version}/flit_core/build_dists.py
 BuildRequires:  %{python_module base >= 3.6}
 %if %{with test}
+BuildRequires:  %{python_module flit-core = %{version}}
 BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module testpath}
-BuildRequires:  %{python_module tomli}
 %endif
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
@@ -51,6 +52,7 @@
 
 %prep
 %setup -q -n flit_core-%{version}
+cp %{SOURCE1} .
 
 %build
 # https://flit.readthedocs.io/en/latest/bootstrap.html
@@ -63,13 +65,19 @@
 unzip dist/flit_core-%{version}-py3-none-any.whl -d 
%{buildroot}%{$python_sitelib}
 rm -r  %{buildroot}%{$python_sitelib}/flit_core/tests
 }
-%python_compileall
+%{python_expand # debundle after the bootstrap. See vendor/README
+sed -i 's/from .vendor import tomli/import tomli/'  
%{buildroot}%{$python_sitelib}/flit_core/config.py
+rm -r %{buildroot}%{$python_sitelib}/flit_core/vendor
+}
+%{?python_compileall}
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 %endif
 
 %if %{with test}
 %check
-%pytest
+# make sure we do not test the sources but the debundled package
+rm flit_core/*.py pyproject.toml
+%pytest -rfEs
 %endif
 
 %if !%{with test}

++++++ build_dists.py ++++++
"""Build flit_core to upload to PyPI.

Normally, this should only be used by me when making a release.
"""
import os

from flit_core import buildapi

os.chdir(os.path.dirname(os.path.abspath(__file__)))

print("Building sdist")
sdist_fname = buildapi.build_sdist('dist/')
print(os.path.join('dist', sdist_fname))

print("\nBuilding wheel")
whl_fname = buildapi.build_wheel('dist/')
print(os.path.join('dist', whl_fname))

++++++ flit_core-3.4.0.tar.gz -> flit_core-3.6.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/PKG-INFO new/flit_core-3.6.0/PKG-INFO
--- old/flit_core-3.4.0/PKG-INFO        1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.6.0/PKG-INFO        1970-01-01 01:00:00.000000000 +0100
@@ -1,11 +1,9 @@
 Metadata-Version: 2.1
 Name: flit_core
-Version: 3.4.0
+Version: 3.6.0
 Summary: Distribution-building parts of Flit. See flit package for more 
information
-Home-page: https://github.com/takluyver/flit
-Author: Thomas Kluyver & contributors
-Author-email: [email protected]
+Author-email: Thomas Kluyver & contributors <[email protected]>
 Requires-Python: >=3.6
 Classifier: License :: OSI Approved :: BSD License
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Requires-Dist: tomli
+Project-URL: Source, https://github.com/pypa/flit
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/build_dists.py 
new/flit_core-3.6.0/build_dists.py
--- old/flit_core-3.4.0/build_dists.py  2021-05-09 17:40:19.105348300 +0200
+++ new/flit_core-3.6.0/build_dists.py  1970-01-01 01:00:00.000000000 +0100
@@ -1,17 +0,0 @@
-"""Build flit_core to upload to PyPI.
-
-Normally, this should only be used by me when making a release.
-"""
-import os
-
-from flit_core import build_thyself
-
-os.chdir(os.path.dirname(os.path.abspath(__file__)))
-
-print("Building sdist")
-sdist_fname = build_thyself.build_sdist('dist/')
-print(os.path.join('dist', sdist_fname))
-
-print("\nBuilding wheel")
-whl_fname = build_thyself.build_wheel('dist/')
-print(os.path.join('dist', whl_fname))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/__init__.py 
new/flit_core-3.6.0/flit_core/__init__.py
--- old/flit_core-3.4.0/flit_core/__init__.py   2021-10-10 11:29:14.143066200 
+0200
+++ new/flit_core-3.6.0/flit_core/__init__.py   2021-12-27 14:38:33.710516700 
+0100
@@ -4,4 +4,4 @@
 All the convenient development features live in the main 'flit' package.
 """
 
-__version__ = '3.4.0'
+__version__ = '3.6.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/build_thyself.py 
new/flit_core-3.6.0/flit_core/build_thyself.py
--- old/flit_core-3.4.0/flit_core/build_thyself.py      2021-10-10 
11:14:23.714307800 +0200
+++ new/flit_core-3.6.0/flit_core/build_thyself.py      1970-01-01 
01:00:00.000000000 +0100
@@ -1,95 +0,0 @@
-"""Bootstrapping backend
-
-This is *only* meant to build flit_core itself.
-Building any other packages occurs through flit_core.buildapi
-"""
-
-import io
-import os
-import os.path as osp
-from pathlib import Path
-import tempfile
-
-from .common import Metadata, Module, dist_info_name
-from .wheel import WheelBuilder, _write_wheel_file
-from .sdist import SdistBuilder
-
-from . import __version__
-
-metadata_dict = {
-    'name': 'flit_core',
-    'version': __version__,
-    'author': 'Thomas Kluyver & contributors',
-    'author_email': '[email protected]',
-    'home_page': 'https://github.com/takluyver/flit',
-    'summary': ('Distribution-building parts of Flit. '
-                    'See flit package for more information'),
-    'requires_dist': [
-        'tomli',
-    ],
-    'requires_python': '>=3.6',
-    'classifiers': [
-        "License :: OSI Approved :: BSD License",
-        "Topic :: Software Development :: Libraries :: Python Modules",
-    ]
-}
-metadata = Metadata(metadata_dict)
-
-def get_requires_for_build_wheel(config_settings=None):
-    """Returns a list of requirements for building, as strings"""
-    return []
-
-def get_requires_for_build_sdist(config_settings=None):
-    """Returns a list of requirements for building, as strings"""
-    return []
-
-def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
-    """Creates {metadata_directory}/foo-1.2.dist-info"""
-    dist_info = osp.join(metadata_directory,
-                         dist_info_name(metadata.name, metadata.version))
-    os.mkdir(dist_info)
-
-    with open(osp.join(dist_info, 'WHEEL'), 'w') as f:
-        _write_wheel_file(f, supports_py2=metadata.supports_py2)
-
-    with open(osp.join(dist_info, 'METADATA'), 'w') as f:
-        metadata.write_metadata_file(f)
-
-    return osp.basename(dist_info)
-
-def build_wheel(wheel_directory, config_settings=None, 
metadata_directory=None):
-    """Builds a wheel, places it in wheel_directory"""
-    cwd = Path.cwd()
-    module = Module('flit_core', cwd)
-
-    # We don't know the final filename until metadata is loaded, so write to
-    # a temporary_file, and rename it afterwards.
-    (fd, temp_path) = tempfile.mkstemp(suffix='.whl', dir=str(wheel_directory))
-    try:
-        with io.open(fd, 'w+b') as fp:
-            wb = WheelBuilder(
-                cwd, module, metadata, entrypoints={}, target_fp=fp
-            )
-            wb.build()
-
-        wheel_path = osp.join(wheel_directory, wb.wheel_filename)
-        os.replace(temp_path, wheel_path)
-    except:
-        os.unlink(temp_path)
-        raise
-
-    return wb.wheel_filename
-
-def build_sdist(sdist_directory, config_settings=None):
-    """Builds an sdist, places it in sdist_directory"""
-    cwd = Path.cwd()
-    module = Module('flit_core', cwd)
-    reqs_by_extra = {'.none': metadata.requires}
-
-    sb = SdistBuilder(
-        module, metadata, cwd, reqs_by_extra, entrypoints={},
-        extra_files=['pyproject.toml', 'build_dists.py']
-    )
-    path = sb.build(Path(sdist_directory))
-    return path.name
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/common.py 
new/flit_core-3.6.0/flit_core/common.py
--- old/flit_core-3.4.0/flit_core/common.py     2021-05-09 17:40:19.105348300 
+0200
+++ new/flit_core-3.6.0/flit_core/common.py     2021-11-23 12:08:18.530732200 
+0100
@@ -3,7 +3,7 @@
 import hashlib
 import logging
 import os
-import os.path as osp
+
 from pathlib import Path
 import re
 
@@ -14,15 +14,18 @@
 class Module(object):
     """This represents the module/package that we are going to distribute
     """
+    in_namespace_package = False
+    namespace_package_name = None
+
     def __init__(self, name, directory=Path()):
         self.name = name
-        self.directory = directory
 
         # It must exist either as a .py file or a directory, but not both
-        pkg_dir = directory / name
-        py_file = directory / (name+'.py')
-        src_pkg_dir = directory / 'src' / name
-        src_py_file = directory / 'src' / (name+'.py')
+        name_as_path = name.replace('.', os.sep)
+        pkg_dir = directory / name_as_path
+        py_file = directory / (name_as_path+'.py')
+        src_pkg_dir = directory / 'src' / name_as_path
+        src_py_file = directory / 'src' / (name_as_path+'.py')
 
         existing = set()
         if pkg_dir.is_dir():
@@ -54,10 +57,11 @@
         elif not existing:
             raise ValueError("No file/folder found for module {}".format(name))
 
-    @property
-    def source_dir(self):
-        """Path of folder containing the module (src/ or project root)"""
-        return self.path.parent
+        self.source_dir = directory / self.prefix
+
+        if '.' in name:
+            self.namespace_package_name = name.rpartition('.')[0]
+            self.in_namespace_package = True
 
     @property
     def file(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/config.py 
new/flit_core-3.6.0/flit_core/config.py
--- old/flit_core-3.4.0/flit_core/config.py     2021-10-01 10:16:06.493757700 
+0200
+++ new/flit_core-3.6.0/flit_core/config.py     2021-12-27 14:04:58.924610600 
+0100
@@ -5,9 +5,9 @@
 import os
 import os.path as osp
 from pathlib import Path
-import tomli
 import re
 
+from .vendor import tomli
 from .versionno import normalise_version
 
 log = logging.getLogger(__name__)
@@ -287,7 +287,7 @@
     res = LoadedConfig()
 
     res.module = md_sect.get('module')
-    if not str.isidentifier(res.module):
+    if not all([m.isidentifier() for m in res.module.split(".")]):
         raise ConfigError("Module name %r is not a valid identifier" % 
res.module)
 
     md_dict = res.metadata
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/tests/samples/module2.py 
new/flit_core-3.6.0/flit_core/tests/samples/module2.py
--- old/flit_core-3.4.0/flit_core/tests/samples/module2.py      2021-05-09 
17:40:19.106348500 +0200
+++ new/flit_core-3.6.0/flit_core/tests/samples/module2.py      2021-12-06 
15:34:44.137786100 +0100
@@ -4,7 +4,7 @@
 
 a = {}
 # An assignment to a subscript (a['test']) broke introspection
-# https://github.com/takluyver/flit/issues/343
+# https://github.com/pypa/flit/issues/343
 a['test'] = 6
 
 __version__ = '7.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/flit_core-3.4.0/flit_core/tests/samples/ns1-pkg/EG_README.rst 
new/flit_core-3.6.0/flit_core/tests/samples/ns1-pkg/EG_README.rst
--- old/flit_core-3.4.0/flit_core/tests/samples/ns1-pkg/EG_README.rst   
1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.6.0/flit_core/tests/samples/ns1-pkg/EG_README.rst   
2021-11-18 23:10:43.577393000 +0100
@@ -0,0 +1,4 @@
+This is an example long description for tests to load.
+
+This file is `valid reStructuredText
+<http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html>`_.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/flit_core-3.4.0/flit_core/tests/samples/ns1-pkg/ns1/pkg/__init__.py 
new/flit_core-3.6.0/flit_core/tests/samples/ns1-pkg/ns1/pkg/__init__.py
--- old/flit_core-3.4.0/flit_core/tests/samples/ns1-pkg/ns1/pkg/__init__.py     
1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.6.0/flit_core/tests/samples/ns1-pkg/ns1/pkg/__init__.py     
2021-11-18 23:10:43.577393000 +0100
@@ -0,0 +1,8 @@
+"""
+==================
+ns1.pkg
+==================
+"""
+
+__version__ = '0.1'
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/flit_core-3.4.0/flit_core/tests/samples/ns1-pkg/pyproject.toml 
new/flit_core-3.6.0/flit_core/tests/samples/ns1-pkg/pyproject.toml
--- old/flit_core-3.4.0/flit_core/tests/samples/ns1-pkg/pyproject.toml  
1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.6.0/flit_core/tests/samples/ns1-pkg/pyproject.toml  
2021-11-18 23:10:43.577393000 +0100
@@ -0,0 +1,10 @@
+[build-system]
+requires = ["flit_core >=3.5,<4"]
+build-backend = "flit_core.buildapi"
+
+[tool.flit.metadata]
+module = "ns1.pkg"
+author = "Sir Robin"
+author-email = "[email protected]"
+home-page = "http://github.com/sirrobin/module1";
+description-file = "EG_README.rst"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/flit_core-3.4.0/flit_core/tests/test_build_thyself.py 
new/flit_core-3.6.0/flit_core/tests/test_build_thyself.py
--- old/flit_core-3.4.0/flit_core/tests/test_build_thyself.py   2021-05-09 
17:40:19.108348400 +0200
+++ new/flit_core-3.6.0/flit_core/tests/test_build_thyself.py   2021-12-27 
14:04:58.924610600 +0100
@@ -1,3 +1,4 @@
+"""Tests of flit_core building itself"""
 import os
 import os.path as osp
 import pytest
@@ -5,11 +6,11 @@
 from testpath import assert_isdir, assert_isfile
 import zipfile
 
-from flit_core import build_thyself
+from flit_core import buildapi
 
 @pytest.fixture()
 def cwd_project():
-    proj_dir = osp.dirname(osp.dirname(osp.abspath(build_thyself.__file__)))
+    proj_dir = osp.dirname(osp.dirname(osp.abspath(buildapi.__file__)))
     if not osp.isfile(osp.join(proj_dir, 'pyproject.toml')):
         pytest.skip("need flit_core source directory")
 
@@ -21,9 +22,9 @@
         os.chdir(old_cwd)
 
 
-def test_prepare_metadata(tmp_path):
+def test_prepare_metadata(tmp_path, cwd_project):
     tmp_path = str(tmp_path)
-    dist_info = build_thyself.prepare_metadata_for_build_wheel(tmp_path)
+    dist_info = buildapi.prepare_metadata_for_build_wheel(tmp_path)
 
     assert dist_info.endswith('.dist-info')
     assert dist_info.startswith('flit_core')
@@ -36,7 +37,7 @@
 
 def test_wheel(tmp_path, cwd_project):
     tmp_path = str(tmp_path)
-    filename = build_thyself.build_wheel(tmp_path)
+    filename = buildapi.build_wheel(tmp_path)
 
     assert filename.endswith('.whl')
     assert filename.startswith('flit_core')
@@ -47,7 +48,7 @@
 
 def test_sdist(tmp_path, cwd_project):
     tmp_path = str(tmp_path)
-    filename = build_thyself.build_sdist(tmp_path)
+    filename = buildapi.build_sdist(tmp_path)
 
     assert filename.endswith('.tar.gz')
     assert filename.startswith('flit_core')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/tests/test_common.py 
new/flit_core-3.6.0/flit_core/tests/test_common.py
--- old/flit_core-3.4.0/flit_core/tests/test_common.py  2021-05-09 
17:40:19.108348400 +0200
+++ new/flit_core-3.6.0/flit_core/tests/test_common.py  2021-11-18 
23:10:43.577393000 +0100
@@ -14,6 +14,15 @@
 samples_dir = Path(__file__).parent / 'samples'
 
 class ModuleTests(TestCase):
+    def test_ns_package_importable(self):
+        i = Module('ns1.pkg', samples_dir / 'ns1-pkg')
+        assert i.path == Path(samples_dir, 'ns1-pkg', 'ns1', 'pkg')
+        assert i.file == Path(samples_dir, 'ns1-pkg', 'ns1', 'pkg', 
'__init__.py')
+        assert i.is_package
+
+        assert i.in_namespace_package
+        assert i.namespace_package_name == 'ns1'
+
     def test_package_importable(self):
         i = Module('package1', samples_dir)
         assert i.path == samples_dir / 'package1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/tests/test_config.py 
new/flit_core-3.6.0/flit_core/tests/test_config.py
--- old/flit_core-3.4.0/flit_core/tests/test_config.py  2021-08-19 
19:07:06.144217700 +0200
+++ new/flit_core-3.6.0/flit_core/tests/test_config.py  2021-11-18 
23:10:43.578393000 +0100
@@ -15,6 +15,11 @@
     assert inf.module == 'module1'
     assert inf.metadata['home_page'] == 'http://github.com/sirrobin/module1'
 
+def test_load_toml_ns():
+    inf = config.read_flit_config(samples_dir / 'ns1-pkg' / 'pyproject.toml')
+    assert inf.module == 'ns1.pkg'
+    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'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/tests/test_wheel.py 
new/flit_core-3.6.0/flit_core/tests/test_wheel.py
--- old/flit_core-3.4.0/flit_core/tests/test_wheel.py   2021-10-06 
21:26:07.727812800 +0200
+++ new/flit_core-3.6.0/flit_core/tests/test_wheel.py   2021-12-06 
15:34:44.137786100 +0100
@@ -8,7 +8,7 @@
 samples_dir = Path(__file__).parent / 'samples'
 
 def test_licenses_dir(tmp_path):
-    # Smoketest for https://github.com/takluyver/flit/issues/399
+    # Smoketest for https://github.com/pypa/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.4.0/flit_core/vendor/README 
new/flit_core-3.6.0/flit_core/vendor/README
--- old/flit_core-3.4.0/flit_core/vendor/README 1970-01-01 01:00:00.000000000 
+0100
+++ new/flit_core-3.6.0/flit_core/vendor/README 2021-12-27 14:04:58.925610500 
+0100
@@ -0,0 +1,13 @@
+flit_core bundles the 'tomli' TOML parser, to avoid a bootstrapping problem.
+tomli is packaged using Flit, so there would be a dependency cycle when 
building
+from source. Vendoring a copy of tomli avoids this. The code in tomli is under
+the MIT license, and the LICENSE file is in the .dist-info folder.
+
+If you want to unbundle tomli and rely on it as a separate package, you can
+replace the package with Python code doing 'from tomli import *'. You will
+probably need to work around the dependency cycle between flit_core and tomli.
+
+Bundling a TOML parser should be a special case - I don't plan on bundling
+anything else in flit_core (or depending on any other packages).
+I hope that a TOML parser will be added to the Python standard library, and 
then
+this bundled parser will go away.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/vendor/tomli/__init__.py 
new/flit_core-3.6.0/flit_core/vendor/tomli/__init__.py
--- old/flit_core-3.4.0/flit_core/vendor/tomli/__init__.py      1970-01-01 
01:00:00.000000000 +0100
+++ new/flit_core-3.6.0/flit_core/vendor/tomli/__init__.py      2021-12-27 
14:04:58.927610600 +0100
@@ -0,0 +1,9 @@
+"""A lil' TOML parser."""
+
+__all__ = ("loads", "load", "TOMLDecodeError")
+__version__ = "1.2.3"  # DO NOT EDIT THIS LINE MANUALLY. LET bump2version 
UTILITY DO IT
+
+from ._parser import TOMLDecodeError, load, loads
+
+# Pretend this exception was created here.
+TOMLDecodeError.__module__ = "tomli"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/vendor/tomli/_parser.py 
new/flit_core-3.6.0/flit_core/vendor/tomli/_parser.py
--- old/flit_core-3.4.0/flit_core/vendor/tomli/_parser.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/flit_core-3.6.0/flit_core/vendor/tomli/_parser.py       2021-12-27 
14:04:58.927610600 +0100
@@ -0,0 +1,663 @@
+import string
+from types import MappingProxyType
+from typing import Any, BinaryIO, Dict, FrozenSet, Iterable, NamedTuple, 
Optional, Tuple
+import warnings
+
+from ._re import (
+    RE_DATETIME,
+    RE_LOCALTIME,
+    RE_NUMBER,
+    match_to_datetime,
+    match_to_localtime,
+    match_to_number,
+)
+from ._types import Key, ParseFloat, Pos
+
+ASCII_CTRL = frozenset(chr(i) for i in range(32)) | frozenset(chr(127))
+
+# Neither of these sets include quotation mark or backslash. They are
+# currently handled as separate cases in the parser functions.
+ILLEGAL_BASIC_STR_CHARS = ASCII_CTRL - frozenset("\t")
+ILLEGAL_MULTILINE_BASIC_STR_CHARS = ASCII_CTRL - frozenset("\t\n")
+
+ILLEGAL_LITERAL_STR_CHARS = ILLEGAL_BASIC_STR_CHARS
+ILLEGAL_MULTILINE_LITERAL_STR_CHARS = ILLEGAL_MULTILINE_BASIC_STR_CHARS
+
+ILLEGAL_COMMENT_CHARS = ILLEGAL_BASIC_STR_CHARS
+
+TOML_WS = frozenset(" \t")
+TOML_WS_AND_NEWLINE = TOML_WS | frozenset("\n")
+BARE_KEY_CHARS = frozenset(string.ascii_letters + string.digits + "-_")
+KEY_INITIAL_CHARS = BARE_KEY_CHARS | frozenset("\"'")
+HEXDIGIT_CHARS = frozenset(string.hexdigits)
+
+BASIC_STR_ESCAPE_REPLACEMENTS = MappingProxyType(
+    {
+        "\\b": "\u0008",  # backspace
+        "\\t": "\u0009",  # tab
+        "\\n": "\u000A",  # linefeed
+        "\\f": "\u000C",  # form feed
+        "\\r": "\u000D",  # carriage return
+        '\\"': "\u0022",  # quote
+        "\\\\": "\u005C",  # backslash
+    }
+)
+
+
+class TOMLDecodeError(ValueError):
+    """An error raised if a document is not valid TOML."""
+
+
+def load(fp: BinaryIO, *, parse_float: ParseFloat = float) -> Dict[str, Any]:
+    """Parse TOML from a binary file object."""
+    s_bytes = fp.read()
+    try:
+        s = s_bytes.decode()
+    except AttributeError:
+        warnings.warn(
+            "Text file object support is deprecated in favor of binary file 
objects."
+            ' Use `open("foo.toml", "rb")` to open the file in binary mode.',
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        s = s_bytes  # type: ignore[assignment]
+    return loads(s, parse_float=parse_float)
+
+
+def loads(s: str, *, parse_float: ParseFloat = float) -> Dict[str, Any]:  # 
noqa: C901
+    """Parse TOML from a string."""
+
+    # The spec allows converting "\r\n" to "\n", even in string
+    # literals. Let's do so to simplify parsing.
+    src = s.replace("\r\n", "\n")
+    pos = 0
+    out = Output(NestedDict(), Flags())
+    header: Key = ()
+
+    # Parse one statement at a time
+    # (typically means one line in TOML source)
+    while True:
+        # 1. Skip line leading whitespace
+        pos = skip_chars(src, pos, TOML_WS)
+
+        # 2. Parse rules. Expect one of the following:
+        #    - end of file
+        #    - end of line
+        #    - comment
+        #    - key/value pair
+        #    - append dict to list (and move to its namespace)
+        #    - create dict (and move to its namespace)
+        # Skip trailing whitespace when applicable.
+        try:
+            char = src[pos]
+        except IndexError:
+            break
+        if char == "\n":
+            pos += 1
+            continue
+        if char in KEY_INITIAL_CHARS:
+            pos = key_value_rule(src, pos, out, header, parse_float)
+            pos = skip_chars(src, pos, TOML_WS)
+        elif char == "[":
+            try:
+                second_char: Optional[str] = src[pos + 1]
+            except IndexError:
+                second_char = None
+            if second_char == "[":
+                pos, header = create_list_rule(src, pos, out)
+            else:
+                pos, header = create_dict_rule(src, pos, out)
+            pos = skip_chars(src, pos, TOML_WS)
+        elif char != "#":
+            raise suffixed_err(src, pos, "Invalid statement")
+
+        # 3. Skip comment
+        pos = skip_comment(src, pos)
+
+        # 4. Expect end of line or end of file
+        try:
+            char = src[pos]
+        except IndexError:
+            break
+        if char != "\n":
+            raise suffixed_err(
+                src, pos, "Expected newline or end of document after a 
statement"
+            )
+        pos += 1
+
+    return out.data.dict
+
+
+class Flags:
+    """Flags that map to parsed keys/namespaces."""
+
+    # Marks an immutable namespace (inline array or inline table).
+    FROZEN = 0
+    # Marks a nest that has been explicitly created and can no longer
+    # be opened using the "[table]" syntax.
+    EXPLICIT_NEST = 1
+
+    def __init__(self) -> None:
+        self._flags: Dict[str, dict] = {}
+
+    def unset_all(self, key: Key) -> None:
+        cont = self._flags
+        for k in key[:-1]:
+            if k not in cont:
+                return
+            cont = cont[k]["nested"]
+        cont.pop(key[-1], None)
+
+    def set_for_relative_key(self, head_key: Key, rel_key: Key, flag: int) -> 
None:
+        cont = self._flags
+        for k in head_key:
+            if k not in cont:
+                cont[k] = {"flags": set(), "recursive_flags": set(), "nested": 
{}}
+            cont = cont[k]["nested"]
+        for k in rel_key:
+            if k in cont:
+                cont[k]["flags"].add(flag)
+            else:
+                cont[k] = {"flags": {flag}, "recursive_flags": set(), 
"nested": {}}
+            cont = cont[k]["nested"]
+
+    def set(self, key: Key, flag: int, *, recursive: bool) -> None:  # noqa: 
A003
+        cont = self._flags
+        key_parent, key_stem = key[:-1], key[-1]
+        for k in key_parent:
+            if k not in cont:
+                cont[k] = {"flags": set(), "recursive_flags": set(), "nested": 
{}}
+            cont = cont[k]["nested"]
+        if key_stem not in cont:
+            cont[key_stem] = {"flags": set(), "recursive_flags": set(), 
"nested": {}}
+        cont[key_stem]["recursive_flags" if recursive else "flags"].add(flag)
+
+    def is_(self, key: Key, flag: int) -> bool:
+        if not key:
+            return False  # document root has no flags
+        cont = self._flags
+        for k in key[:-1]:
+            if k not in cont:
+                return False
+            inner_cont = cont[k]
+            if flag in inner_cont["recursive_flags"]:
+                return True
+            cont = inner_cont["nested"]
+        key_stem = key[-1]
+        if key_stem in cont:
+            cont = cont[key_stem]
+            return flag in cont["flags"] or flag in cont["recursive_flags"]
+        return False
+
+
+class NestedDict:
+    def __init__(self) -> None:
+        # The parsed content of the TOML document
+        self.dict: Dict[str, Any] = {}
+
+    def get_or_create_nest(
+        self,
+        key: Key,
+        *,
+        access_lists: bool = True,
+    ) -> dict:
+        cont: Any = self.dict
+        for k in key:
+            if k not in cont:
+                cont[k] = {}
+            cont = cont[k]
+            if access_lists and isinstance(cont, list):
+                cont = cont[-1]
+            if not isinstance(cont, dict):
+                raise KeyError("There is no nest behind this key")
+        return cont
+
+    def append_nest_to_list(self, key: Key) -> None:
+        cont = self.get_or_create_nest(key[:-1])
+        last_key = key[-1]
+        if last_key in cont:
+            list_ = cont[last_key]
+            try:
+                list_.append({})
+            except AttributeError:
+                raise KeyError("An object other than list found behind this 
key")
+        else:
+            cont[last_key] = [{}]
+
+
+class Output(NamedTuple):
+    data: NestedDict
+    flags: Flags
+
+
+def skip_chars(src: str, pos: Pos, chars: Iterable[str]) -> Pos:
+    try:
+        while src[pos] in chars:
+            pos += 1
+    except IndexError:
+        pass
+    return pos
+
+
+def skip_until(
+    src: str,
+    pos: Pos,
+    expect: str,
+    *,
+    error_on: FrozenSet[str],
+    error_on_eof: bool,
+) -> Pos:
+    try:
+        new_pos = src.index(expect, pos)
+    except ValueError:
+        new_pos = len(src)
+        if error_on_eof:
+            raise suffixed_err(src, new_pos, f"Expected {expect!r}") from None
+
+    if not error_on.isdisjoint(src[pos:new_pos]):
+        while src[pos] not in error_on:
+            pos += 1
+        raise suffixed_err(src, pos, f"Found invalid character {src[pos]!r}")
+    return new_pos
+
+
+def skip_comment(src: str, pos: Pos) -> Pos:
+    try:
+        char: Optional[str] = src[pos]
+    except IndexError:
+        char = None
+    if char == "#":
+        return skip_until(
+            src, pos + 1, "\n", error_on=ILLEGAL_COMMENT_CHARS, 
error_on_eof=False
+        )
+    return pos
+
+
+def skip_comments_and_array_ws(src: str, pos: Pos) -> Pos:
+    while True:
+        pos_before_skip = pos
+        pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE)
+        pos = skip_comment(src, pos)
+        if pos == pos_before_skip:
+            return pos
+
+
+def create_dict_rule(src: str, pos: Pos, out: Output) -> Tuple[Pos, Key]:
+    pos += 1  # Skip "["
+    pos = skip_chars(src, pos, TOML_WS)
+    pos, key = parse_key(src, pos)
+
+    if out.flags.is_(key, Flags.EXPLICIT_NEST) or out.flags.is_(key, 
Flags.FROZEN):
+        raise suffixed_err(src, pos, f"Can not declare {key} twice")
+    out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False)
+    try:
+        out.data.get_or_create_nest(key)
+    except KeyError:
+        raise suffixed_err(src, pos, "Can not overwrite a value") from None
+
+    if not src.startswith("]", pos):
+        raise suffixed_err(src, pos, 'Expected "]" at the end of a table 
declaration')
+    return pos + 1, key
+
+
+def create_list_rule(src: str, pos: Pos, out: Output) -> Tuple[Pos, Key]:
+    pos += 2  # Skip "[["
+    pos = skip_chars(src, pos, TOML_WS)
+    pos, key = parse_key(src, pos)
+
+    if out.flags.is_(key, Flags.FROZEN):
+        raise suffixed_err(src, pos, f"Can not mutate immutable namespace 
{key}")
+    # Free the namespace now that it points to another empty list item...
+    out.flags.unset_all(key)
+    # ...but this key precisely is still prohibited from table declaration
+    out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False)
+    try:
+        out.data.append_nest_to_list(key)
+    except KeyError:
+        raise suffixed_err(src, pos, "Can not overwrite a value") from None
+
+    if not src.startswith("]]", pos):
+        raise suffixed_err(src, pos, 'Expected "]]" at the end of an array 
declaration')
+    return pos + 2, key
+
+
+def key_value_rule(
+    src: str, pos: Pos, out: Output, header: Key, parse_float: ParseFloat
+) -> Pos:
+    pos, key, value = parse_key_value_pair(src, pos, parse_float)
+    key_parent, key_stem = key[:-1], key[-1]
+    abs_key_parent = header + key_parent
+
+    if out.flags.is_(abs_key_parent, Flags.FROZEN):
+        raise suffixed_err(
+            src, pos, f"Can not mutate immutable namespace {abs_key_parent}"
+        )
+    # Containers in the relative path can't be opened with the table syntax 
after this
+    out.flags.set_for_relative_key(header, key, Flags.EXPLICIT_NEST)
+    try:
+        nest = out.data.get_or_create_nest(abs_key_parent)
+    except KeyError:
+        raise suffixed_err(src, pos, "Can not overwrite a value") from None
+    if key_stem in nest:
+        raise suffixed_err(src, pos, "Can not overwrite a value")
+    # Mark inline table and array namespaces recursively immutable
+    if isinstance(value, (dict, list)):
+        out.flags.set(header + key, Flags.FROZEN, recursive=True)
+    nest[key_stem] = value
+    return pos
+
+
+def parse_key_value_pair(
+    src: str, pos: Pos, parse_float: ParseFloat
+) -> Tuple[Pos, Key, Any]:
+    pos, key = parse_key(src, pos)
+    try:
+        char: Optional[str] = src[pos]
+    except IndexError:
+        char = None
+    if char != "=":
+        raise suffixed_err(src, pos, 'Expected "=" after a key in a key/value 
pair')
+    pos += 1
+    pos = skip_chars(src, pos, TOML_WS)
+    pos, value = parse_value(src, pos, parse_float)
+    return pos, key, value
+
+
+def parse_key(src: str, pos: Pos) -> Tuple[Pos, Key]:
+    pos, key_part = parse_key_part(src, pos)
+    key: Key = (key_part,)
+    pos = skip_chars(src, pos, TOML_WS)
+    while True:
+        try:
+            char: Optional[str] = src[pos]
+        except IndexError:
+            char = None
+        if char != ".":
+            return pos, key
+        pos += 1
+        pos = skip_chars(src, pos, TOML_WS)
+        pos, key_part = parse_key_part(src, pos)
+        key += (key_part,)
+        pos = skip_chars(src, pos, TOML_WS)
+
+
+def parse_key_part(src: str, pos: Pos) -> Tuple[Pos, str]:
+    try:
+        char: Optional[str] = src[pos]
+    except IndexError:
+        char = None
+    if char in BARE_KEY_CHARS:
+        start_pos = pos
+        pos = skip_chars(src, pos, BARE_KEY_CHARS)
+        return pos, src[start_pos:pos]
+    if char == "'":
+        return parse_literal_str(src, pos)
+    if char == '"':
+        return parse_one_line_basic_str(src, pos)
+    raise suffixed_err(src, pos, "Invalid initial character for a key part")
+
+
+def parse_one_line_basic_str(src: str, pos: Pos) -> Tuple[Pos, str]:
+    pos += 1
+    return parse_basic_str(src, pos, multiline=False)
+
+
+def parse_array(src: str, pos: Pos, parse_float: ParseFloat) -> Tuple[Pos, 
list]:
+    pos += 1
+    array: list = []
+
+    pos = skip_comments_and_array_ws(src, pos)
+    if src.startswith("]", pos):
+        return pos + 1, array
+    while True:
+        pos, val = parse_value(src, pos, parse_float)
+        array.append(val)
+        pos = skip_comments_and_array_ws(src, pos)
+
+        c = src[pos : pos + 1]
+        if c == "]":
+            return pos + 1, array
+        if c != ",":
+            raise suffixed_err(src, pos, "Unclosed array")
+        pos += 1
+
+        pos = skip_comments_and_array_ws(src, pos)
+        if src.startswith("]", pos):
+            return pos + 1, array
+
+
+def parse_inline_table(src: str, pos: Pos, parse_float: ParseFloat) -> 
Tuple[Pos, dict]:
+    pos += 1
+    nested_dict = NestedDict()
+    flags = Flags()
+
+    pos = skip_chars(src, pos, TOML_WS)
+    if src.startswith("}", pos):
+        return pos + 1, nested_dict.dict
+    while True:
+        pos, key, value = parse_key_value_pair(src, pos, parse_float)
+        key_parent, key_stem = key[:-1], key[-1]
+        if flags.is_(key, Flags.FROZEN):
+            raise suffixed_err(src, pos, f"Can not mutate immutable namespace 
{key}")
+        try:
+            nest = nested_dict.get_or_create_nest(key_parent, 
access_lists=False)
+        except KeyError:
+            raise suffixed_err(src, pos, "Can not overwrite a value") from None
+        if key_stem in nest:
+            raise suffixed_err(src, pos, f"Duplicate inline table key 
{key_stem!r}")
+        nest[key_stem] = value
+        pos = skip_chars(src, pos, TOML_WS)
+        c = src[pos : pos + 1]
+        if c == "}":
+            return pos + 1, nested_dict.dict
+        if c != ",":
+            raise suffixed_err(src, pos, "Unclosed inline table")
+        if isinstance(value, (dict, list)):
+            flags.set(key, Flags.FROZEN, recursive=True)
+        pos += 1
+        pos = skip_chars(src, pos, TOML_WS)
+
+
+def parse_basic_str_escape(  # noqa: C901
+    src: str, pos: Pos, *, multiline: bool = False
+) -> Tuple[Pos, str]:
+    escape_id = src[pos : pos + 2]
+    pos += 2
+    if multiline and escape_id in {"\\ ", "\\\t", "\\\n"}:
+        # Skip whitespace until next non-whitespace character or end of
+        # the doc. Error if non-whitespace is found before newline.
+        if escape_id != "\\\n":
+            pos = skip_chars(src, pos, TOML_WS)
+            try:
+                char = src[pos]
+            except IndexError:
+                return pos, ""
+            if char != "\n":
+                raise suffixed_err(src, pos, 'Unescaped "\\" in a string')
+            pos += 1
+        pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE)
+        return pos, ""
+    if escape_id == "\\u":
+        return parse_hex_char(src, pos, 4)
+    if escape_id == "\\U":
+        return parse_hex_char(src, pos, 8)
+    try:
+        return pos, BASIC_STR_ESCAPE_REPLACEMENTS[escape_id]
+    except KeyError:
+        if len(escape_id) != 2:
+            raise suffixed_err(src, pos, "Unterminated string") from None
+        raise suffixed_err(src, pos, 'Unescaped "\\" in a string') from None
+
+
+def parse_basic_str_escape_multiline(src: str, pos: Pos) -> Tuple[Pos, str]:
+    return parse_basic_str_escape(src, pos, multiline=True)
+
+
+def parse_hex_char(src: str, pos: Pos, hex_len: int) -> Tuple[Pos, str]:
+    hex_str = src[pos : pos + hex_len]
+    if len(hex_str) != hex_len or not HEXDIGIT_CHARS.issuperset(hex_str):
+        raise suffixed_err(src, pos, "Invalid hex value")
+    pos += hex_len
+    hex_int = int(hex_str, 16)
+    if not is_unicode_scalar_value(hex_int):
+        raise suffixed_err(src, pos, "Escaped character is not a Unicode 
scalar value")
+    return pos, chr(hex_int)
+
+
+def parse_literal_str(src: str, pos: Pos) -> Tuple[Pos, str]:
+    pos += 1  # Skip starting apostrophe
+    start_pos = pos
+    pos = skip_until(
+        src, pos, "'", error_on=ILLEGAL_LITERAL_STR_CHARS, error_on_eof=True
+    )
+    return pos + 1, src[start_pos:pos]  # Skip ending apostrophe
+
+
+def parse_multiline_str(src: str, pos: Pos, *, literal: bool) -> Tuple[Pos, 
str]:
+    pos += 3
+    if src.startswith("\n", pos):
+        pos += 1
+
+    if literal:
+        delim = "'"
+        end_pos = skip_until(
+            src,
+            pos,
+            "'''",
+            error_on=ILLEGAL_MULTILINE_LITERAL_STR_CHARS,
+            error_on_eof=True,
+        )
+        result = src[pos:end_pos]
+        pos = end_pos + 3
+    else:
+        delim = '"'
+        pos, result = parse_basic_str(src, pos, multiline=True)
+
+    # Add at maximum two extra apostrophes/quotes if the end sequence
+    # is 4 or 5 chars long instead of just 3.
+    if not src.startswith(delim, pos):
+        return pos, result
+    pos += 1
+    if not src.startswith(delim, pos):
+        return pos, result + delim
+    pos += 1
+    return pos, result + (delim * 2)
+
+
+def parse_basic_str(src: str, pos: Pos, *, multiline: bool) -> Tuple[Pos, str]:
+    if multiline:
+        error_on = ILLEGAL_MULTILINE_BASIC_STR_CHARS
+        parse_escapes = parse_basic_str_escape_multiline
+    else:
+        error_on = ILLEGAL_BASIC_STR_CHARS
+        parse_escapes = parse_basic_str_escape
+    result = ""
+    start_pos = pos
+    while True:
+        try:
+            char = src[pos]
+        except IndexError:
+            raise suffixed_err(src, pos, "Unterminated string") from None
+        if char == '"':
+            if not multiline:
+                return pos + 1, result + src[start_pos:pos]
+            if src.startswith('"""', pos):
+                return pos + 3, result + src[start_pos:pos]
+            pos += 1
+            continue
+        if char == "\\":
+            result += src[start_pos:pos]
+            pos, parsed_escape = parse_escapes(src, pos)
+            result += parsed_escape
+            start_pos = pos
+            continue
+        if char in error_on:
+            raise suffixed_err(src, pos, f"Illegal character {char!r}")
+        pos += 1
+
+
+def parse_value(  # noqa: C901
+    src: str, pos: Pos, parse_float: ParseFloat
+) -> Tuple[Pos, Any]:
+    try:
+        char: Optional[str] = src[pos]
+    except IndexError:
+        char = None
+
+    # Basic strings
+    if char == '"':
+        if src.startswith('"""', pos):
+            return parse_multiline_str(src, pos, literal=False)
+        return parse_one_line_basic_str(src, pos)
+
+    # Literal strings
+    if char == "'":
+        if src.startswith("'''", pos):
+            return parse_multiline_str(src, pos, literal=True)
+        return parse_literal_str(src, pos)
+
+    # Booleans
+    if char == "t":
+        if src.startswith("true", pos):
+            return pos + 4, True
+    if char == "f":
+        if src.startswith("false", pos):
+            return pos + 5, False
+
+    # Dates and times
+    datetime_match = RE_DATETIME.match(src, pos)
+    if datetime_match:
+        try:
+            datetime_obj = match_to_datetime(datetime_match)
+        except ValueError as e:
+            raise suffixed_err(src, pos, "Invalid date or datetime") from e
+        return datetime_match.end(), datetime_obj
+    localtime_match = RE_LOCALTIME.match(src, pos)
+    if localtime_match:
+        return localtime_match.end(), match_to_localtime(localtime_match)
+
+    # Integers and "normal" floats.
+    # The regex will greedily match any type starting with a decimal
+    # char, so needs to be located after handling of dates and times.
+    number_match = RE_NUMBER.match(src, pos)
+    if number_match:
+        return number_match.end(), match_to_number(number_match, parse_float)
+
+    # Arrays
+    if char == "[":
+        return parse_array(src, pos, parse_float)
+
+    # Inline tables
+    if char == "{":
+        return parse_inline_table(src, pos, parse_float)
+
+    # Special floats
+    first_three = src[pos : pos + 3]
+    if first_three in {"inf", "nan"}:
+        return pos + 3, parse_float(first_three)
+    first_four = src[pos : pos + 4]
+    if first_four in {"-inf", "+inf", "-nan", "+nan"}:
+        return pos + 4, parse_float(first_four)
+
+    raise suffixed_err(src, pos, "Invalid value")
+
+
+def suffixed_err(src: str, pos: Pos, msg: str) -> TOMLDecodeError:
+    """Return a `TOMLDecodeError` where error message is suffixed with
+    coordinates in source."""
+
+    def coord_repr(src: str, pos: Pos) -> str:
+        if pos >= len(src):
+            return "end of document"
+        line = src.count("\n", 0, pos) + 1
+        if line == 1:
+            column = pos + 1
+        else:
+            column = pos - src.rindex("\n", 0, pos)
+        return f"line {line}, column {column}"
+
+    return TOMLDecodeError(f"{msg} (at {coord_repr(src, pos)})")
+
+
+def is_unicode_scalar_value(codepoint: int) -> bool:
+    return (0 <= codepoint <= 55295) or (57344 <= codepoint <= 1114111)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/vendor/tomli/_re.py 
new/flit_core-3.6.0/flit_core/vendor/tomli/_re.py
--- old/flit_core-3.4.0/flit_core/vendor/tomli/_re.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/flit_core-3.6.0/flit_core/vendor/tomli/_re.py   2021-12-27 
14:04:58.927610600 +0100
@@ -0,0 +1,101 @@
+from datetime import date, datetime, time, timedelta, timezone, tzinfo
+from functools import lru_cache
+import re
+from typing import Any, Optional, Union
+
+from ._types import ParseFloat
+
+# E.g.
+# - 00:32:00.999999
+# - 00:32:00
+_TIME_RE_STR = 
r"([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(?:\.([0-9]{1,6})[0-9]*)?"
+
+RE_NUMBER = re.compile(
+    r"""
+0
+(?:
+    x[0-9A-Fa-f](?:_?[0-9A-Fa-f])*   # hex
+    |
+    b[01](?:_?[01])*                 # bin
+    |
+    o[0-7](?:_?[0-7])*               # oct
+)
+|
+[+-]?(?:0|[1-9](?:_?[0-9])*)         # dec, integer part
+(?P<floatpart>
+    (?:\.[0-9](?:_?[0-9])*)?         # optional fractional part
+    (?:[eE][+-]?[0-9](?:_?[0-9])*)?  # optional exponent part
+)
+""",
+    flags=re.VERBOSE,
+)
+RE_LOCALTIME = re.compile(_TIME_RE_STR)
+RE_DATETIME = re.compile(
+    fr"""
+([0-9]{{4}})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])  # date, e.g. 1988-10-27
+(?:
+    [Tt ]
+    {_TIME_RE_STR}
+    (?:([Zz])|([+-])([01][0-9]|2[0-3]):([0-5][0-9]))?  # optional time offset
+)?
+""",
+    flags=re.VERBOSE,
+)
+
+
+def match_to_datetime(match: "re.Match") -> Union[datetime, date]:
+    """Convert a `RE_DATETIME` match to `datetime.datetime` or `datetime.date`.
+
+    Raises ValueError if the match does not correspond to a valid date
+    or datetime.
+    """
+    (
+        year_str,
+        month_str,
+        day_str,
+        hour_str,
+        minute_str,
+        sec_str,
+        micros_str,
+        zulu_time,
+        offset_sign_str,
+        offset_hour_str,
+        offset_minute_str,
+    ) = match.groups()
+    year, month, day = int(year_str), int(month_str), int(day_str)
+    if hour_str is None:
+        return date(year, month, day)
+    hour, minute, sec = int(hour_str), int(minute_str), int(sec_str)
+    micros = int(micros_str.ljust(6, "0")) if micros_str else 0
+    if offset_sign_str:
+        tz: Optional[tzinfo] = cached_tz(
+            offset_hour_str, offset_minute_str, offset_sign_str
+        )
+    elif zulu_time:
+        tz = timezone.utc
+    else:  # local date-time
+        tz = None
+    return datetime(year, month, day, hour, minute, sec, micros, tzinfo=tz)
+
+
+@lru_cache(maxsize=None)
+def cached_tz(hour_str: str, minute_str: str, sign_str: str) -> timezone:
+    sign = 1 if sign_str == "+" else -1
+    return timezone(
+        timedelta(
+            hours=sign * int(hour_str),
+            minutes=sign * int(minute_str),
+        )
+    )
+
+
+def match_to_localtime(match: "re.Match") -> time:
+    hour_str, minute_str, sec_str, micros_str = match.groups()
+    micros = int(micros_str.ljust(6, "0")) if micros_str else 0
+    return time(int(hour_str), int(minute_str), int(sec_str), micros)
+
+
+def match_to_number(match: "re.Match", parse_float: "ParseFloat") -> Any:
+    if match.group("floatpart"):
+        return parse_float(match.group())
+    return int(match.group(), 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/vendor/tomli/_types.py 
new/flit_core-3.6.0/flit_core/vendor/tomli/_types.py
--- old/flit_core-3.4.0/flit_core/vendor/tomli/_types.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/flit_core-3.6.0/flit_core/vendor/tomli/_types.py        2021-12-27 
14:04:58.927610600 +0100
@@ -0,0 +1,6 @@
+from typing import Any, Callable, Tuple
+
+# Type annotations
+ParseFloat = Callable[[str], Any]
+Key = Tuple[str, ...]
+Pos = int
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/flit_core/vendor/tomli/py.typed 
new/flit_core-3.6.0/flit_core/vendor/tomli/py.typed
--- old/flit_core-3.4.0/flit_core/vendor/tomli/py.typed 1970-01-01 
01:00:00.000000000 +0100
+++ new/flit_core-3.6.0/flit_core/vendor/tomli/py.typed 2021-12-27 
14:04:58.927610600 +0100
@@ -0,0 +1 @@
+# Marker file for PEP 561
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/flit_core-3.4.0/flit_core/vendor/tomli-1.2.3.dist-info/LICENSE 
new/flit_core-3.6.0/flit_core/vendor/tomli-1.2.3.dist-info/LICENSE
--- old/flit_core-3.4.0/flit_core/vendor/tomli-1.2.3.dist-info/LICENSE  
1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.6.0/flit_core/vendor/tomli-1.2.3.dist-info/LICENSE  
2021-12-27 14:04:58.926610500 +0100
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Taneli Hukkinen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/flit_core-3.4.0/flit_core/vendor/tomli-1.2.3.dist-info/METADATA 
new/flit_core-3.6.0/flit_core/vendor/tomli-1.2.3.dist-info/METADATA
--- old/flit_core-3.4.0/flit_core/vendor/tomli-1.2.3.dist-info/METADATA 
1970-01-01 01:00:00.000000000 +0100
+++ new/flit_core-3.6.0/flit_core/vendor/tomli-1.2.3.dist-info/METADATA 
2021-12-27 14:04:58.926610500 +0100
@@ -0,0 +1,208 @@
+Metadata-Version: 2.1
+Name: tomli
+Version: 1.2.3
+Summary: A lil' TOML parser
+Keywords: toml
+Author-email: Taneli Hukkinen <[email protected]>
+Requires-Python: >=3.6
+Description-Content-Type: text/markdown
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: MacOS
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Typing :: Typed
+Project-URL: Changelog, 
https://github.com/hukkin/tomli/blob/master/CHANGELOG.md
+Project-URL: Homepage, https://github.com/hukkin/tomli
+
+[![Build 
Status](https://github.com/hukkin/tomli/workflows/Tests/badge.svg?branch=master)](https://github.com/hukkin/tomli/actions?query=workflow%3ATests+branch%3Amaster+event%3Apush)
+[![codecov.io](https://codecov.io/gh/hukkin/tomli/branch/master/graph/badge.svg)](https://codecov.io/gh/hukkin/tomli)
+[![PyPI 
version](https://img.shields.io/pypi/v/tomli)](https://pypi.org/project/tomli)
+
+# Tomli
+
+> A lil' TOML parser
+
+**Table of Contents**  *generated with 
[mdformat-toc](https://github.com/hukkin/mdformat-toc)*
+
+<!-- mdformat-toc start --slug=github --maxlevel=6 --minlevel=2 -->
+
+- [Intro](#intro)
+- [Installation](#installation)
+- [Usage](#usage)
+  - [Parse a TOML string](#parse-a-toml-string)
+  - [Parse a TOML file](#parse-a-toml-file)
+  - [Handle invalid TOML](#handle-invalid-toml)
+  - [Construct `decimal.Decimal`s from TOML 
floats](#construct-decimaldecimals-from-toml-floats)
+- [FAQ](#faq)
+  - [Why this parser?](#why-this-parser)
+  - [Is comment preserving round-trip parsing 
supported?](#is-comment-preserving-round-trip-parsing-supported)
+  - [Is there a `dumps`, `write` or `encode` 
function?](#is-there-a-dumps-write-or-encode-function)
+  - [How do TOML types map into Python 
types?](#how-do-toml-types-map-into-python-types)
+- [Performance](#performance)
+
+<!-- mdformat-toc end -->
+
+## Intro<a name="intro"></a>
+
+Tomli is a Python library for parsing [TOML](https://toml.io).
+Tomli is fully compatible with [TOML v1.0.0](https://toml.io/en/v1.0.0).
+
+## Installation<a name="installation"></a>
+
+```bash
+pip install tomli
+```
+
+## Usage<a name="usage"></a>
+
+### Parse a TOML string<a name="parse-a-toml-string"></a>
+
+```python
+import tomli
+
+toml_str = """
+           gretzky = 99
+
+           [kurri]
+           jari = 17
+           """
+
+toml_dict = tomli.loads(toml_str)
+assert toml_dict == {"gretzky": 99, "kurri": {"jari": 17}}
+```
+
+### Parse a TOML file<a name="parse-a-toml-file"></a>
+
+```python
+import tomli
+
+with open("path_to_file/conf.toml", "rb") as f:
+    toml_dict = tomli.load(f)
+```
+
+The file must be opened in binary mode (with the `"rb"` flag).
+Binary mode will enforce decoding the file as UTF-8 with universal newlines 
disabled,
+both of which are required to correctly parse TOML.
+Support for text file objects is deprecated for removal in the next major 
release.
+
+### Handle invalid TOML<a name="handle-invalid-toml"></a>
+
+```python
+import tomli
+
+try:
+    toml_dict = tomli.loads("]] this is invalid TOML [[")
+except tomli.TOMLDecodeError:
+    print("Yep, definitely not valid.")
+```
+
+Note that while the `TOMLDecodeError` type is public API, error messages of 
raised instances of it are not.
+Error messages should not be assumed to stay constant across Tomli versions.
+
+### Construct `decimal.Decimal`s from TOML floats<a 
name="construct-decimaldecimals-from-toml-floats"></a>
+
+```python
+from decimal import Decimal
+import tomli
+
+toml_dict = tomli.loads("precision-matters = 0.982492", parse_float=Decimal)
+assert toml_dict["precision-matters"] == Decimal("0.982492")
+```
+
+Note that `decimal.Decimal` can be replaced with another callable that 
converts a TOML float from string to a Python type.
+The `decimal.Decimal` is, however, a practical choice for use cases where 
float inaccuracies can not be tolerated.
+
+Illegal types include `dict`, `list`, and anything that has the `append` 
attribute.
+Parsing floats into an illegal type results in undefined behavior.
+
+## FAQ<a name="faq"></a>
+
+### Why this parser?<a name="why-this-parser"></a>
+
+- it's lil'
+- pure Python with zero dependencies
+- the fastest pure Python parser [\*](#performance):
+  15x as fast as [tomlkit](https://pypi.org/project/tomlkit/),
+  2.4x as fast as [toml](https://pypi.org/project/toml/)
+- outputs [basic data types](#how-do-toml-types-map-into-python-types) only
+- 100% spec compliant: passes all tests in
+  [a test set](https://github.com/toml-lang/compliance/pull/8)
+  soon to be merged to the official
+  [compliance tests for TOML](https://github.com/toml-lang/compliance)
+  repository
+- thoroughly tested: 100% branch coverage
+
+### Is comment preserving round-trip parsing supported?<a 
name="is-comment-preserving-round-trip-parsing-supported"></a>
+
+No.
+
+The `tomli.loads` function returns a plain `dict` that is populated with 
builtin types and types from the standard library only.
+Preserving comments requires a custom type to be returned so will not be 
supported,
+at least not by the `tomli.loads` and `tomli.load` functions.
+
+Look into [TOML Kit](https://github.com/sdispater/tomlkit) if preservation of 
style is what you need.
+
+### Is there a `dumps`, `write` or `encode` function?<a 
name="is-there-a-dumps-write-or-encode-function"></a>
+
+[Tomli-W](https://github.com/hukkin/tomli-w) is the write-only counterpart of 
Tomli, providing `dump` and `dumps` functions.
+
+The core library does not include write capability, as most TOML use cases are 
read-only, and Tomli intends to be minimal.
+
+### How do TOML types map into Python types?<a 
name="how-do-toml-types-map-into-python-types"></a>
+
+| TOML type        | Python type         | Details                             
                         |
+| ---------------- | ------------------- | 
------------------------------------------------------------ |
+| Document Root    | `dict`              |                                     
                         |
+| Key              | `str`               |                                     
                         |
+| String           | `str`               |                                     
                         |
+| Integer          | `int`               |                                     
                         |
+| Float            | `float`             |                                     
                         |
+| Boolean          | `bool`              |                                     
                         |
+| Offset Date-Time | `datetime.datetime` | `tzinfo` attribute set to an 
instance of `datetime.timezone` |
+| Local Date-Time  | `datetime.datetime` | `tzinfo` attribute set to `None`    
                         |
+| Local Date       | `datetime.date`     |                                     
                         |
+| Local Time       | `datetime.time`     |                                     
                         |
+| Array            | `list`              |                                     
                         |
+| Table            | `dict`              |                                     
                         |
+| Inline Table     | `dict`              |                                     
                         |
+
+## Performance<a name="performance"></a>
+
+The `benchmark/` folder in this repository contains a performance benchmark 
for comparing the various Python TOML parsers.
+The benchmark can be run with `tox -e benchmark-pypi`.
+Running the benchmark on my personal computer output the following:
+
+```console
+foo@bar:~/dev/tomli$ tox -e benchmark-pypi
+benchmark-pypi installed: 
attrs==19.3.0,click==7.1.2,pytomlpp==1.0.2,qtoml==0.3.0,rtoml==0.7.0,toml==0.10.2,tomli==1.1.0,tomlkit==0.7.2
+benchmark-pypi run-test-pre: PYTHONHASHSEED='2658546909'
+benchmark-pypi run-test: commands[0] | python -c 'import datetime; 
print(datetime.date.today())'
+2021-07-23
+benchmark-pypi run-test: commands[1] | python --version
+Python 3.8.10
+benchmark-pypi run-test: commands[2] | python benchmark/run.py
+Parsing data.toml 5000 times:
+------------------------------------------------------
+    parser |  exec time | performance (more is better)
+-----------+------------+-----------------------------
+     rtoml |    0.901 s | baseline (100%)
+  pytomlpp |     1.08 s | 83.15%
+     tomli |     3.89 s | 23.15%
+      toml |     9.36 s | 9.63%
+     qtoml |     11.5 s | 7.82%
+   tomlkit |     56.8 s | 1.59%
+```
+
+The parsers are ordered from fastest to slowest, using the fastest parser as 
baseline.
+Tomli performed the best out of all pure Python TOML parsers,
+losing only to pytomlpp (wraps C++) and rtoml (wraps Rust).
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/flit_core-3.4.0/pyproject.toml 
new/flit_core-3.6.0/pyproject.toml
--- old/flit_core-3.4.0/pyproject.toml  2021-05-09 17:40:19.109348300 +0200
+++ new/flit_core-3.6.0/pyproject.toml  2021-12-27 14:04:58.928610600 +0100
@@ -1,4 +1,21 @@
 [build-system]
 requires = []
-build-backend = "flit_core.build_thyself"
+build-backend = "flit_core.buildapi"
 backend-path = ["."]
+
+[project]
+name="flit_core"
+authors=[
+    {name = "Thomas Kluyver & contributors", email = "[email protected]"},
+]
+description = "Distribution-building parts of Flit. See flit package for more 
information"
+dependencies = []
+requires-python = '>=3.6'
+classifiers = [
+    "License :: OSI Approved :: BSD License",
+    "Topic :: Software Development :: Libraries :: Python Modules",
+]
+dynamic = ["version"]
+
+[project.urls]
+Source = "https://github.com/pypa/flit";

Reply via email to