Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-importlib-metadata for 
openSUSE:Factory checked in at 2023-04-16 16:06:41
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-importlib-metadata (Old)
 and      /work/SRC/openSUSE:Factory/.python-importlib-metadata.new.19717 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-importlib-metadata"

Sun Apr 16 16:06:41 2023 rev:18 rq:1079571 version:6.3.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-importlib-metadata/python-importlib-metadata.changes
      2023-04-04 21:16:58.847874613 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-importlib-metadata.new.19717/python-importlib-metadata.changes
   2023-04-16 16:06:45.844709325 +0200
@@ -1,0 +2,12 @@
+Sat Apr 15 10:16:48 UTC 2023 - Dirk Müller <dmuel...@suse.com>
+
+- update to 6.3.0:
+  * #115: Support ``installed-files.txt`` for
+    ``Distribution.files`` when present.
+  * #442: Fixed issue introduced in v6.1.0 where non-importable
+  * names (metadata dirs) began appearing in ``packages_distributions``.
+  * #384: ``PackageMetadata`` now stipulates an additional
+    ``get`` method allowing for easy querying of metadata keys that may
+    not be present
+
+-------------------------------------------------------------------

Old:
----
  importlib_metadata-6.1.0.tar.gz

New:
----
  importlib_metadata-6.3.0.tar.gz

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

Other differences:
------------------
++++++ python-importlib-metadata.spec ++++++
--- /var/tmp/diff_new_pack.dcZrDv/_old  2023-04-16 16:06:46.352712253 +0200
+++ /var/tmp/diff_new_pack.dcZrDv/_new  2023-04-16 16:06:46.356712276 +0200
@@ -27,7 +27,7 @@
 %{?!python_module:%define python_module() python3-%{**}}
 %define skip_python2 1
 Name:           python-importlib-metadata%{psuffix}
-Version:        6.1.0
+Version:        6.3.0
 Release:        0
 Summary:        Read metadata from Python packages
 License:        Apache-2.0

++++++ importlib_metadata-6.1.0.tar.gz -> importlib_metadata-6.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/importlib_metadata-6.1.0/.github/workflows/main.yml 
new/importlib_metadata-6.3.0/.github/workflows/main.yml
--- old/importlib_metadata-6.1.0/.github/workflows/main.yml     2023-03-18 
18:10:20.000000000 +0100
+++ new/importlib_metadata-6.3.0/.github/workflows/main.yml     2023-04-10 
04:27:13.000000000 +0200
@@ -2,6 +2,9 @@
 
 on: [push, pull_request]
 
+permissions:
+  contents: read
+
 env:
   # Environment variables to support color support (jaraco/skeleton#66):
   # Request colored output from CLI tools supporting it. Different tools
@@ -130,6 +133,8 @@
           TOXENV: diffcov
 
   release:
+    permissions:
+      contents: write
     needs:
     - check
     if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/importlib_metadata-6.1.0/CHANGES.rst 
new/importlib_metadata-6.3.0/CHANGES.rst
--- old/importlib_metadata-6.1.0/CHANGES.rst    2023-03-18 18:10:20.000000000 
+0100
+++ new/importlib_metadata-6.3.0/CHANGES.rst    2023-04-10 04:27:13.000000000 
+0200
@@ -1,3 +1,23 @@
+v6.3.0
+======
+
+* #115: Support ``installed-files.txt`` for ``Distribution.files``
+  when present.
+
+v6.2.1
+======
+
+* #442: Fixed issue introduced in v6.1.0 where non-importable
+  names (metadata dirs) began appearing in
+  ``packages_distributions``.
+
+v6.2.0
+======
+
+* #384: ``PackageMetadata`` now stipulates an additional ``get``
+  method allowing for easy querying of metadata keys that may not
+  be present.
+
 v6.1.0
 ======
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/importlib_metadata-6.1.0/PKG-INFO 
new/importlib_metadata-6.3.0/PKG-INFO
--- old/importlib_metadata-6.1.0/PKG-INFO       2023-03-18 18:10:38.770994400 
+0100
+++ new/importlib_metadata-6.3.0/PKG-INFO       2023-04-10 04:27:32.096812500 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: importlib_metadata
-Version: 6.1.0
+Version: 6.3.0
 Summary: Read metadata from Python packages
 Home-page: https://github.com/python/importlib_metadata
 Author: Jason R. Coombs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/importlib_metadata-6.1.0/importlib_metadata/__init__.py 
new/importlib_metadata-6.3.0/importlib_metadata/__init__.py
--- old/importlib_metadata-6.1.0/importlib_metadata/__init__.py 2023-03-18 
18:10:20.000000000 +0100
+++ new/importlib_metadata-6.3.0/importlib_metadata/__init__.py 2023-04-10 
04:27:13.000000000 +0200
@@ -12,6 +12,7 @@
 import functools
 import itertools
 import posixpath
+import contextlib
 import collections
 import inspect
 
@@ -461,8 +462,8 @@
         :return: List of PackagePath for this distribution or None
 
         Result is `None` if the metadata file that enumerates files
-        (i.e. RECORD for dist-info or SOURCES.txt for egg-info) is
-        missing.
+        (i.e. RECORD for dist-info, or installed-files.txt or
+        SOURCES.txt for egg-info) is missing.
         Result may be empty if the metadata exists but is empty.
         """
 
@@ -475,9 +476,19 @@
 
         @pass_none
         def make_files(lines):
-            return list(starmap(make_file, csv.reader(lines)))
+            return starmap(make_file, csv.reader(lines))
 
-        return make_files(self._read_files_distinfo() or 
self._read_files_egginfo())
+        @pass_none
+        def skip_missing_files(package_paths):
+            return list(filter(lambda path: path.locate().exists(), 
package_paths))
+
+        return skip_missing_files(
+            make_files(
+                self._read_files_distinfo()
+                or self._read_files_egginfo_installed()
+                or self._read_files_egginfo_sources()
+            )
+        )
 
     def _read_files_distinfo(self):
         """
@@ -486,10 +497,43 @@
         text = self.read_text('RECORD')
         return text and text.splitlines()
 
-    def _read_files_egginfo(self):
+    def _read_files_egginfo_installed(self):
         """
-        SOURCES.txt might contain literal commas, so wrap each line
-        in quotes.
+        Read installed-files.txt and return lines in a similar
+        CSV-parsable format as RECORD: each file must be placed
+        relative to the site-packages directory, and must also be
+        quoted (since file names can contain literal commas).
+
+        This file is written when the package is installed by pip,
+        but it might not be written for other installation methods.
+        Hence, even if we can assume that this file is accurate
+        when it exists, we cannot assume that it always exists.
+        """
+        text = self.read_text('installed-files.txt')
+        # We need to prepend the .egg-info/ subdir to the lines in this file.
+        # But this subdir is only available in the PathDistribution's 
self._path
+        # which is not easily accessible from this base class...
+        subdir = getattr(self, '_path', None)
+        if not text or not subdir:
+            return
+        with contextlib.suppress(Exception):
+            ret = [
+                str((subdir / 
line).resolve().relative_to(self.locate_file('')))
+                for line in text.splitlines()
+            ]
+            return map('"{}"'.format, ret)
+
+    def _read_files_egginfo_sources(self):
+        """
+        Read SOURCES.txt and return lines in a similar CSV-parsable
+        format as RECORD: each file name must be quoted (since it
+        might contain literal commas).
+
+        Note that SOURCES.txt is not a reliable source for what
+        files are installed by a package. This file is generated
+        for a source archive, and the files that are present
+        there (e.g. setup.py) may not correctly reflect the files
+        that are present after the package has been installed.
         """
         text = self.read_text('SOURCES.txt')
         return text and map('"{}"'.format, text.splitlines())
@@ -902,4 +946,9 @@
         f.parts[0] if len(f.parts) > 1 else inspect.getmodulename(f)
         for f in always_iterable(dist.files)
     }
-    return filter(None, opt_names)
+
+    @pass_none
+    def importable_name(name):
+        return '.' not in name
+
+    return filter(importable_name, opt_names)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/importlib_metadata-6.1.0/importlib_metadata/_meta.py 
new/importlib_metadata-6.3.0/importlib_metadata/_meta.py
--- old/importlib_metadata-6.1.0/importlib_metadata/_meta.py    2023-03-18 
18:10:20.000000000 +0100
+++ new/importlib_metadata-6.3.0/importlib_metadata/_meta.py    2023-04-10 
04:27:13.000000000 +0200
@@ -18,6 +18,14 @@
     def __iter__(self) -> Iterator[str]:
         ...  # pragma: no cover
 
+    @overload
+    def get(self, name: str, failobj: None = None) -> Optional[str]:
+        ...  # pragma: no cover
+
+    @overload
+    def get(self, name: str, failobj: _T) -> Union[str, _T]:
+        ...  # pragma: no cover
+
     # overload per python/importlib_metadata#435
     @overload
     def get_all(self, name: str, failobj: None = None) -> Optional[List[Any]]:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/importlib_metadata-6.1.0/importlib_metadata.egg-info/PKG-INFO 
new/importlib_metadata-6.3.0/importlib_metadata.egg-info/PKG-INFO
--- old/importlib_metadata-6.1.0/importlib_metadata.egg-info/PKG-INFO   
2023-03-18 18:10:38.000000000 +0100
+++ new/importlib_metadata-6.3.0/importlib_metadata.egg-info/PKG-INFO   
2023-04-10 04:27:32.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: importlib-metadata
-Version: 6.1.0
+Version: 6.3.0
 Summary: Read metadata from Python packages
 Home-page: https://github.com/python/importlib_metadata
 Author: Jason R. Coombs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/importlib_metadata-6.1.0/importlib_metadata.egg-info/SOURCES.txt 
new/importlib_metadata-6.3.0/importlib_metadata.egg-info/SOURCES.txt
--- old/importlib_metadata-6.1.0/importlib_metadata.egg-info/SOURCES.txt        
2023-03-18 18:10:38.000000000 +0100
+++ new/importlib_metadata-6.3.0/importlib_metadata.egg-info/SOURCES.txt        
2023-04-10 04:27:32.000000000 +0200
@@ -44,6 +44,7 @@
 prepare/example2/pyproject.toml
 prepare/example2/example2/__init__.py
 tests/__init__.py
+tests/_path.py
 tests/fixtures.py
 tests/py39compat.py
 tests/test_api.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/importlib_metadata-6.1.0/tests/_path.py 
new/importlib_metadata-6.3.0/tests/_path.py
--- old/importlib_metadata-6.1.0/tests/_path.py 1970-01-01 01:00:00.000000000 
+0100
+++ new/importlib_metadata-6.3.0/tests/_path.py 2023-04-10 04:27:13.000000000 
+0200
@@ -0,0 +1,104 @@
+# from jaraco.path 3.5
+
+import functools
+import pathlib
+from typing import Dict, Union
+
+try:
+    from typing import Protocol, runtime_checkable
+except ImportError:  # pragma: no cover
+    # Python 3.7
+    from typing_extensions import Protocol, runtime_checkable  # type: ignore
+
+
+FilesSpec = Dict[str, Union[str, bytes, 'FilesSpec']]  # type: ignore
+
+
+@runtime_checkable
+class TreeMaker(Protocol):
+    def __truediv__(self, *args, **kwargs):
+        ...  # pragma: no cover
+
+    def mkdir(self, **kwargs):
+        ...  # pragma: no cover
+
+    def write_text(self, content, **kwargs):
+        ...  # pragma: no cover
+
+    def write_bytes(self, content):
+        ...  # pragma: no cover
+
+
+def _ensure_tree_maker(obj: Union[str, TreeMaker]) -> TreeMaker:
+    return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj)  # type: 
ignore
+
+
+def build(
+    spec: FilesSpec,
+    prefix: Union[str, TreeMaker] = pathlib.Path(),  # type: ignore
+):
+    """
+    Build a set of files/directories, as described by the spec.
+
+    Each key represents a pathname, and the value represents
+    the content. Content may be a nested directory.
+
+    >>> spec = {
+    ...     'README.txt': "A README file",
+    ...     "foo": {
+    ...         "__init__.py": "",
+    ...         "bar": {
+    ...             "__init__.py": "",
+    ...         },
+    ...         "baz.py": "# Some code",
+    ...     }
+    ... }
+    >>> target = getfixture('tmp_path')
+    >>> build(spec, target)
+    >>> target.joinpath('foo/baz.py').read_text(encoding='utf-8')
+    '# Some code'
+    """
+    for name, contents in spec.items():
+        create(contents, _ensure_tree_maker(prefix) / name)
+
+
+@functools.singledispatch
+def create(content: Union[str, bytes, FilesSpec], path):
+    path.mkdir(exist_ok=True)
+    build(content, prefix=path)  # type: ignore
+
+
+@create.register
+def _(content: bytes, path):
+    path.write_bytes(content)
+
+
+@create.register
+def _(content: str, path):
+    path.write_text(content, encoding='utf-8')
+
+
+class Recording:
+    """
+    A TreeMaker object that records everything that would be written.
+
+    >>> r = Recording()
+    >>> build({'foo': {'foo1.txt': 'yes'}, 'bar.txt': 'abc'}, r)
+    >>> r.record
+    ['foo/foo1.txt', 'bar.txt']
+    """
+
+    def __init__(self, loc=pathlib.PurePosixPath(), record=None):
+        self.loc = loc
+        self.record = record if record is not None else []
+
+    def __truediv__(self, other):
+        return Recording(self.loc / other, self.record)
+
+    def write_text(self, content, **kwargs):
+        self.record.append(str(self.loc))
+
+    write_bytes = write_text
+
+    def mkdir(self, **kwargs):
+        return
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/importlib_metadata-6.1.0/tests/fixtures.py 
new/importlib_metadata-6.3.0/tests/fixtures.py
--- old/importlib_metadata-6.1.0/tests/fixtures.py      2023-03-18 
18:10:20.000000000 +0100
+++ new/importlib_metadata-6.3.0/tests/fixtures.py      2023-04-10 
04:27:13.000000000 +0200
@@ -11,6 +11,9 @@
 from .py39compat import FS_NONASCII
 from typing import Dict, Union
 
+from . import _path
+
+
 try:
     from importlib import resources  # type: ignore
 
@@ -83,8 +86,10 @@
 
 
 # Except for python/mypy#731, prefer to define
-# FilesDef = Dict[str, Union['FilesDef', str]]
-FilesDef = Dict[str, Union[Dict[str, Union[Dict[str, str], str]], str]]
+# FilesDef = Dict[str, Union['FilesDef', str, bytes]]
+FilesDef = Dict[
+    str, Union[Dict[str, Union[Dict[str, Union[str, bytes]], str, bytes]], 
str, bytes]
+]
 
 
 class DistInfoPkg(OnSysPath, SiteDir):
@@ -211,6 +216,97 @@
         build_files(EggInfoPkg.files, prefix=self.site_dir)
 
 
+class EggInfoPkgPipInstalledNoToplevel(OnSysPath, SiteDir):
+    files: FilesDef = {
+        "egg_with_module_pkg.egg-info": {
+            "PKG-INFO": "Name: egg_with_module-pkg",
+            # SOURCES.txt is made from the source archive, and contains files
+            # (setup.py) that are not present after installation.
+            "SOURCES.txt": """
+                egg_with_module.py
+                setup.py
+                egg_with_module_pkg.egg-info/PKG-INFO
+                egg_with_module_pkg.egg-info/SOURCES.txt
+                egg_with_module_pkg.egg-info/top_level.txt
+            """,
+            # installed-files.txt is written by pip, and is a strictly more
+            # accurate source than SOURCES.txt as to the installed contents of
+            # the package.
+            "installed-files.txt": """
+                ../egg_with_module.py
+                PKG-INFO
+                SOURCES.txt
+                top_level.txt
+            """,
+            # missing top_level.txt (to trigger fallback to 
installed-files.txt)
+        },
+        "egg_with_module.py": """
+            def main():
+                print("hello world")
+            """,
+    }
+
+    def setUp(self):
+        super().setUp()
+        build_files(EggInfoPkgPipInstalledNoToplevel.files, 
prefix=self.site_dir)
+
+
+class EggInfoPkgPipInstalledNoModules(OnSysPath, SiteDir):
+    files: FilesDef = {
+        "egg_with_no_modules_pkg.egg-info": {
+            "PKG-INFO": "Name: egg_with_no_modules-pkg",
+            # SOURCES.txt is made from the source archive, and contains files
+            # (setup.py) that are not present after installation.
+            "SOURCES.txt": """
+                setup.py
+                egg_with_no_modules_pkg.egg-info/PKG-INFO
+                egg_with_no_modules_pkg.egg-info/SOURCES.txt
+                egg_with_no_modules_pkg.egg-info/top_level.txt
+            """,
+            # installed-files.txt is written by pip, and is a strictly more
+            # accurate source than SOURCES.txt as to the installed contents of
+            # the package.
+            "installed-files.txt": """
+                PKG-INFO
+                SOURCES.txt
+                top_level.txt
+            """,
+            # top_level.txt correctly reflects that no modules are installed
+            "top_level.txt": b"\n",
+        },
+    }
+
+    def setUp(self):
+        super().setUp()
+        build_files(EggInfoPkgPipInstalledNoModules.files, 
prefix=self.site_dir)
+
+
+class EggInfoPkgSourcesFallback(OnSysPath, SiteDir):
+    files: FilesDef = {
+        "sources_fallback_pkg.egg-info": {
+            "PKG-INFO": "Name: sources_fallback-pkg",
+            # SOURCES.txt is made from the source archive, and contains files
+            # (setup.py) that are not present after installation.
+            "SOURCES.txt": """
+                sources_fallback.py
+                setup.py
+                sources_fallback_pkg.egg-info/PKG-INFO
+                sources_fallback_pkg.egg-info/SOURCES.txt
+            """,
+            # missing installed-files.txt (i.e. not installed by pip) and
+            # missing top_level.txt (to trigger fallback to SOURCES.txt)
+        },
+        "sources_fallback.py": """
+            def main():
+                print("hello world")
+            """,
+    }
+
+    def setUp(self):
+        super().setUp()
+        build_files(EggInfoPkgSourcesFallback.files, prefix=self.site_dir)
+
+
 class EggInfoFile(OnSysPath, SiteDir):
     files: FilesDef = {
         "egginfo_file.egg-info": """
@@ -266,6 +362,16 @@
                     f.write(DALS(contents))
 
 
+def build_record(file_defs):
+    return ''.join(f'{name},,\n' for name in record_names(file_defs))
+
+
+def record_names(file_defs):
+    recording = _path.Recording()
+    _path.build(file_defs, recording)
+    return recording.record
+
+
 class FileBuilder:
     def unicode_filename(self):
         return FS_NONASCII or self.skip("File system does not support 
non-ascii.")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/importlib_metadata-6.1.0/tests/test_api.py 
new/importlib_metadata-6.3.0/tests/test_api.py
--- old/importlib_metadata-6.1.0/tests/test_api.py      2023-03-18 
18:10:20.000000000 +0100
+++ new/importlib_metadata-6.3.0/tests/test_api.py      2023-04-10 
04:27:13.000000000 +0200
@@ -27,6 +27,9 @@
 
 class APITests(
     fixtures.EggInfoPkg,
+    fixtures.EggInfoPkgPipInstalledNoToplevel,
+    fixtures.EggInfoPkgPipInstalledNoModules,
+    fixtures.EggInfoPkgSourcesFallback,
     fixtures.DistInfoPkg,
     fixtures.DistInfoPkgWithDot,
     fixtures.EggInfoFile,
@@ -62,15 +65,28 @@
                     distribution(prefix)
 
     def test_for_top_level(self):
-        self.assertEqual(
-            distribution('egginfo-pkg').read_text('top_level.txt').strip(), 
'mod'
-        )
+        tests = [
+            ('egginfo-pkg', 'mod'),
+            ('egg_with_no_modules-pkg', ''),
+        ]
+        for pkg_name, expect_content in tests:
+            with self.subTest(pkg_name):
+                self.assertEqual(
+                    distribution(pkg_name).read_text('top_level.txt').strip(),
+                    expect_content,
+                )
 
     def test_read_text(self):
-        top_level = [
-            path for path in files('egginfo-pkg') if path.name == 
'top_level.txt'
-        ][0]
-        self.assertEqual(top_level.read_text(), 'mod\n')
+        tests = [
+            ('egginfo-pkg', 'mod\n'),
+            ('egg_with_no_modules-pkg', '\n'),
+        ]
+        for pkg_name, expect_content in tests:
+            with self.subTest(pkg_name):
+                top_level = [
+                    path for path in files(pkg_name) if path.name == 
'top_level.txt'
+                ][0]
+                self.assertEqual(top_level.read_text(), expect_content)
 
     def test_entry_points(self):
         eps = entry_points()
@@ -148,6 +164,20 @@
         with suppress_known_deprecation():
             assert md['does-not-exist'] is None
 
+    def test_get_key(self):
+        """
+        Getting a key gets the key.
+        """
+        md = metadata('egginfo-pkg')
+        assert md.get('Name') == 'egginfo-pkg'
+
+    def test_get_missing_key(self):
+        """
+        Requesting a missing key will return None.
+        """
+        md = metadata('distinfo-pkg')
+        assert md.get('does-not-exist') is None
+
     @staticmethod
     def _test_files(files):
         root = files[0].root
@@ -170,6 +200,9 @@
 
     def test_files_egg_info(self):
         self._test_files(files('egginfo-pkg'))
+        self._test_files(files('egg_with_module-pkg'))
+        self._test_files(files('egg_with_no_modules-pkg'))
+        self._test_files(files('sources_fallback-pkg'))
 
     def test_version_egg_info_file(self):
         self.assertEqual(version('egginfo-file'), '0.1')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/importlib_metadata-6.1.0/tests/test_main.py 
new/importlib_metadata-6.3.0/tests/test_main.py
--- old/importlib_metadata-6.1.0/tests/test_main.py     2023-03-18 
18:10:20.000000000 +0100
+++ new/importlib_metadata-6.3.0/tests/test_main.py     2023-04-10 
04:27:13.000000000 +0200
@@ -3,6 +3,7 @@
 import unittest
 import importlib
 import importlib_metadata
+import itertools
 import pyfakefs.fake_filesystem_unittest as ffs
 
 from . import fixtures
@@ -170,11 +171,21 @@
         assert meta['Description'] == 'pôrˈtend'
 
 
-class DiscoveryTests(fixtures.EggInfoPkg, fixtures.DistInfoPkg, 
unittest.TestCase):
+class DiscoveryTests(
+    fixtures.EggInfoPkg,
+    fixtures.EggInfoPkgPipInstalledNoToplevel,
+    fixtures.EggInfoPkgPipInstalledNoModules,
+    fixtures.EggInfoPkgSourcesFallback,
+    fixtures.DistInfoPkg,
+    unittest.TestCase,
+):
     def test_package_discovery(self):
         dists = list(distributions())
         assert all(isinstance(dist, Distribution) for dist in dists)
         assert any(dist.metadata['Name'] == 'egginfo-pkg' for dist in dists)
+        assert any(dist.metadata['Name'] == 'egg_with_module-pkg' for dist in 
dists)
+        assert any(dist.metadata['Name'] == 'egg_with_no_modules-pkg' for dist 
in dists)
+        assert any(dist.metadata['Name'] == 'sources_fallback-pkg' for dist in 
dists)
         assert any(dist.metadata['Name'] == 'distinfo-pkg' for dist in dists)
 
     def test_invalid_usage(self):
@@ -328,28 +339,73 @@
         Test top-level modules detected on a package without 'top-level.txt'.
         """
         suffixes = importlib.machinery.all_suffixes()
-        fixtures.build_files(
-            {
-                'all_distributions-1.0.0.dist-info': {
-                    'METADATA': """
-                        Name: all_distributions
-                        Version: 1.0.0
-                    """,
-                    'RECORD': ''.join(
-                        f'{i}-top-level{suffix},,\n'
-                        f'{i}-in-namespace/mod{suffix},,\n'
-                        f'{i}-in-package/__init__.py,,\n'
-                        f'{i}-in-package/mod{suffix},,\n'
-                        for i, suffix in enumerate(suffixes)
-                    ),
-                },
-            },
-            prefix=self.site_dir,
+        metadata = dict(
+            METADATA="""
+                Name: all_distributions
+                Version: 1.0.0
+                """,
         )
+        files = {
+            'all_distributions-1.0.0.dist-info': metadata,
+        }
+        for i, suffix in enumerate(suffixes):
+            files.update(
+                {
+                    f'importable-name {i}{suffix}': '',
+                    f'in_namespace_{i}': {
+                        f'mod{suffix}': '',
+                    },
+                    f'in_package_{i}': {
+                        '__init__.py': '',
+                        f'mod{suffix}': '',
+                    },
+                }
+            )
+        metadata.update(RECORD=fixtures.build_record(files))
+        fixtures.build_files(files, prefix=self.site_dir)
 
         distributions = packages_distributions()
 
         for i in range(len(suffixes)):
-            assert distributions[f'{i}-top-level'] == ['all_distributions']
-            assert distributions[f'{i}-in-namespace'] == ['all_distributions']
-            assert distributions[f'{i}-in-package'] == ['all_distributions']
+            assert distributions[f'importable-name {i}'] == 
['all_distributions']
+            assert distributions[f'in_namespace_{i}'] == ['all_distributions']
+            assert distributions[f'in_package_{i}'] == ['all_distributions']
+
+        assert not any(name.endswith('.dist-info') for name in distributions)
+
+
+class PackagesDistributionsEggTest(
+    fixtures.EggInfoPkg,
+    fixtures.EggInfoPkgPipInstalledNoToplevel,
+    fixtures.EggInfoPkgPipInstalledNoModules,
+    fixtures.EggInfoPkgSourcesFallback,
+    unittest.TestCase,
+):
+    def test_packages_distributions_on_eggs(self):
+        """
+        Test old-style egg packages with a variation of 'top_level.txt',
+        'SOURCES.txt', and 'installed-files.txt', available.
+        """
+        distributions = packages_distributions()
+
+        def import_names_from_package(package_name):
+            return {
+                import_name
+                for import_name, package_names in distributions.items()
+                if package_name in package_names
+            }
+
+        # egginfo-pkg declares one import ('mod') via top_level.txt
+        assert import_names_from_package('egginfo-pkg') == {'mod'}
+
+        # egg_with_module-pkg has one import ('egg_with_module') inferred from
+        # installed-files.txt (top_level.txt is missing)
+        assert import_names_from_package('egg_with_module-pkg') == 
{'egg_with_module'}
+
+        # egg_with_no_modules-pkg should not be associated with any import 
names
+        # (top_level.txt is empty, and installed-files.txt has no .py files)
+        assert import_names_from_package('egg_with_no_modules-pkg') == set()
+
+        # sources_fallback-pkg has one import ('sources_fallback') inferred 
from
+        # SOURCES.txt (top_level.txt and installed-files.txt is missing)
+        assert import_names_from_package('sources_fallback-pkg') == 
{'sources_fallback'}

Reply via email to