Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LocalPackageResolver: Handle multiple package dirs inside one Python env #318

Merged
merged 1 commit into from
May 30, 2023

Conversation

jherland
Copy link
Member

@jherland jherland commented Apr 26, 2023

Until now, the --pyenv option has accepted any path that points inside a Python environment, e.g.:

  • .venv/
  • .venv/bin
  • .venv/bin/python
  • .venv/lib
  • .venv/lib/python3.11
  • .venv/lib/python3.11/site-packages

These all unambiguously point to the Python environment rooted at .venv/, and they will all result in LocalPackageResolver looking for packages inside .venv/lib/python3.11/site-packages.

But this is all assuming that .venv/lib/python3.11/site-packages is the only directory inside that Python environment that can hold Python packages.

We could have a situation where there are multiple site-packages dirs inside .venv/:

  • .venv/lib/python3.9/site-packages
  • .venv/lib/python3.11/site-packages

In this case1, things start to go off the rails. Before this commit, we would first follow parents until .venv/ was found, and then we would use the first result of path.glob("lib/python?.*/site-packages"), in other words, they would end up using .venv/lib/python3.9/site-packages.

This is maybe not what the user intended if they passed in .venv/ or .venv/lib, but it's certainly not what the user wanted if they passed in a full/versioned path like .venv/lib/python3.11/site-packages.

There are two things to be fixed here, and this commit fixes both:

  1. When passing the path to a Python environment, there might be multiple package dirs hiding inside. In other words:

    determine_package_dir(cls, path: Path) -> Optional[Path]
    

    is NOT a suitable signature, we rather need the more general:

    find_package_dirs(cls, path: Path) -> Iterator[Path]
    

    signature, which is able to return zero, one, or more results. And the surrounding code should handle this by adding all matching package dirs to the LocalPackageResolver.package_dirs.

  2. We should also filter the package dirs found inside the given Python environment to exclude those that are not relative to the given path. That is, if you pass .venv/lib/python3.11/site-packages, you should only get .venv/lib/python3.11/site-packages back, and not .venv/lib/python3.9/site-packages, even if that also exists within the same Python environment.

As a result, a user can now specify --pyenv .venv to get all Python packages within any .venv/lib/python?.*/site-packages/ directory, OR they can specify --pyenv .venv/lib/python3.11/site-packages to be very explicit about which package directory they do want.

The only "casualty" of this change is that specifying a path within the environments that is not a parent of any package dir (for example: --pyenv .venv/bin/python) is no longer supported. This was already a corner case, and I don't think we lose much by no longer supporting it.

Footnotes

  1. This whole argument is somewhat strained when using .venv/ virtualenvs as an example: virtualenvs typically only exist within the context of a single Python version (the one in .venv/bin/python), and there is always only one site-packages dir in a virtualenv. However, the same argument applies equally to system environments under e.g. /usr/ or /usr/local/, and they certainly apply to __pypackages__ environments that are not bound to a specific interpreter.

@jherland jherland self-assigned this Apr 26, 2023
@jherland jherland requested review from mknorps and Nour-Mws April 26, 2023 12:52
@jherland jherland changed the title LocalPackageResolver: Handle multiple package dirs inside one Python env LocalPackageResolver: Handle multiple package dirs inside one Python env Apr 26, 2023
@jherland jherland added this to the Mapping strategy milestone Apr 26, 2023
@jherland jherland force-pushed the jherland/multiple-pyenvs branch 2 times, most recently from d03225a to 1ade7d9 Compare May 6, 2023 01:02
@jherland jherland force-pushed the jherland/package_dirs-vs-pyenvs branch from 3dd1546 to 32e8655 Compare May 6, 2023 01:17
@jherland jherland force-pushed the jherland/multiple-pyenvs branch from 517775d to a10e43a Compare May 8, 2023 13:25
Base automatically changed from jherland/multiple-pyenvs to main May 8, 2023 13:50
@tweag tweag deleted a comment from dpulls bot May 8, 2023
@jherland jherland changed the base branch from main to jherland/multiple-pyenvs-2 May 8, 2023 14:21
@jherland jherland force-pushed the jherland/multiple-pyenvs-2 branch from 1b5204a to 5c10aa5 Compare May 8, 2023 14:27
@jherland jherland force-pushed the jherland/package_dirs-vs-pyenvs branch from 32e8655 to a925605 Compare May 8, 2023 15:13
@jherland jherland force-pushed the jherland/multiple-pyenvs-2 branch from 5c10aa5 to 1c60455 Compare May 9, 2023 23:29
@jherland jherland force-pushed the jherland/package_dirs-vs-pyenvs branch from a925605 to 33449fa Compare May 9, 2023 23:33
@jherland jherland force-pushed the jherland/multiple-pyenvs-2 branch 2 times, most recently from 4f26b83 to af07e8e Compare May 11, 2023 14:16
Base automatically changed from jherland/multiple-pyenvs-2 to main May 11, 2023 14:22
@dpulls
Copy link

dpulls bot commented May 11, 2023

🎉 All dependencies have been resolved !

@jherland jherland force-pushed the jherland/package_dirs-vs-pyenvs branch from 33449fa to 5f552c5 Compare May 12, 2023 09:16
Copy link
Collaborator

@mknorps mknorps left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @jherland !
It looks like good handling of multiple Python version environment handling. I think we are very good at making sure that many corner cases are covered in FawltyDeps 💯

I have some small suggestions and a question if we need the suppress mechanism. Otherwise, I think this is good to go :)

Copy link
Collaborator

@mknorps mknorps left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @jherland !
It looks like good handling of multiple Python version environment handling. I think we are very good at making sure that many corner cases are covered in FawltyDeps 💯

I have some small suggestions and a question if we need the suppress mechanism. Otherwise, I think this is good to go :)

Until now, the --pyenv option has accepted any path that points inside a
Python environment, e.g.:
 - .venv/
 - .venv/bin
 - .venv/bin/python
 - .venv/lib
 - .venv/lib/python3.11
 - .venv/lib/python3.11/site-packages

These all unambiguously point to the Python environment rooted at
.venv/, and they will all result in LocalPackageResolver looking for
packages inside .venv/lib/python3.11/site-packages.

But this is all assuming that .venv/lib/python3.11/site-packages is the
_only_ directory inside that Python environment that can hold Python
packages.

We could have a situation where there are _multiple_ site-packages dirs
inside .venv/:

 - .venv/lib/python3.9/site-packages
 - .venv/lib/python3.11/site-packages

In this case[1], things start to go off the rails. Before this commit,
we would first follow parents until .venv/ was found, and then we would
use the first result of path.glob("lib/python?.*/site-packages"), in
other words, they would end up using .venv/lib/python3.9/site-packages.

This is _maybe_ not what the user intended if they passed in .venv/ or
.venv/lib, but it's _certainly_ not what the user wanted if they passed
in a full/versioned path like .venv/lib/python3.11/site-packages.

There are two things to be fixed here, and this commit fixes both:

 1. When passing the path to a Python environment, there might be
    _multiple_ package dirs hiding inside. In other words:

        determine_package_dir(cls, path: Path) -> Optional[Path]

    is NOT a suitable signature, we rather need the more general:

        find_package_dirs(cls, path: Path) -> Iterator[Path]:

    signature, which is able to return zero, one, or more results.
    And the surrounding code should handle this by adding _all_
    matching package dirs to the LocalPackageResolver.package_dirs.

 2. We should also _filter_ the package dirs found inside the given
    Python environment to _exclude_ those that are not relative to the
    given path. That is, if you pass .venv/lib/python3.11/site-packages,
    you should only get .venv/lib/python3.11/site-packages back, and not
    .venv/lib/python3.9/site-packages, even if that also exists within
    the same Python environment.

As a result, a user can now specify `--pyenv .venv` to get _all_ Python
packages within any .venv/lib/python?.*/site-packages/ directory, OR
they can specify `--pyenv .venv/lib/python3.11/site-packages` to be very
explicit about which package directory they do want.

The only "casualty" of this change is that specifying a path within the
environments that is _not_ a parent of any package dir (for example:
`--pyenv .venv/bin/python`) is no longer supported. This was already a
corner case, and I don't think we lose much by no longer supporting it.

[1]: This whole argument is somewhat strained when using .venv/
virtualenvs as an example: virtualenvs typically only exist within the
context of a _single_ Python version (the one in .venv/bin/python), and
there is always only one site-packages dir in a virtualenv.
However, the same argument applies equally to system environments under
e.g. /usr/ or /usr/local/, and they certainly apply to __pypackages__
environments that are not bound to a specific interpreter.
@jherland jherland force-pushed the jherland/package_dirs-vs-pyenvs branch from 5f552c5 to e0d7c83 Compare May 30, 2023 11:27
@jherland jherland merged commit ed2d0cc into main May 30, 2023
@jherland jherland deleted the jherland/package_dirs-vs-pyenvs branch May 30, 2023 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants