-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Ensure writable paths are used for wheel installer #9014
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
from poetry.utils.env.exceptions import EnvCommandError | ||
from poetry.utils.env.site_packages import SitePackages | ||
from poetry.utils.helpers import get_real_windows_path | ||
from poetry.utils.helpers import is_dir_writable | ||
|
||
|
||
if TYPE_CHECKING: | ||
|
@@ -55,6 +56,7 @@ def __init__(self, path: Path, base: Path | None = None) -> None: | |
self._marker_env: dict[str, Any] | None = None | ||
self._site_packages: SitePackages | None = None | ||
self._paths: dict[str, str] | None = None | ||
self._installer_scheme_dict: dict[str, str] | None = None | ||
self._supported_tags: list[Tag] | None = None | ||
self._purelib: Path | None = None | ||
self._platlib: Path | None = None | ||
|
@@ -242,6 +244,41 @@ def paths(self) -> dict[str, str]: | |
|
||
return self._paths | ||
|
||
@property | ||
def installer_scheme_dict(self) -> dict[str, str]: | ||
""" | ||
This property exists to allow cases where system environment paths are not writable and | ||
user site is enabled. This enables us to ensure packages (wheels) are correctly installed | ||
into directories where the current user can write to. | ||
""" | ||
if self._installer_scheme_dict is None: | ||
paths = self.paths.copy() | ||
|
||
if not self.is_venv() and paths.get("userbase"): | ||
overrides: dict[str, str] = {} | ||
base_path = os.path.commonpath([paths["include"], paths["purelib"]]) | ||
|
||
for key in [ | ||
"include", | ||
"purelib", | ||
"platlib", | ||
"stdlib", | ||
"platinclude", | ||
"scripts", | ||
"data", | ||
]: | ||
if not is_dir_writable(path=Path(paths[key]), create=True): | ||
overrides[key] = paths[key].replace( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it ok to end up potentially with a mix of system and user directories here? This is not something I have looked into but I would have guessed you'd want all or nothing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pretty sure there is a feature request somewhere asking for would it get messy if eg you provide There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suspect that would confuse things more from the user perspective. Especially because we are predominantly servicing virtual environments. Such a flag would in theory only be used when the user knows they are running in a system environment and does not have write access to the system environment. Hence, I'm not sure how valuable it might be as a cli option. Maybe a config option, I do not know. If I understood the issues requesting There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In practice it shouldn't matter. And in reality it is highly unlikely that parts of it is writable and others not. Python will look everywhere by default. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can replicate that I guess. |
||
base_path, paths["userbase"] | ||
) | ||
|
||
for k, v in overrides.items(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
paths[k] = v | ||
|
||
self._installer_scheme_dict = paths | ||
|
||
return self._installer_scheme_dict | ||
|
||
@property | ||
def supported_tags(self) -> list[Tag]: | ||
if self._supported_tags is None: | ||
|
@@ -312,7 +349,9 @@ def run_pip(self, *args: str, **kwargs: Any) -> str: | |
def run_python_script(self, content: str, **kwargs: Any) -> str: | ||
return self.run( | ||
self._executable, | ||
"-I", | ||
# if isolation is enabled for system env, user site would be | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suppose this reintroduces #6627, which was the reason for adding this flag There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch thanks. Let me see if there is a better way. |
||
# incorrectly disabled | ||
*(["-I"] if self.is_venv() else []), | ||
"-W", | ||
"ignore", | ||
"-c", | ||
|
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.
We may use
@cached_property
instead so we don't need_installer_scheme_dict
.