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

pip, _cli: Add --path argument to mirror pip list #148

Merged
merged 10 commits into from
Dec 3, 2021
14 changes: 13 additions & 1 deletion pip_audit/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,15 @@ def audit() -> None:
parser.add_argument(
"--timeout", type=int, default=15, help="set the socket timeout" # Match the `pip` default
)
parser.add_argument(
"--path",
type=Path,
action="append",
dest="paths",
default=[],
help="restrict to the specified installation path for auditing packages; "
"this option can be used multiple times",
)

args = parser.parse_args()
logger.debug(f"parsed arguments: {args}")
Expand All @@ -227,10 +236,13 @@ def audit() -> None:

source: DependencySource
if args.requirements is not None:
if args.paths:
print("--requirement (-r) and --path arguments cannot be used together")
sys.exit(1)
woodruffw marked this conversation as resolved.
Show resolved Hide resolved
req_files: List[Path] = [Path(req.name) for req in args.requirements]
source = RequirementSource(req_files, ResolveLibResolver(args.timeout, state), state)
else:
source = PipSource(local=args.local)
source = PipSource(local=args.local, paths=args.paths)

auditor = Auditor(service, options=AuditOptions(dry_run=args.dry_run))

Expand Down
12 changes: 9 additions & 3 deletions pip_audit/_dependency_source/pip.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"""

import logging
from typing import Iterator, Optional
from pathlib import Path
from typing import Iterator, List, Optional

import pip_api
from packaging.version import InvalidVersion, Version
Expand Down Expand Up @@ -32,7 +33,9 @@ class PipSource(DependencySource):
Wraps `pip` (specifically `pip list`) as a dependency source.
"""

def __init__(self, *, local: bool = False, state: Optional[AuditState] = None) -> None:
def __init__(
self, *, local: bool = False, paths: List[Path], state: Optional[AuditState] = None
) -> None:
"""
Create a new `PipSource`.

Expand All @@ -42,6 +45,7 @@ def __init__(self, *, local: bool = False, state: Optional[AuditState] = None) -
`state` is an optional `AuditState` to use for state callbacks.
"""
self._local = local
self._paths = paths
self.state = state

if _PIP_VERSION < _MINIMUM_RELIABLE_PIP_VERSION:
Expand All @@ -61,7 +65,9 @@ def collect(self) -> Iterator[Dependency]:
# The `pip list` call that underlies `pip_api` could fail for myriad reasons.
# We collect them all into a single well-defined error.
try:
for (_, dist) in pip_api.installed_distributions(local=self._local).items():
for (_, dist) in pip_api.installed_distributions(
local=self._local, paths=self._paths
).items():
dep: Dependency
try:
dep = ResolvedDependency(name=dist.name, version=Version(str(dist.version)))
Expand Down