pypa / pip

The Python package installer
https://pip.pypa.io/
MIT License
9.55k stars 3.04k forks source link

DistInfoDistribution._compute_dependencies fails if the package has extras_require that are PEP440 versions. #4356

Closed vphilippon closed 9 months ago

vphilippon commented 7 years ago

Description:

I have a package which provides extras. The extras keys happen to have the format of PEP440 versions, such as 3.2.1 or 3.0. When installing the package using pip install, I end up with an exception (see in the "What I've run" section).

Note: While this occured using pip, I'm not exactly sure who is beign faulty (pip, setuptools, pkg_resources, packaging?)

What I've run:

Here's the setup.py to make a package that reproduces the issue:

from setuptools import setup

setup(
    name='my-test-pkg',
    version='1.2.3',
    description='Reproducing install issue with PEP440 extras.',
    install_requires=[],
    extras_require={
        '3.2.1': [  # The extra key is a PEP440 version
            'requests<3.0.0'
        ],
    }

)

Then, make a wheel:

 python setup.py bdist_wheel --dist-dir _build/dist
 # or, using pip:
 pip wheel . -w _build/dist

Then, install the package (not even using the extra):

 pip install --find-links _build/dist/ my-test-pkg==1.2.3

And the result:

Collecting my-test-pkg==1.2.3
c:\python27\lib\site-packages\pip\_vendor\requests\packages\urllib3\util\ssl_.py:318: SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform. This may cause the server to present an incorrect TLS certificate, which can cause validation failures. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/security.html#snimissingwarning.
  SNIMissingWarning
c:\python27\lib\site-packages\pip\_vendor\requests\packages\urllib3\util\ssl_.py:122: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
Exception:
Traceback (most recent call last):
  File "c:\python27\lib\site-packages\pip\basecommand.py", line 215, in main
    status = self.run(options, args)
  File "c:\python27\lib\site-packages\pip\commands\install.py", line 335, in run
    wb.build(autobuilding=True)
  File "c:\python27\lib\site-packages\pip\wheel.py", line 749, in build
    self.requirement_set.prepare_files(self.finder)
  File "c:\python27\lib\site-packages\pip\req\req_set.py", line 380, in prepare_files
    ignore_dependencies=self.ignore_dependencies))
  File "c:\python27\lib\site-packages\pip\req\req_set.py", line 699, in _prepare_file
    set(req_to_install.extras) - set(dist.extras)
  File "c:\python27\lib\site-packages\pip\_vendor\pkg_resources\__init__.py", line 2757, in extras
    return [dep for dep in self._dep_map if dep]
  File "c:\python27\lib\site-packages\pip\_vendor\pkg_resources\__init__.py", line 2799, in _dep_map
    self.__dep_map = self._compute_dependencies()
  File "c:\python27\lib\site-packages\pip\_vendor\pkg_resources\__init__.py", line 2816, in _compute_dependencies
    common = frozenset(reqs_for_extra(None))
  File "c:\python27\lib\site-packages\pip\_vendor\pkg_resources\__init__.py", line 2813, in reqs_for_extra
    if not req.marker or req.marker.evaluate({'extra': extra}):
  File "c:\python27\lib\site-packages\pip\_vendor\packaging\markers.py", line 303, in evaluate
    return _evaluate_markers(self._markers, current_environment)
  File "c:\python27\lib\site-packages\pip\_vendor\packaging\markers.py", line 234, in _evaluate_markers
    groups[-1].append(_eval_op(lhs_value, op, rhs_value))
  File "c:\python27\lib\site-packages\pip\_vendor\packaging\markers.py", line 191, in _eval_op
    return spec.contains(lhs)
  File "c:\python27\lib\site-packages\pip\_vendor\packaging\specifiers.py", line 170, in contains
    item = self._coerce_version(item)
  File "c:\python27\lib\site-packages\pip\_vendor\packaging\specifiers.py", line 141, in _coerce_version
    version = parse(version)
  File "c:\python27\lib\site-packages\pip\_vendor\packaging\version.py", line 31, in parse
    return Version(version)
  File "c:\python27\lib\site-packages\pip\_vendor\packaging\version.py", line 200, in __init__
    match = self._regex.search(version)
TypeError: expected string or buffer

What I figured out

I went around the code in the stack trace and managed to figure what's happening:

The TypeError comes from trying to parse None as a packaging.Version object. The None comes from DistInfoDistribution._compute_dependencies, with this call: common = frozenset(reqs_for_extra(None)).

Later, during the markers evaluation in packaging.markers, at line 185, we have this function:

def _eval_op(lhs, op, rhs):
    try:
        spec = Specifier("".join([op.serialize(), rhs]))
    except InvalidSpecifier:
        pass
    else:
        return spec.contains(lhs)

    oper = _operators.get(op.serialize())
    if oper is None:
        raise UndefinedComparison(
            "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs)
        )

    return oper(lhs, rhs)

As rhs is the extra key, a PEP440 version (3.2.1), the Specifier creation succeeds, and we call return spec.contains(lhs). In this case, lhs is the None I pointed out earlier, which cause the TypeError when trying to parse it as a version. Note that if rhs was not a version-like string (such as foobar or security), the Specifier creation would fail, (I think) and we would execute oper = _operators.get(op.serialize()) and return oper(lhs, rhs) instead.

How to fix

I'm not sure. I feel like the logic in _eval_op is not precise enough, or maybe the marker evaluation is not meant to be used this way. I'm not familiar enough with pip/pkg_ressources/packaging structure and interaction to tell what's going to happen if I change any of this.

I'd need the input of someone with a lot more knowledge about the project to help sort this out.

I tried making this as clear as possible, but don't hesitate to ask for details.

vphilippon commented 7 years ago

I looked a bit more into this, and I'm understanding a bit more of what's going on. I hope this will help find a good fix:

This call:

File "c:\python27\lib\site-packages\pip\_vendor\pkg_resources\__init__.py", line 2816, in _compute_dependencies
    common = frozenset(reqs_for_extra(None))

tries to gather all requirements for which there is either no marker, or for which the marker, when setting extra to None, evaluates as True.

As an example, given the following requirements:

Requires-Dist: requests (==2.13.0)
Requires-Dist: toto (==7.8.9); sys_platform == "win32"
Requires-Dist: bar (==4.2.1); extra == None
Requires-Dist: foo (==1.2.4); extra == '3.10'

common would contain the 1st, 2nd and 3rd requirements. I can see where the 1st one could come from: the install_requires list. The second one, probably from extras_require: {':sys_platform == "win32"': ['toto==7.8.9']} The 3rd one would be from something like extras_require: {None: ['bar==4.2.1']}, which I'm not sure should be part of common, or is even possible (I claim here my right to be wrong and to not have a clue).

Now, as I pointed out in my initial comment, the issue happens with the 4th requirements. When evaluating the marker of that requirements, we call _eval_op. And on this line: spec = Specifier("".join([op.serialize(), rhs])) We succed, because: op.serialize() -> "==", rhs -> "3.10" So we call this line of code: return spec.contains(lhs) And we get an exception, because: lhs -> None, and trying to parse None with a regex to create a Version object fails.

So, it looks like the issue is from either:

While this seems outside of the hand of pip itself, could someone knowledgeable (@dstufft ?) give me some pointers on which one I should go to and open an issue? I have a feeling that Specifier.contains in packaging should be handling None nicely, but I'd really like a second opinion.

Thanks to whoever will take the time to read all this and reply :) .

dstufft commented 7 years ago

Hmm passing in None as an extra feels wrong to me, but I'm happy to have a PR to packaging that makes _eval_op handle that case better.

vphilippon commented 7 years ago

Allright, thanks for your input! I'll try to take a stab at this on the packaging side soon-ish. I suggest we keep this issue active here until the vendored packaging is updated in pip too.

vphilippon commented 7 years ago

Small update: This still occurs with pip 10 (commit 8f4f15a5a95d7d5b511ceaee9ed261176c181970). I checked in case some change in the refactor changed so that None isn't passed anymore.

About that, I submitted a PR in pypa/packaging to deal with this a while ago, but my tests brought up some legitimate questions, putting a pause on the change.

Should I take another approach and fix this from pip side to not pass a None? This isn't critical, I know I haven't seen much "version-like extras", only my own fancy/weird stuff so far, but if we can get this done, let's do it.

pfmoore commented 6 years ago

Is this still awaiting a fix, or did a change to packaging ever get made to address it?

pradyunsg commented 6 years ago

Waiting on a fix.

pradyunsg commented 6 years ago

Pushing this down the road to the next release since I don't think this'd happen in time for 18.0.

pradyunsg commented 6 years ago

Pushing this down the road since I don't think this'd happen in time for 18.1.

pradyunsg commented 2 years ago

Reproduced this with the current version of pip as well:

$ pip install ./dist/my_test_pkg-1.2.3-py3-none-any.whl --debug 2>&1
Processing ./dist/my_test_pkg-1.2.3-py3-none-any.whl
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/pkg_resources/__init__.py:3021 in _dep_map │
│                                                                                                  │
│   3018 │   @property                                                                             │
│   3019 │   def _dep_map(self):                                                                   │
│   3020 │   │   try:                                                                              │
│ ❱ 3021 │   │   │   return self.__dep_map                                                         │
│   3022 │   │   except AttributeError:                                                            │
│   3023 │   │   │   self.__dep_map = self._compute_dependencies()                                 │
│   3024 │   │   │   return self.__dep_map                                                         │
│                                                                                                  │
│ ╭────────────────────────────────────── locals ───────────────────────────────────────╮          │
│ │ self = my-test-pkg 1.2.3 (/private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-any.whl) │          │
│ ╰─────────────────────────────────────────────────────────────────────────────────────╯          │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/pkg_resources/__init__.py:2815 in          │
│ __getattr__                                                                                      │
│                                                                                                  │
│   2812 │   def __getattr__(self, attr):                                                          │
│   2813 │   │   """Delegate all unrecognized public attributes to .metadata provider"""           │
│   2814 │   │   if attr.startswith('_'):                                                          │
│ ❱ 2815 │   │   │   raise AttributeError(attr)                                                    │
│   2816 │   │   return getattr(self._provider, attr)                                              │
│   2817 │                                                                                         │
│   2818 │   def __dir__(self):                                                                    │
│                                                                                                  │
│ ╭────────────────────────────────────── locals ───────────────────────────────────────╮          │
│ │ attr = '_DistInfoDistribution__dep_map'                                             │          │
│ │ self = my-test-pkg 1.2.3 (/private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-any.whl) │          │
│ ╰─────────────────────────────────────────────────────────────────────────────────────╯          │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
AttributeError: _DistInfoDistribution__dep_map

During handling of the above exception, another exception occurred:

╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /Users/pradyunsg/Developer/github/pip/.venv/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__ = '/Users/pradyunsg/Developer/github/pip/.venv/bin/pip'                      │ │
│ │      __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x104a25390>        │ │
│ │        __name__ = '__main__'                                                                 │ │
│ │     __package__ = None                                                                       │ │
│ │        __spec__ = None                                                                       │ │
│ │            main = <function main at 0x104b3f010>                                             │ │
│ │              re = <module 're' from                                                          │ │
│ │                   '/Users/pradyunsg/.asdf/installs/python/3.10.1/lib/python3.10/re.py'>      │ │
│ │             sys = <module 'sys' (built-in)>                                                  │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/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 = ['install', './dist/my_test_pkg-1.2.3-py3-none-any.whl', '--debug']   │             │
│ │ cmd_args = ['./dist/my_test_pkg-1.2.3-py3-none-any.whl', '--debug']              │             │
│ │ cmd_name = 'install'                                                             │             │
│ │  command = <pip._internal.commands.install.InstallCommand object at 0x106126d10> │             │
│ ╰──────────────────────────────────────────────────────────────────────────────────╯             │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/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 = ['./dist/my_test_pkg-1.2.3-py3-none-any.whl', '--debug']              │                 │
│ │ self = <pip._internal.commands.install.InstallCommand object at 0x106126d10> │                 │
│ ╰──────────────────────────────────────────────────────────────────────────────╯                 │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/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 = ['./dist/my_test_pkg-1.2.3-py3-none-any.whl']                     │ │
│ │ intercepts_unhandled_exc = <function Command._main.<locals>.intercepts_unhandled_exc at      │ │
│ │                            0x10496bd90>                                                      │ │
│ │             level_number = 20                                                                │ │
│ │                  options = <Values at 0x106426a10: {'help': None, 'debug_mode': True,        │ │
│ │                            'isolated_mode': False, 'require_venv': 1, 'python': None,        │ │
│ │                            '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':                                 │ │
│ │                            '/Users/pradyunsg/Library/Caches/pip',                            │ │
│ │                            'disable_pip_version_check': False, 'no_color': False,            │ │
│ │                            'no_python_version_warning': False, 'features_enabled': [],       │ │
│ │                            'deprecated_features_enabled': [], 'requirements': [],            │ │
│ │                            'constraints': [], 'ignore_dependencies': False, 'pre': False,    │ │
│ │                            'editables': [], 'dry_run': False, 'target_dir': None,            │ │
│ │                            'platforms': None, 'python_version': None, 'implementation':      │ │
│ │                            None, 'abis': None, 'use_user_site': False, 'root_path': None,    │ │
│ │                            'prefix_path': None, 'src_dir':                                   │ │
│ │                            '/Users/pradyunsg/Developer/github/pip/.venv/src', 'upgrade':     │ │
│ │                            None, 'upgrade_strategy': 'only-if-needed', 'force_reinstall':    │ │
│ │                            None, 'ignore_installed': None, 'ignore_requires_python': None,   │ │
│ │                            'build_isolation': True, 'use_pep517': None, 'check_build_deps':  │ │
│ │                            False, 'config_settings': None, 'install_options': None,          │ │
│ │                            'global_options': None, 'compile': True, 'warn_script_location':  │ │
│ │                            True, 'warn_about_conflicts': True, 'format_control':             │ │
│ │                            FormatControl(set(), set()), 'prefer_binary': False,              │ │
│ │                            'require_hashes': False, 'progress_bar': 'on',                    │ │
│ │                            'root_user_action': 'warn', 'index_url':                          │ │
│ │                            'https://pypi.org/simple', 'extra_index_urls': [], 'no_index':    │ │
│ │                            False, 'find_links': [], 'json_report_file': None, 'no_clean':    │ │
│ │                            False}>                                                           │ │
│ │                      run = <bound method with_cleanup.<locals>.wrapper of                    │ │
│ │                            <pip._internal.commands.install.InstallCommand object at          │ │
│ │                            0x106126d10>>                                                     │ │
│ │                     self = <pip._internal.commands.install.InstallCommand object at          │ │
│ │                            0x106126d10>                                                      │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_internal/cli/req_command.py:247 in wrapper        │
│                                                                                                  │
│   244 │   │   │   configure_tempdir_registry(self.tempdir_registry)                              │
│   245 │   │                                                                                      │
│   246 │   │   try:                                                                               │
│ ❱ 247 │   │   │   return func(self, options, args)                                               │
│   248 │   │   except PreviousBuildDirError:                                                      │
│   249 │   │   │   # This kind of conflict can occur when the user passes an explicit             │
│   250 │   │   │   # build directory with a pre-existing folder. In that case we do               │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │                       args = ['./dist/my_test_pkg-1.2.3-py3-none-any.whl']                   │ │
│ │ configure_tempdir_registry = <function with_cleanup.<locals>.configure_tempdir_registry at   │ │
│ │                              0x106422710>                                                    │ │
│ │                       func = <function InstallCommand.run at 0x106422680>                    │ │
│ │                    options = <Values at 0x106426a10: {'help': None, 'debug_mode': True,      │ │
│ │                              'isolated_mode': False, 'require_venv': 1, 'python': None,      │ │
│ │                              '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':                               │ │
│ │                              '/Users/pradyunsg/Library/Caches/pip',                          │ │
│ │                              'disable_pip_version_check': False, 'no_color': False,          │ │
│ │                              'no_python_version_warning': False, 'features_enabled': [],     │ │
│ │                              'deprecated_features_enabled': [], 'requirements': [],          │ │
│ │                              'constraints': [], 'ignore_dependencies': False, 'pre': False,  │ │
│ │                              'editables': [], 'dry_run': False, 'target_dir': None,          │ │
│ │                              'platforms': None, 'python_version': None, 'implementation':    │ │
│ │                              None, 'abis': None, 'use_user_site': False, 'root_path': None,  │ │
│ │                              'prefix_path': None, 'src_dir':                                 │ │
│ │                              '/Users/pradyunsg/Developer/github/pip/.venv/src', 'upgrade':   │ │
│ │                              None, 'upgrade_strategy': 'only-if-needed', 'force_reinstall':  │ │
│ │                              None, 'ignore_installed': None, 'ignore_requires_python': None, │ │
│ │                              'build_isolation': True, 'use_pep517': None,                    │ │
│ │                              'check_build_deps': False, 'config_settings': None,             │ │
│ │                              'install_options': None, 'global_options': None, 'compile':     │ │
│ │                              True, 'warn_script_location': True, 'warn_about_conflicts':     │ │
│ │                              True, 'format_control': FormatControl(set(), set()),            │ │
│ │                              'prefer_binary': False, 'require_hashes': False,                │ │
│ │                              'progress_bar': 'on', 'root_user_action': 'warn', 'index_url':  │ │
│ │                              'https://pypi.org/simple', 'extra_index_urls': [], 'no_index':  │ │
│ │                              False, 'find_links': [], 'json_report_file': None, 'no_clean':  │ │
│ │                              False}>                                                         │ │
│ │                       self = <pip._internal.commands.install.InstallCommand object at        │ │
│ │                              0x106126d10>                                                    │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_internal/commands/install.py:400 in run           │
│                                                                                                  │
│   397 │   │   │                                                                                  │
│   398 │   │   │   self.trace_basic_info(finder)                                                  │
│   399 │   │   │                                                                                  │
│ ❱ 400 │   │   │   requirement_set = resolver.resolve(                                            │
│   401 │   │   │   │   reqs, check_supported_wheels=not options.target_dir                        │
│   402 │   │   │   )                                                                              │
│   403                                                                                            │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │                 args = ['./dist/my_test_pkg-1.2.3-py3-none-any.whl']                         │ │
│ │        build_tracker = <pip._internal.operations.build.build_tracker.BuildTracker object at  │ │
│ │                        0x1064bf550>                                                          │ │
│ │            directory = <repr-error 'Attempted to access deleted path:                        │ │
│ │                        /private/var/folders/y1/j465wvf92vs938kmgqh63bj80000gn/T/pip-install… │ │
│ │               finder = <pip._internal.index.package_finder.PackageFinder object at           │ │
│ │                        0x106427760>                                                          │ │
│ │       global_options = []                                                                    │ │
│ │      install_options = []                                                                    │ │
│ │              options = <Values at 0x106426a10: {'help': None, 'debug_mode': True,            │ │
│ │                        'isolated_mode': False, 'require_venv': 1, 'python': None, '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':  │ │
│ │                        '/Users/pradyunsg/Library/Caches/pip', 'disable_pip_version_check':   │ │
│ │                        False, 'no_color': False, 'no_python_version_warning': False,         │ │
│ │                        'features_enabled': [], 'deprecated_features_enabled': [],            │ │
│ │                        'requirements': [], 'constraints': [], 'ignore_dependencies': False,  │ │
│ │                        'pre': False, 'editables': [], 'dry_run': False, 'target_dir': None,  │ │
│ │                        'platforms': None, 'python_version': None, 'implementation': None,    │ │
│ │                        'abis': None, 'use_user_site': False, 'root_path': None,              │ │
│ │                        'prefix_path': None, 'src_dir':                                       │ │
│ │                        '/Users/pradyunsg/Developer/github/pip/.venv/src', 'upgrade': None,   │ │
│ │                        'upgrade_strategy': 'only-if-needed', 'force_reinstall': None,        │ │
│ │                        'ignore_installed': None, 'ignore_requires_python': None,             │ │
│ │                        'build_isolation': True, 'use_pep517': None, 'check_build_deps':      │ │
│ │                        False, 'config_settings': None, 'install_options': None,              │ │
│ │                        'global_options': None, 'compile': True, 'warn_script_location':      │ │
│ │                        True, 'warn_about_conflicts': True, 'format_control':                 │ │
│ │                        FormatControl(set(), set()), 'prefer_binary': False,                  │ │
│ │                        'require_hashes': False, 'progress_bar': 'on', 'root_user_action':    │ │
│ │                        'warn', 'index_url': 'https://pypi.org/simple', 'extra_index_urls':   │ │
│ │                        [], 'no_index': False, 'find_links': [], 'json_report_file': None,    │ │
│ │                        'no_clean': False}>                                                   │ │
│ │             preparer = <pip._internal.operations.prepare.RequirementPreparer object at       │ │
│ │                        0x1064bfbb0>                                                          │ │
│ │                  req = <InstallRequirement object: my-test-pkg==1.2.3 from                   │ │
│ │                        file:///private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-any.whl       │ │
│ │                        editable=False>                                                       │ │
│ │                 reqs = [                                                                     │ │
│ │                        │   <InstallRequirement object: my-test-pkg==1.2.3 from               │ │
│ │                        file:///private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-any.whl       │ │
│ │                        editable=False>                                                       │ │
│ │                        ]                                                                     │ │
│ │             resolver = <pip._internal.resolution.resolvelib.resolver.Resolver object at      │ │
│ │                        0x1064bfd60>                                                          │ │
│ │                 self = <pip._internal.commands.install.InstallCommand object at 0x106126d10> │ │
│ │              session = <pip._internal.network.session.PipSession object at 0x106427400>      │ │
│ │        target_python = <pip._internal.models.target_python.TargetPython object at            │ │
│ │                        0x10643dfc0>                                                          │ │
│ │      target_temp_dir = None                                                                  │ │
│ │ target_temp_dir_path = None                                                                  │ │
│ │     upgrade_strategy = 'to-satisfy-only'                                                     │ │
│ │          wheel_cache = <pip._internal.cache.WheelCache object at 0x1064bdf00>                │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_internal/resolution/resolvelib/resolver.py:92 in  │
│ resolve                                                                                          │
│                                                                                                  │
│    89 │   │                                                                                      │
│    90 │   │   try:                                                                               │
│    91 │   │   │   try_to_avoid_resolution_too_deep = 2000000                                     │
│ ❱  92 │   │   │   result = self._result = resolver.resolve(                                      │
│    93 │   │   │   │   collected.requirements, max_rounds=try_to_avoid_resolution_too_deep        │
│    94 │   │   │   )                                                                              │
│    95                                                                                            │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │           check_supported_wheels = True                                                      │ │
│ │                        collected = CollectedRootRequirements(                                │ │
│ │                                    │   requirements=[                                        │ │
│ │                                    │   │                                                     │ │
│ │                                    ExplicitRequirement(LinkCandidate('file:///private/tmp/f… │ │
│ │                                    │   ],                                                    │ │
│ │                                    │   constraints={},                                       │ │
│ │                                    │   user_requested={'my-test-pkg': 0}                     │ │
│ │                                    )                                                         │ │
│ │                         provider = <pip._internal.resolution.resolvelib.provider.PipProvider │ │
│ │                                    object at 0x106522320>                                    │ │
│ │                         reporter = <pip._internal.resolution.resolvelib.reporter.PipReporter │ │
│ │                                    object at 0x106552f50>                                    │ │
│ │                         resolver = <pip._vendor.resolvelib.resolvers.Resolver object at      │ │
│ │                                    0x106552f80>                                              │ │
│ │                        root_reqs = [                                                         │ │
│ │                                    │   <InstallRequirement object: my-test-pkg==1.2.3 from   │ │
│ │                                    file:///private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-… │ │
│ │                                    editable=False>                                           │ │
│ │                                    ]                                                         │ │
│ │                             self = <pip._internal.resolution.resolvelib.resolver.Resolver    │ │
│ │                                    object at 0x1064bfd60>                                    │ │
│ │ try_to_avoid_resolution_too_deep = 2000000                                                   │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/resolvelib/resolvers.py:481 in resolve     │
│                                                                                                  │
│   478 │   │   │   `max_rounds` argument.                                                         │
│   479 │   │   """                                                                                │
│   480 │   │   resolution = Resolution(self.provider, self.reporter)                              │
│ ❱ 481 │   │   state = resolution.resolve(requirements, max_rounds=max_rounds)                    │
│   482 │   │   return _build_result(state)                                                        │
│   483                                                                                            │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │   max_rounds = 2000000                                                                       │ │
│ │ requirements = [                                                                             │ │
│ │                │                                                                             │ │
│ │                ExplicitRequirement(LinkCandidate('file:///private/tmp/foo/dist/my_test_pkg-… │ │
│ │                ]                                                                             │ │
│ │   resolution = <pip._vendor.resolvelib.resolvers.Resolution object at 0x106552aa0>           │ │
│ │         self = <pip._vendor.resolvelib.resolvers.Resolver object at 0x106552f80>             │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/resolvelib/resolvers.py:373 in resolve     │
│                                                                                                  │
│   370 │   │   │                                                                                  │
│   371 │   │   │   # Choose the most preferred unpinned criterion to try.                         │
│   372 │   │   │   name = min(unsatisfied_names, key=self._get_preference)                        │
│ ❱ 373 │   │   │   failure_causes = self._attempt_to_pin_criterion(name)                          │
│   374 │   │   │                                                                                  │
│   375 │   │   │   if failure_causes:                                                             │
│   376 │   │   │   │   causes = [i for c in failure_causes for i in c.information]                │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │        max_rounds = 2000000                                                                  │ │
│ │              name = 'my-test-pkg'                                                            │ │
│ │                 r = ExplicitRequirement(LinkCandidate('file:///private/tmp/foo/dist/my_test… │ │
│ │      requirements = [                                                                        │ │
│ │                     │                                                                        │ │
│ │                     ExplicitRequirement(LinkCandidate('file:///private/tmp/foo/dist/my_test… │ │
│ │                     ]                                                                        │ │
│ │       round_index = 0                                                                        │ │
│ │              self = <pip._vendor.resolvelib.resolvers.Resolution object at 0x106552aa0>      │ │
│ │ unsatisfied_names = ['my-test-pkg']                                                          │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/resolvelib/resolvers.py:213 in             │
│ _attempt_to_pin_criterion                                                                        │
│                                                                                                  │
│   210 │   │   causes = []                                                                        │
│   211 │   │   for candidate in criterion.candidates:                                             │
│   212 │   │   │   try:                                                                           │
│ ❱ 213 │   │   │   │   criteria = self._get_updated_criteria(candidate)                           │
│   214 │   │   │   except RequirementsConflicted as e:                                            │
│   215 │   │   │   │   causes.append(e.criterion)                                                 │
│   216 │   │   │   │   continue                                                                   │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ candidate = LinkCandidate('file:///private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-any.whl') │ │
│ │    causes = []                                                                               │ │
│ │ criterion = Criterion((ExplicitRequirement(LinkCandidate('file:///private/tmp/foo/dist/my_t… │ │
│ │             via=None))                                                                       │ │
│ │      name = 'my-test-pkg'                                                                    │ │
│ │      self = <pip._vendor.resolvelib.resolvers.Resolution object at 0x106552aa0>              │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/resolvelib/resolvers.py:203 in             │
│ _get_updated_criteria                                                                            │
│                                                                                                  │
│   200 │                                                                                          │
│   201 │   def _get_updated_criteria(self, candidate):                                            │
│   202 │   │   criteria = self.state.criteria.copy()                                              │
│ ❱ 203 │   │   for requirement in self._p.get_dependencies(candidate=candidate):                  │
│   204 │   │   │   self._add_to_criteria(criteria, requirement, parent=candidate)                 │
│   205 │   │   return criteria                                                                    │
│   206                                                                                            │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ candidate = LinkCandidate('file:///private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-any.whl') │ │
│ │  criteria = {                                                                                │ │
│ │             │   'my-test-pkg':                                                               │ │
│ │             Criterion((ExplicitRequirement(LinkCandidate('file:///private/tmp/foo/dist/my_t… │ │
│ │             via=None))                                                                       │ │
│ │             }                                                                                │ │
│ │      self = <pip._vendor.resolvelib.resolvers.Resolution object at 0x106552aa0>              │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_internal/resolution/resolvelib/provider.py:237 in │
│ get_dependencies                                                                                 │
│                                                                                                  │
│   234 │                                                                                          │
│   235 │   def get_dependencies(self, candidate: Candidate) -> Sequence[Requirement]:             │
│   236 │   │   with_requires = not self._ignore_dependencies                                      │
│ ❱ 237 │   │   return [r for r in candidate.iter_dependencies(with_requires) if r is not None]    │
│   238 │                                                                                          │
│   239 │   @staticmethod                                                                          │
│   240 │   def is_backtrack_cause(                                                                │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │     candidate = LinkCandidate('file:///private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-any.… │ │
│ │          self = <pip._internal.resolution.resolvelib.provider.PipProvider object at          │ │
│ │                 0x106522320>                                                                 │ │
│ │ with_requires = True                                                                         │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_internal/resolution/resolvelib/provider.py:237 in │
│ <listcomp>                                                                                       │
│                                                                                                  │
│   234 │                                                                                          │
│   235 │   def get_dependencies(self, candidate: Candidate) -> Sequence[Requirement]:             │
│   236 │   │   with_requires = not self._ignore_dependencies                                      │
│ ❱ 237 │   │   return [r for r in candidate.iter_dependencies(with_requires) if r is not None]    │
│   238 │                                                                                          │
│   239 │   @staticmethod                                                                          │
│   240 │   def is_backtrack_cause(                                                                │
│                                                                                                  │
│ ╭────────────────────────────────────────── locals ───────────────────────────────────────────╮  │
│ │ .0 = <generator object _InstallRequirementBackedCandidate.iter_dependencies at 0x1064b7df0> │  │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯  │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_internal/resolution/resolvelib/candidates.py:247  │
│ in iter_dependencies                                                                             │
│                                                                                                  │
│   244 │   │   return dist                                                                        │
│   245 │                                                                                          │
│   246 │   def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]:   │
│ ❱ 247 │   │   requires = self.dist.iter_dependencies() if with_requires else ()                  │
│   248 │   │   for r in requires:                                                                 │
│   249 │   │   │   yield self._factory.make_requirement_from_spec(str(r), self._ireq)             │
│   250 │   │   yield self._factory.make_requires_python_requirement(self.dist.requires_python)    │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │          self = LinkCandidate('file:///private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-any.… │ │
│ │ with_requires = True                                                                         │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_internal/metadata/pkg_resources.py:216 in         │
│ iter_dependencies                                                                                │
│                                                                                                  │
│   213 │   def iter_dependencies(self, extras: Collection[str] = ()) -> Iterable[Requirement]:    │
│   214 │   │   if extras:  # pkg_resources raises on invalid extras, so we sanitize.              │
│   215 │   │   │   extras = frozenset(extras).intersection(self._dist.extras)                     │
│ ❱ 216 │   │   return self._dist.requires(extras)                                                 │
│   217 │                                                                                          │
│   218 │   def iter_provided_extras(self) -> Iterable[str]:                                       │
│   219 │   │   return self._dist.extras                                                           │
│                                                                                                  │
│ ╭─────────────────────────────────────── locals ────────────────────────────────────────╮        │
│ │ extras = ()                                                                           │        │
│ │   self = my-test-pkg 1.2.3 (/private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-any.whl) │        │
│ ╰───────────────────────────────────────────────────────────────────────────────────────╯        │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/pkg_resources/__init__.py:2736 in requires │
│                                                                                                  │
│   2733 │                                                                                         │
│   2734 │   def requires(self, extras=()):                                                        │
│   2735 │   │   """List of Requirements needed for this distro if `extras` are used"""            │
│ ❱ 2736 │   │   dm = self._dep_map                                                                │
│   2737 │   │   deps = []                                                                         │
│   2738 │   │   deps.extend(dm.get(None, ()))                                                     │
│   2739 │   │   for ext in extras:                                                                │
│                                                                                                  │
│ ╭─────────────────────────────────────── locals ────────────────────────────────────────╮        │
│ │ extras = ()                                                                           │        │
│ │   self = my-test-pkg 1.2.3 (/private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-any.whl) │        │
│ ╰───────────────────────────────────────────────────────────────────────────────────────╯        │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/pkg_resources/__init__.py:3023 in _dep_map │
│                                                                                                  │
│   3020 │   │   try:                                                                              │
│   3021 │   │   │   return self.__dep_map                                                         │
│   3022 │   │   except AttributeError:                                                            │
│ ❱ 3023 │   │   │   self.__dep_map = self._compute_dependencies()                                 │
│   3024 │   │   │   return self.__dep_map                                                         │
│   3025 │                                                                                         │
│   3026 │   def _compute_dependencies(self):                                                      │
│                                                                                                  │
│ ╭────────────────────────────────────── locals ───────────────────────────────────────╮          │
│ │ self = my-test-pkg 1.2.3 (/private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-any.whl) │          │
│ ╰─────────────────────────────────────────────────────────────────────────────────────╯          │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/pkg_resources/__init__.py:3040 in          │
│ _compute_dependencies                                                                            │
│                                                                                                  │
│   3037 │   │   │   │   if not req.marker or req.marker.evaluate({'extra': extra}):               │
│   3038 │   │   │   │   │   yield req                                                             │
│   3039 │   │                                                                                     │
│ ❱ 3040 │   │   common = frozenset(reqs_for_extra(None))                                          │
│   3041 │   │   dm[None].extend(common)                                                           │
│   3042 │   │                                                                                     │
│   3043 │   │   for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []:               │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │             dm = {None: []}                                                                  │ │
│ │            req = "requests (<3.0.0) ; extra == '3.2.1'"                                      │ │
│ │           reqs = [Requirement.parse('requests<3.0.0; extra == "3.2.1"')]                     │ │
│ │ reqs_for_extra = <function                                                                   │ │
│ │                  DistInfoDistribution._compute_dependencies.<locals>.reqs_for_extra at       │ │
│ │                  0x106541e10>                                                                │ │
│ │           self = my-test-pkg 1.2.3                                                           │ │
│ │                  (/private/tmp/foo/dist/my_test_pkg-1.2.3-py3-none-any.whl)                  │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/pkg_resources/__init__.py:3037 in          │
│ reqs_for_extra                                                                                   │
│                                                                                                  │
│   3034 │   │                                                                                     │
│   3035 │   │   def reqs_for_extra(extra):                                                        │
│   3036 │   │   │   for req in reqs:                                                              │
│ ❱ 3037 │   │   │   │   if not req.marker or req.marker.evaluate({'extra': extra}):               │
│   3038 │   │   │   │   │   yield req                                                             │
│   3039 │   │                                                                                     │
│   3040 │   │   common = frozenset(reqs_for_extra(None))                                          │
│                                                                                                  │
│ ╭──────────────────────────── locals ─────────────────────────────╮                              │
│ │ extra = None                                                    │                              │
│ │   req = Requirement.parse('requests<3.0.0; extra == "3.2.1"')   │                              │
│ │  reqs = [Requirement.parse('requests<3.0.0; extra == "3.2.1"')] │                              │
│ ╰─────────────────────────────────────────────────────────────────╯                              │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/packaging/markers.py:304 in evaluate       │
│                                                                                                  │
│   301 │   │   if environment is not None:                                                        │
│   302 │   │   │   current_environment.update(environment)                                        │
│   303 │   │                                                                                      │
│ ❱ 304 │   │   return _evaluate_markers(self._markers, current_environment)                       │
│   305                                                                                            │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ current_environment = {                                                                      │ │
│ │                       │   'implementation_name': 'cpython',                                  │ │
│ │                       │   'implementation_version': '3.10.1',                                │ │
│ │                       │   'os_name': 'posix',                                                │ │
│ │                       │   'platform_machine': 'arm64',                                       │ │
│ │                       │   'platform_release': '21.6.0',                                      │ │
│ │                       │   'platform_system': 'Darwin',                                       │ │
│ │                       │   'platform_version': 'Darwin Kernel Version 21.6.0: Wed Aug 10      │ │
│ │                       14:28:35 PDT 2022; root:xnu-8020.141.5~'+21,                           │ │
│ │                       │   'python_full_version': '3.10.1',                                   │ │
│ │                       │   'platform_python_implementation': 'CPython',                       │ │
│ │                       │   'python_version': '3.10',                                          │ │
│ │                       │   ... +2                                                             │ │
│ │                       }                                                                      │ │
│ │         environment = {'extra': None}                                                        │ │
│ │                self = <Marker('extra == "3.2.1"')>                                           │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/packaging/markers.py:240 in                │
│ _evaluate_markers                                                                                │
│                                                                                                  │
│   237 │   │   │   │   lhs_value = lhs.value                                                      │
│   238 │   │   │   │   rhs_value = _get_env(environment, rhs.value)                               │
│   239 │   │   │                                                                                  │
│ ❱ 240 │   │   │   groups[-1].append(_eval_op(lhs_value, op, rhs_value))                          │
│   241 │   │   else:                                                                              │
│   242 │   │   │   assert marker in ["and", "or"]                                                 │
│   243 │   │   │   if marker == "or":                                                             │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ environment = {                                                                              │ │
│ │               │   'implementation_name': 'cpython',                                          │ │
│ │               │   'implementation_version': '3.10.1',                                        │ │
│ │               │   'os_name': 'posix',                                                        │ │
│ │               │   'platform_machine': 'arm64',                                               │ │
│ │               │   'platform_release': '21.6.0',                                              │ │
│ │               │   'platform_system': 'Darwin',                                               │ │
│ │               │   'platform_version': 'Darwin Kernel Version 21.6.0: Wed Aug 10 14:28:35 PDT │ │
│ │               2022; root:xnu-8020.141.5~'+21,                                                │ │
│ │               │   'python_full_version': '3.10.1',                                           │ │
│ │               │   'platform_python_implementation': 'CPython',                               │ │
│ │               │   'python_version': '3.10',                                                  │ │
│ │               │   ... +2                                                                     │ │
│ │               }                                                                              │ │
│ │      groups = [[]]                                                                           │ │
│ │         lhs = <Variable('extra')>                                                            │ │
│ │   lhs_value = None                                                                           │ │
│ │      marker = (<Variable('extra')>, <Op('==')>, <Value('3.2.1')>)                            │ │
│ │     markers = [(<Variable('extra')>, <Op('==')>, <Value('3.2.1')>)]                          │ │
│ │          op = <Op('==')>                                                                     │ │
│ │         rhs = <Value('3.2.1')>                                                               │ │
│ │   rhs_value = '3.2.1'                                                                        │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/packaging/markers.py:195 in _eval_op       │
│                                                                                                  │
│   192 │   except InvalidSpecifier:                                                               │
│   193 │   │   pass                                                                               │
│   194 │   else:                                                                                  │
│ ❱ 195 │   │   return spec.contains(lhs)                                                          │
│   196 │                                                                                          │
│   197 │   oper: Optional[Operator] = _operators.get(op.serialize())                              │
│   198 │   if oper is None:                                                                       │
│                                                                                                  │
│ ╭─────────── locals ────────────╮                                                                │
│ │  lhs = None                   │                                                                │
│ │   op = <Op('==')>             │                                                                │
│ │  rhs = '3.2.1'                │                                                                │
│ │ spec = <Specifier('==3.2.1')> │                                                                │
│ ╰───────────────────────────────╯                                                                │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/packaging/specifiers.py:178 in contains    │
│                                                                                                  │
│   175 │   │                                                                                      │
│   176 │   │   # Normalize item to a Version or LegacyVersion, this allows us to have             │
│   177 │   │   # a shortcut for ``"2.0" in Specifier(">=2")                                       │
│ ❱ 178 │   │   normalized_item = self._coerce_version(item)                                       │
│   179 │   │                                                                                      │
│   180 │   │   # Determine if we should be supporting prereleases in this specifier               │
│   181 │   │   # or not, if we do not support prereleases than we can short circuit               │
│                                                                                                  │
│ ╭─────────────── locals ───────────────╮                                                         │
│ │        item = None                   │                                                         │
│ │ prereleases = False                  │                                                         │
│ │        self = <Specifier('==3.2.1')> │                                                         │
│ ╰──────────────────────────────────────╯                                                         │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/packaging/specifiers.py:146 in             │
│ _coerce_version                                                                                  │
│                                                                                                  │
│   143 │                                                                                          │
│   144 │   def _coerce_version(self, version: UnparsedVersion) -> ParsedVersion:                  │
│   145 │   │   if not isinstance(version, (LegacyVersion, Version)):                              │
│ ❱ 146 │   │   │   version = parse(version)                                                       │
│   147 │   │   return version                                                                     │
│   148 │                                                                                          │
│   149 │   @property                                                                              │
│                                                                                                  │
│ ╭───────────── locals ─────────────╮                                                             │
│ │    self = <Specifier('==3.2.1')> │                                                             │
│ │ version = None                   │                                                             │
│ ╰──────────────────────────────────╯                                                             │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/packaging/version.py:49 in parse           │
│                                                                                                  │
│    46 │   a valid PEP 440 version or a legacy version.                                           │
│    47 │   """                                                                                    │
│    48 │   try:                                                                                   │
│ ❱  49 │   │   return Version(version)                                                            │
│    50 │   except InvalidVersion:                                                                 │
│    51 │   │   return LegacyVersion(version)                                                      │
│    52                                                                                            │
│                                                                                                  │
│ ╭──── locals ────╮                                                                               │
│ │ version = None │                                                                               │
│ ╰────────────────╯                                                                               │
│                                                                                                  │
│ /Users/pradyunsg/Developer/github/pip/src/pip/_vendor/packaging/version.py:264 in __init__       │
│                                                                                                  │
│   261 │   def __init__(self, version: str) -> None:                                              │
│   262 │   │                                                                                      │
│   263 │   │   # Validate the version and parse it into pieces                                    │
│ ❱ 264 │   │   match = self._regex.search(version)                                                │
│   265 │   │   if not match:                                                                      │
│   266 │   │   │   raise InvalidVersion(f"Invalid version: '{version}'")                          │
│   267                                                                                            │
│                                                                                                  │
│ ╭─────────────────────────────── locals ────────────────────────────────╮                        │
│ │    self = <repr-error "'Version' object has no attribute '_version'"> │                        │
│ │ version = None                                                        │                        │
│ ╰───────────────────────────────────────────────────────────────────────╯                        │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
TypeError: expected string or bytes-like object
q0w commented 2 years ago

Why not just do the same https://github.com/pypa/pip/pull/11112 (passing empty string extra instead of None) in https://github.com/pypa/pip/blob/a8ba0eec6ac3c1f6cf23f1e2e4c64954bd7a08ed/src/pip/_vendor/pkg_resources/__init__.py#L3035-L3040

---  common = frozenset(reqs_for_extra(None)) 
+++  common = frozenset(reqs_for_extra(''))

This change also needs new packaging release for pkg_resources because of this https://github.com/pypa/packaging/pull/545. I tried to write some tests but it fails without this pr


# pkg_resources/tests/test_resources.py
    def test_marker_evaluation_with_extras2(self):
        """Extras are also evaluated as markers at resolution time."""
        ad = pkg_resources.Environment([])
        ws = WorkingSet([])
        Foo = Distribution.from_filename(
            "/foo_dir/Foo-1.2.dist-info",
            metadata=Metadata(("METADATA", "Provides-Extra: 3.2.1\n"
                               "Requires-Dist: quux; extra=='3.2.1'"))
        )
        ad.add(Foo)
        assert list(ws.resolve(parse_requirements("Foo"), ad)) == [Foo]
        quux = Distribution.from_filename("/foo_dir/quux-1.0.dist-info")
        ad.add(quux)
        res = list(ws.resolve(parse_requirements("Foo[3.2.1]"), ad))
        assert res == [Foo, quux]
q0w commented 1 year ago

It was fixed, I can't reproduce with 23.1.2

webknjaz commented 9 months ago

It was fixed, I can't reproduce with 23.1.2

Closing, then.