Skip to content

Commit

Permalink
venv
Browse files Browse the repository at this point in the history
  • Loading branch information
cidrblock committed Aug 22, 2023
1 parent 297d273 commit 98d9804
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 74 deletions.
42 changes: 27 additions & 15 deletions src/pip4a/arg_parser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Parse the command line arguments."""
import argparse

from ._version import __version__


def parse() -> argparse.Namespace:
"""Parse the command line arguments.
Expand All @@ -13,9 +15,10 @@ def parse() -> argparse.Namespace:
formatter_class=argparse.RawTextHelpFormatter,
)
parser.add_argument(
"--verbose",
action="store_true",
help="Increase output verbosity.",
"--version",
action="version",
help="Version specifier.",
version=__version__,
)

subparsers = parser.add_subparsers(
Expand All @@ -25,6 +28,24 @@ def parse() -> argparse.Namespace:
dest="subcommand",
)

parent_parser = argparse.ArgumentParser(add_help=False)

parent_parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="Increase output verbosity.",
)
parent_parser.add_argument(
"collection_specifier",
help="Collection name or path to collection with extras.",
)
parent_parser.add_argument(
"--venv",
help="Target virtual environment.",
)


install_usage = """Usage:
pip4a install .
pip4a install -e .
Expand All @@ -35,28 +56,19 @@ def parse() -> argparse.Namespace:
"install",
epilog=install_usage,
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[parent_parser],
)

install.add_argument(
"-e",
"--editable",
action="store_true",
help="Install editable.",
)
install.add_argument(
"collection_specifier",
help="Collection to install.",
)

uninstall = subparsers.add_parser(
_uninstall = subparsers.add_parser(
"uninstall",
epilog=install_usage,
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[parent_parser],
)

uninstall.add_argument(
"collection_specifier",
help="Collection to uninstall.",
)

return parser.parse_args()
122 changes: 122 additions & 0 deletions src/pip4a/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
"""A base class for pip4a."""

from __future__ import annotations

import json
import logging
import os
import subprocess
import sys

from pathlib import Path
from typing import TYPE_CHECKING


if TYPE_CHECKING:
from .app import App

logger = logging.getLogger(__name__)

class Base:
"""A base class for pip4a."""

def __init__(self: Base, app: App) -> None:
"""Initialize the installer.
Arguments:
app: The app instance
"""
self.app: App = app
self.bindir: Path
self.interpreter: Path
self.site_pkg_path: Path

def _set_interpreter(self: Base, create: bool=False) -> None: # noqa: FBT001,FBT002
"""Set the interpreter."""
venv = None
if self.app.args.venv:
venv = Path(self.app.args.venv).resolve()
else:
venv_str = os.environ.get("VIRTUAL_ENV")
if venv_str:
venv = Path(venv_str).resolve()
if venv:
if not venv.exists():
if create:
if not venv.relative_to(Path.cwd()):
err = "Virtual environment must relative to cwd to create it."
logger.critical(err)
msg = f"Creating virtual environment: {venv}"
logger.info(msg)
command = f"python -m venv {venv}"
msg = f"Running command: {command}"
logger.debug(msg)
try:
subprocess.run(
command,
check=True,
shell=True, # noqa: S602
capture_output=self.app.args.verbose,
)
except subprocess.CalledProcessError as exc:
err = f"Failed to create virtual environment: {exc}"
logger.critical(err)
else:
err = f"Cannot find virtual environment: {venv}."
logger.critical(err)
msg = f"Virtual environment: {venv}"
logger.info(msg)
interpreter = venv / "bin" / "python"
if not interpreter.exists():
err = f"Cannot find interpreter: {interpreter}."
logger.critical(err)

msg = f"Using specified interpreter: {interpreter}"
logger.info(msg)
self.interpreter = interpreter
else:
self.interpreter = Path(sys.executable)
msg = f"Using current interpreter: {self.interpreter}"
logger.info(msg)

def _set_bindir(self: Base) -> None:
"""Set the bindir."""
self.bindir = self.interpreter.parent
if not self.bindir.exists():
err = f"Cannot find bindir: {self.bindir}."
logger.critical(err)

def _set_site_pkg_path(self: Base) -> None:
"""USe the interpreter to find the site packages path."""
command = (
f"{self.interpreter} -c"
" 'import json,site; print(json.dumps(site.getsitepackages()))'"
)
msg = f"Running command: {command}"
logger.debug(msg)
try:
proc = subprocess.run(
command,
check=True,
capture_output=True,
shell=True, # noqa: S602
text=True,
)
except subprocess.CalledProcessError as exc:
err = f"Failed to find site packages path: {exc}"
logger.critical(err)

try:
site_pkg_dirs = json.loads(proc.stdout)
except json.JSONDecodeError as exc:
err = f"Failed to decode json: {exc}"
logger.critical(err)

if not site_pkg_dirs:
err = "Failed to find site packages path."
logger.critical(err)

msg = f"Found site packages path: {site_pkg_dirs[0]}"
logger.debug(msg)

self.site_pkg_path = Path(site_pkg_dirs[0])
Loading

0 comments on commit 98d9804

Please sign in to comment.