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
Eliminate double book keeping in extern
, just using _vendor
directly
#4330
Conversation
extern
and just use _vendor
directlyextern
, just using _vendor
directly
NOTE: There are some people out there importing Maybe we should have a deprecation here? |
@jaraco is this an approach you would be interested for us to follow in setuptools? |
IIRC, my intention for My hope/expectation was that at some point the vendored packages would be removed in all but a few isolated scenarios and real dependencies would be used. That vision never panned out.
Although I made
My hope was that setuptools (and maybe pkg_resources) could simply import these dependencies instead of hard-coding the imports from their vendored location. I was thinking something like: - from setuptools.extern import platformdirs
+ import platformdirs And then early in the import of I'm not confident that transitioning to a hard-coded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I share @jaraco 's concerns about having to hard-code _vendor
in the import.
In my mind, the best-case scenario would be if import packaging
used the system's if it was already present, then fallbacks to _vendor
.
For pkg_resources
we could likely have a bit of logic really early in __init__
that adds to path if missing.
Setuptools isn't as easy with its multiple importable modules. Maybe every module that uses a vendored dependency should call a util function early that does that check and setup? How does the distutil hack do it? Maybe just adding that helper to __init__
is sufficient?
I'm not as experienced with advanced features of python's import system and setuptools' intricacies, sorry if my suggestions don't make sense.
Edit
if the vendored packages were present, they'd be imported, but if they were missing, the dependencies could be loaded from sys.path.
If you prepend _vendor
on the sys.path
so it has priority if a module is found. Wouldn't it work that way?
Anyway, here's a handful of comments concerning type-checking that would be useful even outside of this PR.
from ._vendor.packaging.requirements import ( | ||
# These imports are explicit only to avoid mypy error | ||
InvalidRequirement as _packaging_InvalidRequirement, | ||
Requirement as _packaging_Requirement, | ||
) | ||
|
||
__import__('pkg_resources.extern.packaging.version') | ||
__import__('pkg_resources.extern.packaging.specifiers') | ||
__import__('pkg_resources.extern.packaging.requirements') | ||
__import__('pkg_resources.extern.packaging.markers') | ||
__import__('pkg_resources.extern.packaging.utils') | ||
__import__('pkg_resources._vendor.packaging.version') | ||
__import__('pkg_resources._vendor.packaging.specifiers') | ||
__import__('pkg_resources._vendor.packaging.requirements') | ||
__import__('pkg_resources._vendor.packaging.markers') | ||
__import__('pkg_resources._vendor.packaging.utils') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this direct import might render __import__('pkg_resources._vendor.packaging.requirements')
useless?
On that note I also don't see any packaging.specifiers
in this module.
packaging.version
is only used for Version
and invalidVersion
.
packaging.markers
is only used for Marker
and InvalidMarker
.
packaging.utils
is only used for canonicalize_name
.
Unless I misunderstand what else these imports could be for, they can likely be removed even outside this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since I couldn't do a suggestion over some deleted lines, here's what it'd look like:
from ._vendor import platformdirs
from ._vendor.packaging.markers import Marker, InvalidMarker
from ._vendor.packaging.requirements import (
InvalidRequirement as _packaging_InvalidRequirement,
Requirement as _packaging_Requirement,
)
from ._vendor.packaging.utils import canonicalize_name
from ._vendor.packaging.version import Version, InvalidVersion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see...
My approach here was not to differ much from the original content. I just wanted to make mypy
stop failing.
Removing __import__('pkg_resources._vendor.packaging.requirements')
should be probably fine. But the other ones, maybe it is a separated PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I extracted what I saw as good changes on their own into #4348
mypy.ini
Outdated
[mypy-pkg_resources._vendor.*,setuptools._vendor.*,setuptools.config._validate_pyproject.*,setuptools.tests.*] | ||
# Even when excluded there might be problems: python/mypy/issues/11936#issuecomment-1466764006 | ||
# - Avoid raising issues when importing from "_vendor" modules | ||
# - Avoid raising issues when importing dependencies in tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[mypy-pkg_resources._vendor.*,setuptools._vendor.*,setuptools.config._validate_pyproject.*,setuptools.tests.*] | |
# Even when excluded there might be problems: python/mypy/issues/11936#issuecomment-1466764006 | |
# - Avoid raising issues when importing from "_vendor" modules | |
# - Avoid raising issues when importing dependencies in tests | |
[mypy-pkg_resources._vendor.*,setuptools._vendor.*] | |
# Avoid raising import issues in vendored modules. Even when excluded there might be problems: python/mypy/issues/11936#issuecomment-1466764006 |
Do you still need to specify tests here? These are modules that should also be found in exclude
, tests are not excluded. Originally I added it because of the dynamically imported created modules that are imported, but you type: ignore
d those, so this shouldn't be needed.
Similarly the _validate_pyproject
issue was fixed upstream.
Also seems to work locally w/o.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the current state of the repo, think we need special handling for
pkg_resources._vendor.*
setuptools._vendor.*
setuptools.config._validate_pyproject.*
setuptools.tests.*
so that we can run tests from 3.8 to 3.12. I remember trying without them and hitting some problems.
Further changes might obliviate some of those, but I did not want to extend even more this PR (e.g. using the latest version of _validate_pyproject
).
Co-authored-by: Avasam <samuel.06@hotmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much @jaraco and @Avasam for the insightful comments. I think that for now we can close this PR since it is not the direction we want to go.
My main concern was that simply adding _vendor
to sys.path
is prone to dependency version conflicts (e.g. setuptools might require a minimum version of a certain package, but that is in conflict with the version installed in the system).
Note: I think that there are some ideas here that might be worthy adopting in the code base.
I really liked the division between vendored.in
and vendored.txt
via pip-tools
since it creates a very clear documentation of what are the direct dependencies and what are the transitive dependencies (tracking the chain).
mypy.ini
Outdated
[mypy-pkg_resources._vendor.*,setuptools._vendor.*,setuptools.config._validate_pyproject.*,setuptools.tests.*] | ||
# Even when excluded there might be problems: python/mypy/issues/11936#issuecomment-1466764006 | ||
# - Avoid raising issues when importing from "_vendor" modules | ||
# - Avoid raising issues when importing dependencies in tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the current state of the repo, think we need special handling for
pkg_resources._vendor.*
setuptools._vendor.*
setuptools.config._validate_pyproject.*
setuptools.tests.*
so that we can run tests from 3.8 to 3.12. I remember trying without them and hitting some problems.
Further changes might obliviate some of those, but I did not want to extend even more this PR (e.g. using the latest version of _validate_pyproject
).
from ._vendor.packaging.requirements import ( | ||
# These imports are explicit only to avoid mypy error | ||
InvalidRequirement as _packaging_InvalidRequirement, | ||
Requirement as _packaging_Requirement, | ||
) | ||
|
||
__import__('pkg_resources.extern.packaging.version') | ||
__import__('pkg_resources.extern.packaging.specifiers') | ||
__import__('pkg_resources.extern.packaging.requirements') | ||
__import__('pkg_resources.extern.packaging.markers') | ||
__import__('pkg_resources.extern.packaging.utils') | ||
__import__('pkg_resources._vendor.packaging.version') | ||
__import__('pkg_resources._vendor.packaging.specifiers') | ||
__import__('pkg_resources._vendor.packaging.requirements') | ||
__import__('pkg_resources._vendor.packaging.markers') | ||
__import__('pkg_resources._vendor.packaging.utils') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see...
My approach here was not to differ much from the original content. I just wanted to make mypy
stop failing.
Removing __import__('pkg_resources._vendor.packaging.requirements')
should be probably fine. But the other ones, maybe it is a separated PR.
Main idea:
_vendor
directly instead ofextern
This is an investigation on #4320 (review)
Summary of changes
Intentional changes:
836168b: Modify
tool/vendored.py
so that: <------------------- this is possibly the most relevant commit for review(so we don't loose track of what needs what).
pip-compile
andvendored.in
(direct dependencies)==>
vendored.txt
. See e09f4ae.pkg_resources
andsetuptools
so that it is easier for "de-vendoring" (this is done via
--constraint
inpip
).2c45906: Remove
setuptools.extern
andpkg_resouces.extern
.Collateral changes:
extern
imports with_vendor
Changes that were needed just to make the tests pass:
mypy
happy (there is one actual fix).monkeypatch.setattr
started failing in Pytest 8.1.2 (setuptools CI) pytest-dev/pytest#12254.Closes
Pull Request Checklist
newsfragments/
.(See documentation for details)
Drawbacks
The separation between the direct dependencies (
vendored.in
) and the automatic logging and documentation of the transitive dependencies (vendored.txt
) is nice from some point-of-view.However, it also requires that we run
tox -e vendor
using the lowest version of Python supported bysetuptools
(otherwise conditional environment markers may be ignored). This may be easy to forget.