Repository: pypa/pip

Issue:
Bad metadata: TypeError: expected string or bytes-like object, got 'NoneType'
### Description

Since pip 22, several Fedora Rawhide users reported the following problem for many (all?) pip commands:

```
      File "/usr/lib/python3.11/site-packages/pip/_internal/metadata/base.py", line 604, in 
iter_all_distributions
        for dist in self._iter_distributions():
      File "/usr/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py", line 167, in _iter_distributions
        yield from finder.find(location)
      File "/usr/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py", line 71, in find
        for dist, info_location in self._find_impl(location):
      File "/usr/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py", line 59, in _find_impl
        normalized_name = canonicalize_name(get_dist_name(dist))
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/usr/lib/python3.11/site-packages/pip/_vendor/packaging/utils.py", line 34, in canonicalize_name
        value = _canonicalize_regex.sub("-", name).lower()
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    TypeError: expected string or bytes-like object, got 'NoneType'
```

I could not reproduce at first, but after investigation, @encukou figured out that this works as a repducer:

```
# mkdir /usr/lib/python3.11/site-packages/bad.dist-info
# python3 -m pip list
...
TypeError: expected string or bytes-like object, got 'NoneType'
```

This is not Fedora-pip specific, I can reproduce it in the official python:3.11.0b5 container (see the reproducer below).

This happens with pip-22.2.2, pip-22.2.

This does not happen with pip-21.3.1.

This does not seem to happen with Python 3.10.

**I suspect this is related to the switch to importlib metadata.**

### Expected behavior

This is how it worked before:

```
# mkdir /usr/local/lib/python3.11/site-packages/bad.dist-info
# python3 -m pip list
Package    Version
---------- -------
pip        21.3.1
setuptools 63.2.0
wheel      0.37.1
```

### pip version

22.2.2

### Python version

3.11.0b5

### OS

Linux

### How to Reproduce

```
$ podman run --rm -ti python:3.11.0b5 /bin/bash
# mkdir /usr/local/lib/python3.11/site-packages/bad.dist-info
# python3 -m pip list
```

### Output

```shell
ERROR: Exception:
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/cli/base_command.py", line 167, in exc_logging_wrapper
    status = run_func(*args)
             ^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/commands/list.py", line 164, in run
    packages: "_ProcessedDists" = [
                                  ^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/commands/list.py", line 164, in <listcomp>
    packages: "_ProcessedDists" = [
                                  ^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/metadata/base.py", line 646, in <genexpr>
    return (d for d in it if d.canonical_name not in skip)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/metadata/base.py", line 594, in iter_all_distributions
    for dist in self._iter_distributions():
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py", line 167, in _iter_distributions
    yield from finder.find(location)
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py", line 71, in find
    for dist, info_location in self._find_impl(location):
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py", line 59, in _find_impl
    normalized_name = canonicalize_name(get_dist_name(dist))
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pip/_vendor/packaging/utils.py", line 34, in canonicalize_name
    value = _canonicalize_regex.sub("-", name).lower()
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: expected string or bytes-like object, got 'NoneType'
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/usr/local/lib/python3.11/site-packages/pip/__main__.py", line 31, in <module>
    sys.exit(_main())
             ^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/cli/main.py", line 70, in main
    return command.main(cmd_args)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/cli/base_command.py", line 101, in main
    return self._main(args)
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/cli/base_command.py", line 223, in _main
    self.handle_pip_version_check(options)
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/cli/req_command.py", line 179, in handle_pip_version_check
    session = self._build_session(
              ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/cli/req_command.py", line 125, in _build_session
    session = PipSession(
              ^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/network/session.py", line 343, in __init__
    self.headers["User-Agent"] = user_agent()
                                 ^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/network/session.py", line 175, in user_agent
    setuptools_dist = get_default_environment().get_distribution("setuptools")
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py", line 180, in get_distribution
    return next(matches, None)
           ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py", line 175, in <genexpr>
    matches = (
              ^
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/metadata/base.py", line 594, in iter_all_distributions
    for dist in self._iter_distributions():
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py", line 167, in _iter_distributions
    yield from finder.find(location)
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py", line 71, in find
    for dist, info_location in self._find_impl(location):
  File "/usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py", line 59, in _find_impl
    normalized_name = canonicalize_name(get_dist_name(dist))
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pip/_vendor/packaging/utils.py", line 34, in canonicalize_name
    value = _canonicalize_regex.sub("-", name).lower()
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: expected string or bytes-like object, got 'NoneType'
```


### Code of Conduct

- [X] I agree to follow the [PSF Code of Conduct](https://www.python.org/psf/conduct/).


Discussion:
Can you run pip with `--debug`, and post the output of that?
```
root@b35bd6059f3b:/# pip --debug list
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /usr/local/lib/python3.11/site-packages/pip/_internal/cli/base_command.py:221 in _main           │
│                                                                                                  │
│   218 │   │   │   else:                                                                          │
│   219 │   │   │   │   run = self.run                                                             │
│   220 │   │   │   │   rich_traceback.install(show_locals=True)                                   │
│ ❱ 221 │   │   │   return run(options, args)                                                      │
│   222 │   │   finally:                                                                           │
│   223 │   │   │   self.handle_pip_version_check(options)                                         │
│   224                                                                                            │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │                     args = []                                                                │ │
│ │ intercepts_unhandled_exc = <function Command._main.<locals>.intercepts_unhandled_exc at      │ │
│ │                            0x7f8e70d45080>                                                   │ │
│ │             level_number = 20                                                                │ │
│ │                  options = <Values at 0x7f8e70b2a110: {'help': None, 'debug_mode': True,     │ │
│ │                            'isolated_mode': False, 'require_venv': False, 'verbose': 0,      │ │
│ │                            'version': None, 'quiet': 0, 'log': None, 'no_input': False,      │ │
│ │                            'proxy': '', 'retries': 5, 'timeout': 15, 'exists_action': [],    │ │
│ │                            'trusted_hosts': [], 'cert': None, 'client_cert': None,           │ │
│ │                            'cache_dir': '/root/.cache/pip', 'disable_pip_version_check':     │ │
│ │                            False, 'no_color': False, 'no_python_version_warning': False,     │ │
│ │                            'features_enabled': [], 'deprecated_features_enabled': [],        │ │
│ │                            'outdated': False, 'uptodate': False, 'editable': False, 'local': │ │
│ │                            False, 'user': False, 'path': None, 'pre': False, 'list_format':  │ │
│ │                            'columns', 'not_required': None, 'include_editable': True,        │ │
│ │                            'excludes': None, 'index_url': 'https://pypi.org/simple',         │ │
│ │                            'extra_index_urls': [], 'no_index': False, 'find_links': []}>     │ │
│ │                      run = <bound method ListCommand.run of                                  │ │
│ │                            <pip._internal.commands.list.ListCommand object at                │ │
│ │                            0x7f8e7133eb90>>                                                  │ │
│ │                     self = <pip._internal.commands.list.ListCommand object at                │ │
│ │                            0x7f8e7133eb90>                                                   │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/commands/list.py:164 in run                │
│                                                                                                  │
│   161 │   │   if options.excludes:                                                               │
│   162 │   │   │   skip.update(canonicalize_name(n) for n in options.excludes)                    │
│   163 │   │                                                                                      │
│ ❱ 164 │   │   packages: "_ProcessedDists" = [                                                    │
│   165 │   │   │   cast("_DistWithLatestInfo", d)                                                 │
│   166 │   │   │   for d in get_environment(options.path).iter_installed_distributions(           │
│   167 │   │   │   │   local_only=options.local,                                                  │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │    args = []                                                                                 │ │
│ │ options = <Values at 0x7f8e70b2a110: {'help': None, 'debug_mode': True, 'isolated_mode':     │ │
│ │           False, 'require_venv': False, 'verbose': 0, 'version': None, 'quiet': 0, 'log':    │ │
│ │           None, 'no_input': False, 'proxy': '', 'retries': 5, 'timeout': 15,                 │ │
│ │           'exists_action': [], 'trusted_hosts': [], 'cert': None, 'client_cert': None,       │ │
│ │           'cache_dir': '/root/.cache/pip', 'disable_pip_version_check': False, 'no_color':   │ │
│ │           False, 'no_python_version_warning': False, 'features_enabled': [],                 │ │
│ │           'deprecated_features_enabled': [], 'outdated': False, 'uptodate': False,           │ │
│ │           'editable': False, 'local': False, 'user': False, 'path': None, 'pre': False,      │ │
│ │           'list_format': 'columns', 'not_required': None, 'include_editable': True,          │ │
│ │           'excludes': None, 'index_url': 'https://pypi.org/simple', 'extra_index_urls': [],  │ │
│ │           'no_index': False, 'find_links': []}>                                              │ │
│ │    self = <pip._internal.commands.list.ListCommand object at 0x7f8e7133eb90>                 │ │
│ │    skip = {'wsgiref', 'argparse', 'python'}                                                  │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/commands/list.py:164 in <listcomp>         │
│                                                                                                  │
│   161 │   │   if options.excludes:                                                               │
│   162 │   │   │   skip.update(canonicalize_name(n) for n in options.excludes)                    │
│   163 │   │                                                                                      │
│ ❱ 164 │   │   packages: "_ProcessedDists" = [                                                    │
│   165 │   │   │   cast("_DistWithLatestInfo", d)                                                 │
│   166 │   │   │   for d in get_environment(options.path).iter_installed_distributions(           │
│   167 │   │   │   │   local_only=options.local,                                                  │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ .0 = <generator object BaseEnvironment.iter_installed_distributions.<locals>.<genexpr> at    │ │
│ │      0x7f8e70b15620>                                                                         │ │
│ │  d = wheel 0.37.1 (/usr/local/lib/python3.11/site-packages)                                  │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/metadata/base.py:646 in <genexpr>          │
│                                                                                                  │
│   643 │   │   │   it = (d for d in it if d.editable)                                             │
│   644 │   │   if user_only:                                                                      │
│   645 │   │   │   it = (d for d in it if d.in_usersite)                                          │
│ ❱ 646 │   │   return (d for d in it if d.canonical_name not in skip)                             │
│   647                                                                                            │
│   648                                                                                            │
│   649 class Wheel(Protocol):                                                                     │
│                                                                                                  │
│ ╭────────────────────────────────────── locals ──────────────────────────────────────╮           │
│ │   .0 = <generator object BaseEnvironment.iter_all_distributions at 0x7f8e70b1ac50> │           │
│ │    d = wheel 0.37.1 (/usr/local/lib/python3.11/site-packages)                      │           │
│ │ skip = {'wsgiref', 'argparse', 'python'}                                           │           │
│ ╰────────────────────────────────────────────────────────────────────────────────────╯           │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/metadata/base.py:594 in                    │
│ iter_all_distributions                                                                           │
│                                                                                                  │
│   591 │                                                                                          │
│   592 │   def iter_all_distributions(self) -> Iterator[BaseDistribution]:                        │
│   593 │   │   """Iterate through all installed distributions without any filtering."""           │
│ ❱ 594 │   │   for dist in self._iter_distributions():                                            │
│   595 │   │   │   # Make sure the distribution actually comes from a valid Python                │
│   596 │   │   │   # packaging distribution. Pip's AdjacentTempDirectory leaves folders           │
│   597 │   │   │   # e.g. ``~atplotlib.dist-info`` if cleanup was interrupted. The                │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │               dist = wheel 0.37.1 (/usr/local/lib/python3.11/site-packages)                  │ │
│ │ project_name_valid = <re.Match object; span=(0, 5), match='wheel'>                           │ │
│ │               self = <pip._internal.metadata.importlib._envs.Environment object at           │ │
│ │                      0x7f8e710d79d0>                                                         │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py:167 in         │
│ _iter_distributions                                                                              │
│                                                                                                  │
│   164 │   def _iter_distributions(self) -> Iterator[BaseDistribution]:                           │
│   165 │   │   finder = _DistributionFinder()                                                     │
│   166 │   │   for location in self._paths:                                                       │
│ ❱ 167 │   │   │   yield from finder.find(location)                                               │
│   168 │   │   │   for dist in finder.find_eggs(location):                                        │
│   169 │   │   │   │   # _emit_egg_deprecation(dist.location)  # TODO: Enable this.               │
│   170 │   │   │   │   yield dist                                                                 │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │   finder = <pip._internal.metadata.importlib._envs._DistributionFinder object at             │ │
│ │            0x7f8e7133edd0>                                                                   │ │
│ │ location = '/usr/local/lib/python3.11/site-packages'                                         │ │
│ │     self = <pip._internal.metadata.importlib._envs.Environment object at 0x7f8e710d79d0>     │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py:71 in find     │
│                                                                                                  │
│    68 │   │                                                                                      │
│    69 │   │   The path can be either a directory, or a ZIP archive.                              │
│    70 │   │   """                                                                                │
│ ❱  71 │   │   for dist, info_location in self._find_impl(location):                              │
│    72 │   │   │   if info_location is None:                                                      │
│    73 │   │   │   │   installed_location: Optional[BasePath] = None                              │
│    74 │   │   │   else:                                                                          │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │               dist = <importlib.metadata.PathDistribution object at 0x7f8e709ed2d0>          │ │
│ │      info_location = PosixPath('/usr/local/lib/python3.11/site-packages/wheel-0.37.1.dist-i… │ │
│ │ installed_location = PosixPath('/usr/local/lib/python3.11/site-packages')                    │ │
│ │           location = '/usr/local/lib/python3.11/site-packages'                               │ │
│ │               self = <pip._internal.metadata.importlib._envs._DistributionFinder object at   │ │
│ │                      0x7f8e7133edd0>                                                         │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py:59 in          │
│ _find_impl                                                                                       │
│                                                                                                  │
│    56 │   │   # To know exactly where we find a distribution, we have to feed in the             │
│    57 │   │   # paths one by one, instead of dumping the list to importlib.metadata.             │
│    58 │   │   for dist in importlib.metadata.distributions(path=[location]):                     │
│ ❱  59 │   │   │   normalized_name = canonicalize_name(get_dist_name(dist))                       │
│    60 │   │   │   if normalized_name in self._found_names:                                       │
│    61 │   │   │   │   continue                                                                   │
│    62 │   │   │   self._found_names.add(normalized_name)                                         │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │            dist = <importlib.metadata.PathDistribution object at 0x7f8e71144090>             │ │
│ │   info_location = PosixPath('/usr/local/lib/python3.11/site-packages/wheel-0.37.1.dist-info… │ │
│ │        location = '/usr/local/lib/python3.11/site-packages'                                  │ │
│ │ normalized_name = 'wheel'                                                                    │ │
│ │            self = <pip._internal.metadata.importlib._envs._DistributionFinder object at      │ │
│ │                   0x7f8e7133edd0>                                                            │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_vendor/packaging/utils.py:34 in canonicalize_name   │
│                                                                                                  │
│    31                                                                                            │
│    32 def canonicalize_name(name: str) -> NormalizedName:                                        │
│    33 │   # This is taken from PEP 503.                                                          │
│ ❱  34 │   value = _canonicalize_regex.sub("-", name).lower()                                     │
│    35 │   return cast(NormalizedName, value)                                                     │
│    36                                                                                            │
│    37                                                                                            │
│                                                                                                  │
│ ╭── locals ───╮                                                                                  │
│ │ name = None │                                                                                  │
│ ╰─────────────╯                                                                                  │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
TypeError: expected string or bytes-like object, got 'NoneType'

During handling of the above exception, another exception occurred:

╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /usr/local/bin/pip:8 in <module>                                                                 │
│                                                                                                  │
│   5 from pip._internal.cli.main import main                                                      │
│   6 if __name__ == '__main__':                                                                   │
│   7 │   sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])                         │
│ ❱ 8 │   sys.exit(main())                                                                         │
│   9                                                                                              │
│                                                                                                  │
│ ╭───────────────────────────────────────── locals ─────────────────────────────────────────╮     │
│ │ __annotations__ = {}                                                                     │     │
│ │    __builtins__ = <module 'builtins' (built-in)>                                         │     │
│ │      __cached__ = None                                                                   │     │
│ │         __doc__ = None                                                                   │     │
│ │        __file__ = '/usr/local/bin/pip'                                                   │     │
│ │      __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f8e729da990> │     │
│ │        __name__ = '__main__'                                                             │     │
│ │     __package__ = None                                                                   │     │
│ │        __spec__ = None                                                                   │     │
│ │            main = <function main at 0x7f8e72827600>                                      │     │
│ │              re = <module 're' from '/usr/local/lib/python3.11/re/__init__.py'>          │     │
│ │             sys = <module 'sys' (built-in)>                                              │     │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────╯     │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/cli/main.py:70 in main                     │
│                                                                                                  │
│   67 │   │   logger.debug("Ignoring error %s when setting locale", e)                            │
│   68 │   command = create_command(cmd_name, isolated=("--isolated" in cmd_args))                 │
│   69 │                                                                                           │
│ ❱ 70 │   return command.main(cmd_args)                                                           │
│   71                                                                                             │
│                                                                                                  │
│ ╭─────────────────────────────────── locals ────────────────────────────────────╮                │
│ │     args = ['--debug', 'list']                                                │                │
│ │ cmd_args = ['--debug']                                                        │                │
│ │ cmd_name = 'list'                                                             │                │
│ │  command = <pip._internal.commands.list.ListCommand object at 0x7f8e7133eb90> │                │
│ ╰───────────────────────────────────────────────────────────────────────────────╯                │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/cli/base_command.py:101 in main            │
│                                                                                                  │
│    98 │   def main(self, args: List[str]) -> int:                                                │
│    99 │   │   try:                                                                               │
│   100 │   │   │   with self.main_context():                                                      │
│ ❱ 101 │   │   │   │   return self._main(args)                                                    │
│   102 │   │   finally:                                                                           │
│   103 │   │   │   logging.shutdown()                                                             │
│   104                                                                                            │
│                                                                                                  │
│ ╭───────────────────────────────── locals ──────────────────────────────────╮                    │
│ │ args = ['--debug']                                                        │                    │
│ │ self = <pip._internal.commands.list.ListCommand object at 0x7f8e7133eb90> │                    │
│ ╰───────────────────────────────────────────────────────────────────────────╯                    │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/cli/base_command.py:223 in _main           │
│                                                                                                  │
│   220 │   │   │   │   rich_traceback.install(show_locals=True)                                   │
│   221 │   │   │   return run(options, args)                                                      │
│   222 │   │   finally:                                                                           │
│ ❱ 223 │   │   │   self.handle_pip_version_check(options)                                         │
│   224                                                                                            │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │                     args = []                                                                │ │
│ │ intercepts_unhandled_exc = <function Command._main.<locals>.intercepts_unhandled_exc at      │ │
│ │                            0x7f8e70d45080>                                                   │ │
│ │             level_number = 20                                                                │ │
│ │                  options = <Values at 0x7f8e70b2a110: {'help': None, 'debug_mode': True,     │ │
│ │                            'isolated_mode': False, 'require_venv': False, 'verbose': 0,      │ │
│ │                            'version': None, 'quiet': 0, 'log': None, 'no_input': False,      │ │
│ │                            'proxy': '', 'retries': 5, 'timeout': 15, 'exists_action': [],    │ │
│ │                            'trusted_hosts': [], 'cert': None, 'client_cert': None,           │ │
│ │                            'cache_dir': '/root/.cache/pip', 'disable_pip_version_check':     │ │
│ │                            False, 'no_color': False, 'no_python_version_warning': False,     │ │
│ │                            'features_enabled': [], 'deprecated_features_enabled': [],        │ │
│ │                            'outdated': False, 'uptodate': False, 'editable': False, 'local': │ │
│ │                            False, 'user': False, 'path': None, 'pre': False, 'list_format':  │ │
│ │                            'columns', 'not_required': None, 'include_editable': True,        │ │
│ │                            'excludes': None, 'index_url': 'https://pypi.org/simple',         │ │
│ │                            'extra_index_urls': [], 'no_index': False, 'find_links': []}>     │ │
│ │                      run = <bound method ListCommand.run of                                  │ │
│ │                            <pip._internal.commands.list.ListCommand object at                │ │
│ │                            0x7f8e7133eb90>>                                                  │ │
│ │                     self = <pip._internal.commands.list.ListCommand object at                │ │
│ │                            0x7f8e7133eb90>                                                   │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/cli/req_command.py:179 in                  │
│ handle_pip_version_check                                                                         │
│                                                                                                  │
│   176 │   │   │   return                                                                         │
│   177 │   │                                                                                      │
│   178 │   │   # Otherwise, check if we're using the latest version of pip available.             │
│ ❱ 179 │   │   session = self._build_session(                                                     │
│   180 │   │   │   options,                                                                       │
│   181 │   │   │   retries=0,                                                                     │
│   182 │   │   │   timeout=min(5, options.timeout),                                               │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ options = <Values at 0x7f8e70b2a110: {'help': None, 'debug_mode': True, 'isolated_mode':     │ │
│ │           False, 'require_venv': False, 'verbose': 0, 'version': None, 'quiet': 0, 'log':    │ │
│ │           None, 'no_input': False, 'proxy': '', 'retries': 5, 'timeout': 15,                 │ │
│ │           'exists_action': [], 'trusted_hosts': [], 'cert': None, 'client_cert': None,       │ │
│ │           'cache_dir': '/root/.cache/pip', 'disable_pip_version_check': False, 'no_color':   │ │
│ │           False, 'no_python_version_warning': False, 'features_enabled': [],                 │ │
│ │           'deprecated_features_enabled': [], 'outdated': False, 'uptodate': False,           │ │
│ │           'editable': False, 'local': False, 'user': False, 'path': None, 'pre': False,      │ │
│ │           'list_format': 'columns', 'not_required': None, 'include_editable': True,          │ │
│ │           'excludes': None, 'index_url': 'https://pypi.org/simple', 'extra_index_urls': [],  │ │
│ │           'no_index': False, 'find_links': []}>                                              │ │
│ │    self = <pip._internal.commands.list.ListCommand object at 0x7f8e7133eb90>                 │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/cli/req_command.py:125 in _build_session   │
│                                                                                                  │
│   122 │   │   else:                                                                              │
│   123 │   │   │   ssl_context = None                                                             │
│   124 │   │                                                                                      │
│ ❱ 125 │   │   session = PipSession(                                                              │
│   126 │   │   │   cache=os.path.join(cache_dir, "http") if cache_dir else None,                  │
│   127 │   │   │   retries=retries if retries is not None else options.retries,                   │
│   128 │   │   │   trusted_hosts=options.trusted_hosts,                                           │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │           cache_dir = '/root/.cache/pip'                                                     │ │
│ │ fallback_to_certifi = True                                                                   │ │
│ │             options = <Values at 0x7f8e70b2a110: {'help': None, 'debug_mode': True,          │ │
│ │                       'isolated_mode': False, 'require_venv': False, 'verbose': 0,           │ │
│ │                       'version': None, 'quiet': 0, 'log': None, 'no_input': False, 'proxy':  │ │
│ │                       '', 'retries': 5, 'timeout': 15, 'exists_action': [], 'trusted_hosts': │ │
│ │                       [], 'cert': None, 'client_cert': None, 'cache_dir':                    │ │
│ │                       '/root/.cache/pip', 'disable_pip_version_check': False, 'no_color':    │ │
│ │                       False, 'no_python_version_warning': False, 'features_enabled': [],     │ │
│ │                       'deprecated_features_enabled': [], 'outdated': False, 'uptodate':      │ │
│ │                       False, 'editable': False, 'local': False, 'user': False, 'path': None, │ │
│ │                       'pre': False, 'list_format': 'columns', 'not_required': None,          │ │
│ │                       'include_editable': True, 'excludes': None, 'index_url':               │ │
│ │                       'https://pypi.org/simple', 'extra_index_urls': [], 'no_index': False,  │ │
│ │                       'find_links': []}>                                                     │ │
│ │             retries = 0                                                                      │ │
│ │                self = <pip._internal.commands.list.ListCommand object at 0x7f8e7133eb90>     │ │
│ │         ssl_context = None                                                                   │ │
│ │             timeout = 5                                                                      │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/network/session.py:343 in __init__         │
│                                                                                                  │
│   340 │   │   self.pip_trusted_origins: List[Tuple[str, Optional[int]]] = []                     │
│   341 │   │                                                                                      │
│   342 │   │   # Attach our User Agent to the request                                             │
│ ❱ 343 │   │   self.headers["User-Agent"] = user_agent()                                          │
│   344 │   │                                                                                      │
│   345 │   │   # Attach our Authentication handler to the session                                 │
│   346 │   │   self.auth = MultiDomainBasicAuth(index_urls=index_urls)                            │
│                                                                                                  │
│ ╭────────────────────────────────────── locals ───────────────────────────────────────╮          │
│ │     __class__ = <class 'pip._internal.network.session.PipSession'>                  │          │
│ │          args = ()                                                                  │          │
│ │         cache = '/root/.cache/pip/http'                                             │          │
│ │    index_urls = ['https://pypi.org/simple']                                         │          │
│ │        kwargs = {}                                                                  │          │
│ │       retries = 0                                                                   │          │
│ │          self = <pip._internal.network.session.PipSession object at 0x7f8e709ed8d0> │          │
│ │   ssl_context = None                                                                │          │
│ │ trusted_hosts = []                                                                  │          │
│ ╰─────────────────────────────────────────────────────────────────────────────────────╯          │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/network/session.py:175 in user_agent       │
│                                                                                                  │
│   172 │   │                                                                                      │
│   173 │   │   data["openssl_version"] = ssl.OPENSSL_VERSION                                      │
│   174 │                                                                                          │
│ ❱ 175 │   setuptools_dist = get_default_environment().get_distribution("setuptools")             │
│   176 │   if setuptools_dist is not None:                                                        │
│   177 │   │   data["setuptools_version"] = str(setuptools_dist.version)                          │
│   178                                                                                            │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │               data = {                                                                       │ │
│ │                      │   'installer': {'name': 'pip', 'version': '22.2.2'},                  │ │
│ │                      │   'python': '3.11.0b5',                                               │ │
│ │                      │   'implementation': {'name': 'CPython', 'version': '3.11.0b5'},       │ │
│ │                      │   'distro': {                                                         │ │
│ │                      │   │   'name': 'Debian GNU/Linux',                                     │ │
│ │                      │   │   'version': '11',                                                │ │
│ │                      │   │   'id': 'bullseye',                                               │ │
│ │                      │   │   'libc': {'lib': 'glibc', 'version': '2.31'}                     │ │
│ │                      │   },                                                                  │ │
│ │                      │   'system': {'name': 'Linux', 'release': '5.18.6-100.fc35.x86_64'},   │ │
│ │                      │   'cpu': 'x86_64',                                                    │ │
│ │                      │   'openssl_version': 'OpenSSL 1.1.1n  15 Mar 2022'                    │ │
│ │                      }                                                                       │ │
│ │             distro = <module 'pip._vendor.distro' from                                       │ │
│ │                      '/usr/local/lib/python3.11/site-packages/pip/_vendor/distro/__init__.p… │ │
│ │       distro_infos = {                                                                       │ │
│ │                      │   'name': 'Debian GNU/Linux',                                         │ │
│ │                      │   'version': '11',                                                    │ │
│ │                      │   'id': 'bullseye',                                                   │ │
│ │                      │   'libc': {'lib': 'glibc', 'version': '2.31'}                         │ │
│ │                      }                                                                       │ │
│ │               libc = {'lib': 'glibc', 'version': '2.31'}                                     │ │
│ │ linux_distribution = ('Debian GNU/Linux', '11', 'bullseye')                                  │ │
│ │                ssl = <module '_ssl' from                                                     │ │
│ │                      '/usr/local/lib/python3.11/lib-dynload/_ssl.cpython-311-x86_64-linux-g… │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py:180 in         │
│ get_distribution                                                                                 │
│                                                                                                  │
│   177 │   │   │   for distribution in self.iter_all_distributions()                              │
│   178 │   │   │   if distribution.canonical_name == canonicalize_name(name)                      │
│   179 │   │   )                                                                                  │
│ ❱ 180 │   │   return next(matches, None)                                                         │
│   181                                                                                            │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ matches = <generator object Environment.get_distribution.<locals>.<genexpr> at               │ │
│ │           0x7f8e70b944f0>                                                                    │ │
│ │    name = 'setuptools'                                                                       │ │
│ │    self = <pip._internal.metadata.importlib._envs.Environment object at 0x7f8e70fb9d50>      │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py:175 in         │
│ <genexpr>                                                                                        │
│                                                                                                  │
│   172 │   │   │   yield from finder.find_linked(location)                                        │
│   173 │                                                                                          │
│   174 │   def get_distribution(self, name: str) -> Optional[BaseDistribution]:                   │
│ ❱ 175 │   │   matches = (                                                                        │
│   176 │   │   │   distribution                                                                   │
│   177 │   │   │   for distribution in self.iter_all_distributions()                              │
│   178 │   │   │   if distribution.canonical_name == canonicalize_name(name)                      │
│                                                                                                  │
│ ╭────────────────────────────────────────── locals ──────────────────────────────────────────╮   │
│ │           .0 = <generator object BaseEnvironment.iter_all_distributions at 0x7f8e70b96020> │   │
│ │ distribution = wheel 0.37.1 (/usr/local/lib/python3.11/site-packages)                      │   │
│ │         name = 'setuptools'                                                                │   │
│ ╰────────────────────────────────────────────────────────────────────────────────────────────╯   │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/metadata/base.py:594 in                    │
│ iter_all_distributions                                                                           │
│                                                                                                  │
│   591 │                                                                                          │
│   592 │   def iter_all_distributions(self) -> Iterator[BaseDistribution]:                        │
│   593 │   │   """Iterate through all installed distributions without any filtering."""           │
│ ❱ 594 │   │   for dist in self._iter_distributions():                                            │
│   595 │   │   │   # Make sure the distribution actually comes from a valid Python                │
│   596 │   │   │   # packaging distribution. Pip's AdjacentTempDirectory leaves folders           │
│   597 │   │   │   # e.g. ``~atplotlib.dist-info`` if cleanup was interrupted. The                │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │               dist = wheel 0.37.1 (/usr/local/lib/python3.11/site-packages)                  │ │
│ │ project_name_valid = <re.Match object; span=(0, 5), match='wheel'>                           │ │
│ │               self = <pip._internal.metadata.importlib._envs.Environment object at           │ │
│ │                      0x7f8e70fb9d50>                                                         │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py:167 in         │
│ _iter_distributions                                                                              │
│                                                                                                  │
│   164 │   def _iter_distributions(self) -> Iterator[BaseDistribution]:                           │
│   165 │   │   finder = _DistributionFinder()                                                     │
│   166 │   │   for location in self._paths:                                                       │
│ ❱ 167 │   │   │   yield from finder.find(location)                                               │
│   168 │   │   │   for dist in finder.find_eggs(location):                                        │
│   169 │   │   │   │   # _emit_egg_deprecation(dist.location)  # TODO: Enable this.               │
│   170 │   │   │   │   yield dist                                                                 │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │   finder = <pip._internal.metadata.importlib._envs._DistributionFinder object at             │ │
│ │            0x7f8e71109450>                                                                   │ │
│ │ location = '/usr/local/lib/python3.11/site-packages'                                         │ │
│ │     self = <pip._internal.metadata.importlib._envs.Environment object at 0x7f8e70fb9d50>     │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py:71 in find     │
│                                                                                                  │
│    68 │   │                                                                                      │
│    69 │   │   The path can be either a directory, or a ZIP archive.                              │
│    70 │   │   """                                                                                │
│ ❱  71 │   │   for dist, info_location in self._find_impl(location):                              │
│    72 │   │   │   if info_location is None:                                                      │
│    73 │   │   │   │   installed_location: Optional[BasePath] = None                              │
│    74 │   │   │   else:                                                                          │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │               dist = <importlib.metadata.PathDistribution object at 0x7f8e70fb9910>          │ │
│ │      info_location = PosixPath('/usr/local/lib/python3.11/site-packages/wheel-0.37.1.dist-i… │ │
│ │ installed_location = PosixPath('/usr/local/lib/python3.11/site-packages')                    │ │
│ │           location = '/usr/local/lib/python3.11/site-packages'                               │ │
│ │               self = <pip._internal.metadata.importlib._envs._DistributionFinder object at   │ │
│ │                      0x7f8e71109450>                                                         │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py:59 in          │
│ _find_impl                                                                                       │
│                                                                                                  │
│    56 │   │   # To know exactly where we find a distribution, we have to feed in the             │
│    57 │   │   # paths one by one, instead of dumping the list to importlib.metadata.             │
│    58 │   │   for dist in importlib.metadata.distributions(path=[location]):                     │
│ ❱  59 │   │   │   normalized_name = canonicalize_name(get_dist_name(dist))                       │
│    60 │   │   │   if normalized_name in self._found_names:                                       │
│    61 │   │   │   │   continue                                                                   │
│    62 │   │   │   self._found_names.add(normalized_name)                                         │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │            dist = <importlib.metadata.PathDistribution object at 0x7f8e70a42010>             │ │
│ │   info_location = PosixPath('/usr/local/lib/python3.11/site-packages/wheel-0.37.1.dist-info… │ │
│ │        location = '/usr/local/lib/python3.11/site-packages'                                  │ │
│ │ normalized_name = 'wheel'                                                                    │ │
│ │            self = <pip._internal.metadata.importlib._envs._DistributionFinder object at      │ │
│ │                   0x7f8e71109450>                                                            │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/local/lib/python3.11/site-packages/pip/_vendor/packaging/utils.py:34 in canonicalize_name   │
│                                                                                                  │
│    31                                                                                            │
│    32 def canonicalize_name(name: str) -> NormalizedName:                                        │
│    33 │   # This is taken from PEP 503.                                                          │
│ ❱  34 │   value = _canonicalize_regex.sub("-", name).lower()                                     │
│    35 │   return cast(NormalizedName, value)                                                     │
│    36                                                                                            │
│    37                                                                                            │
│                                                                                                  │
│ ╭── locals ───╮                                                                                  │
│ │ name = None │                                                                                  │
│ ╰─────────────╯                                                                                  │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
TypeError: expected string or bytes-like object, got 'NoneType'
```
IMHO here:

https://github.com/pypa/pip/blob/80708923115c6e7a6af2c685e51f5b514225c5c0/src/pip/_internal/metadata/importlib/_envs.py#L57-L59

If `get_dist_name(dist)` is `None`, the backwards compatible behavior is to `continue`. A progressive behavior might be to issue a warning about that with the `location`.
Ignoring bad metadata with a warning is a good solution to me.

Do we need to worry how the bad metadata get in there in the first place? Or are those generated by Fedora so we don’t need to worry?
In our case, it seems this was an RPM packaging error in the mercurial package. The package "owned" the files in the egg info directory but not the directory itself, so when it was removed/updated, the directory stayed on the system. I've reported that to the Fedora maintainer of mercurial. 

Resolving patch:
diff --git a/src/pip/_internal/metadata/importlib/_compat.py b/src/pip/_internal/metadata/importlib/_compat.py
--- a/src/pip/_internal/metadata/importlib/_compat.py
+++ b/src/pip/_internal/metadata/importlib/_compat.py
@@ -2,6 +2,15 @@
 from typing import Any, Optional, Protocol, cast
 
 
+class BadMetadata(ValueError):
+    def __init__(self, dist: importlib.metadata.Distribution, *, reason: str) -> None:
+        self.dist = dist
+        self.reason = reason
+
+    def __str__(self) -> str:
+        return f"Bad metadata in {self.dist} ({self.reason})"
+
+
 class BasePath(Protocol):
     """A protocol that various path objects conform.
 
@@ -40,4 +49,7 @@ def get_dist_name(dist: importlib.metadata.Distribution) -> str:
     The ``name`` attribute is only available in Python 3.10 or later. We are
     targeting exactly that, but Mypy does not know this.
     """
-    return cast(Any, dist).name
+    name = cast(Any, dist).name
+    if not isinstance(name, str):
+        raise BadMetadata(dist, reason="invalid metadata entry 'name'")
+    return name
diff --git a/src/pip/_internal/metadata/importlib/_envs.py b/src/pip/_internal/metadata/importlib/_envs.py
--- a/src/pip/_internal/metadata/importlib/_envs.py
+++ b/src/pip/_internal/metadata/importlib/_envs.py
@@ -1,5 +1,6 @@
 import functools
 import importlib.metadata
+import logging
 import os
 import pathlib
 import sys
@@ -14,9 +15,11 @@
 from pip._internal.utils.deprecation import deprecated
 from pip._internal.utils.filetypes import WHEEL_EXTENSION
 
-from ._compat import BasePath, get_dist_name, get_info_location
+from ._compat import BadMetadata, BasePath, get_dist_name, get_info_location
 from ._dists import Distribution
 
+logger = logging.getLogger(__name__)
+
 
 def _looks_like_wheel(location: str) -> bool:
     if not location.endswith(WHEEL_EXTENSION):
@@ -56,11 +59,16 @@ def _find_impl(self, location: str) -> Iterator[FoundResult]:
         # To know exactly where we find a distribution, we have to feed in the
         # paths one by one, instead of dumping the list to importlib.metadata.
         for dist in importlib.metadata.distributions(path=[location]):
-            normalized_name = canonicalize_name(get_dist_name(dist))
+            info_location = get_info_location(dist)
+            try:
+                raw_name = get_dist_name(dist)
+            except BadMetadata as e:
+                logger.warning("Skipping %s due to %s", info_location, e.reason)
+                continue
+            normalized_name = canonicalize_name(raw_name)
             if normalized_name in self._found_names:
                 continue
             self._found_names.add(normalized_name)
-            info_location = get_info_location(dist)
             yield dist, info_location
 
     def find(self, location: str) -> Iterator[BaseDistribution]:


Test patch: