-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Basic abstraction one actual migration
- Loading branch information
Showing
6 changed files
with
207 additions
and
82 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from pip._internal.utils.compat import lru_cache | ||
from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
|
||
if MYPY_CHECK_RUNNING: | ||
from typing import List, Optional | ||
|
||
from .base import BaseEnvironment | ||
|
||
|
||
@lru_cache(maxsize=None) | ||
def get_environment(paths=None): | ||
# type: (Optional[List[str]]) -> BaseEnvironment | ||
from .pkg_resources import Environment | ||
if paths is None: | ||
return Environment.default() | ||
return Environment.from_paths(paths) |
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,80 @@ | ||
import abc | ||
|
||
from pip._vendor.six import add_metaclass | ||
|
||
from pip._internal.utils.misc import stdlib_pkgs # TODO: Move definition here. | ||
from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
|
||
if MYPY_CHECK_RUNNING: | ||
from typing import Container, Iterator, List, Optional | ||
|
||
|
||
@add_metaclass(abc.ABCMeta) | ||
class BaseDistribution(object): | ||
@property | ||
def canonical_name(self): | ||
# type: () -> str | ||
raise NotImplementedError() | ||
|
||
@property | ||
def installer(self): | ||
# type: () -> str | ||
raise NotImplementedError() | ||
|
||
@property | ||
def editable(self): | ||
# type: () -> bool | ||
raise NotImplementedError() | ||
|
||
@property | ||
def local(self): | ||
# type: () -> bool | ||
raise NotImplementedError() | ||
|
||
@property | ||
def in_usersite(self): | ||
# type: () -> bool | ||
raise NotImplementedError() | ||
|
||
|
||
@add_metaclass(abc.ABCMeta) | ||
class BaseEnvironment(object): | ||
"""An environment containing distributions to introspect. | ||
""" | ||
@classmethod | ||
def default(cls): | ||
# type: () -> BaseEnvironment | ||
raise NotImplementedError() | ||
|
||
@classmethod | ||
def from_paths(cls, paths): | ||
# type: (List[str]) -> BaseEnvironment | ||
raise NotImplementedError() | ||
|
||
def iter_distributions(self): | ||
# type: () -> Iterator[BaseDistribution] | ||
raise NotImplementedError() | ||
|
||
def iter_installed_distributions( | ||
self, | ||
local_only=True, # type: bool | ||
skip=stdlib_pkgs, # type: Container[str] | ||
include_editables=True, # type: bool | ||
editables_only=False, # type: bool | ||
user_only=False, # type: bool | ||
): | ||
# type: (...) -> Iterator[BaseDistribution] | ||
it = self.iter_distributions() | ||
if local_only: | ||
it = (d for d in it if d.local) | ||
if not include_editables: | ||
it = (d for d in it if not d.editable) | ||
if editables_only: | ||
it = (d for d in it if d.editable) | ||
if user_only: | ||
it = (d for d in it if d.in_usersite) | ||
return (d for d in it if d.canonical_name not in skip) | ||
|
||
def get_installed_distribution(self, name): | ||
# type: (str) -> Optional[BaseDistribution] | ||
raise NotImplementedError() |
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,94 @@ | ||
from pip._vendor import pkg_resources | ||
from pip._vendor.packaging.utils import canonicalize_name | ||
|
||
from pip._internal.utils.misc import ( | ||
dist_in_usersite, | ||
dist_is_editable, | ||
dist_is_local, | ||
) | ||
from pip._internal.utils.packaging import get_installer | ||
from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
|
||
from .base import BaseDistribution, BaseEnvironment | ||
|
||
if MYPY_CHECK_RUNNING: | ||
from typing import Iterator, List, Optional | ||
|
||
|
||
class Distribution(BaseDistribution): | ||
def __init__(self, dist): | ||
# type: (pkg_resources.Distribution) -> None | ||
self._dist = dist | ||
|
||
@property | ||
def canonical_name(self): | ||
# type: () -> str | ||
return canonicalize_name(self._dist.project_name) | ||
|
||
@property | ||
def installer(self): | ||
# type: () -> str | ||
return get_installer(self._dist) | ||
|
||
@property | ||
def editable(self): | ||
# type: () -> bool | ||
return dist_is_editable(self._dist) | ||
|
||
@property | ||
def local(self): | ||
# type: () -> bool | ||
return dist_is_local(self._dist) | ||
|
||
@property | ||
def in_usersite(self): | ||
# type: () -> bool | ||
return dist_in_usersite(self._dist) | ||
|
||
|
||
class Environment(BaseEnvironment): | ||
def __init__(self, ws): | ||
# type: (pkg_resources.WorkingSet) -> None | ||
self._ws = ws | ||
|
||
@classmethod | ||
def default(cls): | ||
# type: () -> BaseEnvironment | ||
return cls(pkg_resources.working_set) | ||
|
||
@classmethod | ||
def from_paths(cls, paths): | ||
# type: (List[str]) -> BaseEnvironment | ||
return cls(pkg_resources.WorkingSet(paths)) | ||
|
||
def iter_distributions(self): | ||
# type: () -> Iterator[BaseDistribution] | ||
for dist in self._ws: | ||
yield Distribution(dist) | ||
|
||
def _get_installed_distribution_from_cache(self, name): | ||
# type: (str) -> Optional[BaseDistribution] | ||
name = canonicalize_name(name) | ||
for dist in self.iter_installed_distributions(): | ||
if dist.canonical_name == name: | ||
return dist | ||
return None | ||
|
||
def get_installed_distribution(self, name): | ||
# type: (str) -> Optional[BaseDistribution] | ||
dist = self._get_installed_distribution_from_cache(name) | ||
if dist: | ||
return dist | ||
# If distribution could not be found, call WorkingSet.require() | ||
# to update the working set, and try to find the distribution again. | ||
# This might happen for e.g. when you install a package twice, once | ||
# using setup.py develop and again using setup.py install. Now when | ||
# pip uninstall is run twice, the package gets removed from the | ||
# working set in the first uninstall, so we have to populate the | ||
# working set again so that pip knows about it and the packages gets | ||
# picked up and is successfully uninstalled the second time too. | ||
try: | ||
self._ws.require(name) | ||
except pkg_resources.DistributionNotFound: | ||
return None | ||
return self._get_installed_distribution_from_cache(name) |
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
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