-
Notifications
You must be signed in to change notification settings - Fork 18
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
Try to make virtualenv metadata findable when invoked globally #207
Closed
Closed
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
49836a3
Guess project virtualenv when invoked globally
7caba00
Extract in dedicated module and remove platform dependency
cc9f2e9
Call virtualenv_finder entrypoint in cli
bf5cc4a
Wrapp runtime information in ExecutionContext dataclass
9465462
Use f-strings for log messages
5245d29
Refactor and rename maybe_install_finder
3c7a727
Add 'venv' folder as virtualenv candidate
kwentine 89e6e4f
Accept --python-site-packages option
1205005
Wording of site-packages option help text
kwentine 419e62a
Path instance is truthy if not null
kwentine 933cd37
Reword warning message
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import logging | ||
import os | ||
import sys | ||
from dataclasses import dataclass | ||
from pathlib import Path | ||
|
||
from deptry.compat import metadata | ||
|
||
|
||
@dataclass | ||
class ExecutionContext: | ||
project_root: Path | ||
base_prefix: str | ||
prefix: str | ||
active_virtual_env: str = None | ||
|
||
@classmethod | ||
def from_runtime(cls, project_root: Path): | ||
return cls( | ||
project_root=project_root, | ||
base_prefix=sys.base_prefix, | ||
prefix=sys.prefix, | ||
active_virtual_env=os.environ.get("VIRTUAL_ENV"), | ||
) | ||
|
||
@property | ||
def project_name(self): | ||
return self.project_root.absolute().name | ||
|
||
def running_in_project_virtualenv(self) -> bool: | ||
"""Determine if executed by the interpreter in the project's virtual environment | ||
|
||
If we are executed from virtual environment, the context `prefix` | ||
will be set to the virtual environment's directory, whereas | ||
`base_prefix` will point to the global Python installation | ||
used to create the virtual environment. | ||
|
||
The `active_virtual_env` context field holds the value of the | ||
VIRTUAL_ENV environment variable, that tells with good reliability | ||
that a virtual environment has been activated in the current shell. | ||
""" | ||
|
||
# Gobal installation | ||
if self.prefix == self.base_prefix: | ||
return False | ||
|
||
# No virtualenv has been activated. Unless the project name is in | ||
# the interpreter path, assume we are not in the project's virtualenv | ||
if not self.active_virtual_env: | ||
return self.project_name in self.prefix | ||
|
||
# A virtualenv has been activated. But if `deptry` was installed gloabally using | ||
# `pipx`, we could be running in another installation. | ||
return self.active_virtual_env == self.prefix | ||
|
||
|
||
def install_metadata_finder(site_packages: Path) -> None: | ||
"""Add poject virtualenv site packages to metadata search path""" | ||
path = [str(site_packages.absolute()), *sys.path] | ||
|
||
class VirtualenvDistributionFinder(metadata.MetadataPathFinder): | ||
@classmethod | ||
def find_distributions(cls, context): | ||
context = metadata.DistributionFinder.Context(name=context.name, path=path) | ||
return super().find_distributions(context) | ||
|
||
sys.meta_path.insert(0, VirtualenvDistributionFinder()) | ||
|
||
|
||
def warn_if_not_running_in_virtualenv(root: Path) -> None: | ||
ctx = ExecutionContext.from_runtime(root) | ||
if not ctx.running_in_project_virtualenv(): | ||
log_msg = ( | ||
f"If deptry is not installed within the `{ctx.project_name}` project's virtual environment, it does not " | ||
"have access to the metadata of dependencies installed within the virtual environment. This can be " | ||
"solved by installing deptry in the virtual environment, or by passing the path to your virtual " | ||
"environment's site-packages directory as the `--python-site-packages` argument." | ||
) | ||
logging.warn(log_msg) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from pathlib import Path | ||
|
||
import pytest | ||
|
||
from deptry.metadata_finder import ExecutionContext | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"params, expected", | ||
[ | ||
# Global installation | ||
((Path("theproject"), "/usr", "/usr", None), False), | ||
# Direct invocation with project interpreter | ||
((Path("theproject"), "/usr", "/home/user/.virtualenvs/theproject", None), True), | ||
# Pipx global install. Project virtualenv active | ||
((Path("theproject"), "/usr", "/home/user/.local/pipx/venvs/deptry", "/home/user/theproject/.venv"), False), | ||
# Project virtualenv active and running | ||
((Path("theproject"), "/usr", "/home/user/theproject/.venv", "/home/user/theproject/.venv"), True), | ||
], | ||
) | ||
def test_running_in_project_virtualenv(params, expected): | ||
arg_names = ("project_root", "base_prefix", "prefix", "active_virtual_env") | ||
kwargs = dict(zip(arg_names, params)) | ||
ctx = ExecutionContext(**kwargs) | ||
assert ctx.running_in_project_virtualenv() == expected |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
typo in project