mirror of
https://github.com/daylinmorgan/viv.git
synced 2024-12-22 02:30:44 -06:00
docs: add more docstrings
This commit is contained in:
parent
8f8d638356
commit
c09d931abf
1 changed files with 46 additions and 14 deletions
|
@ -32,6 +32,8 @@ __version__ = "22.12a2"
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Config:
|
class Config:
|
||||||
|
"""viv config manager"""
|
||||||
|
|
||||||
venvcache: Path = (
|
venvcache: Path = (
|
||||||
Path(os.getenv("XDG_CACHE_HOME", Path.home() / ".local" / "cache"))
|
Path(os.getenv("XDG_CACHE_HOME", Path.home() / ".local" / "cache"))
|
||||||
/ "viv"
|
/ "viv"
|
||||||
|
@ -112,6 +114,8 @@ BOX: Dict[str, str] = {
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Ansi:
|
class Ansi:
|
||||||
|
"""control ouptut of ansi(VT100) control codes"""
|
||||||
|
|
||||||
bold: str = "\033[1m"
|
bold: str = "\033[1m"
|
||||||
dim: str = "\033[2m"
|
dim: str = "\033[2m"
|
||||||
underline: str = "\033[4m"
|
underline: str = "\033[4m"
|
||||||
|
@ -139,6 +143,7 @@ class Ansi:
|
||||||
|
|
||||||
def tagline(self):
|
def tagline(self):
|
||||||
"""generate the viv tagline!"""
|
"""generate the viv tagline!"""
|
||||||
|
|
||||||
return " ".join(
|
return " ".join(
|
||||||
(
|
(
|
||||||
self.style(f, "magenta") + self.style(rest, "cyan")
|
self.style(f, "magenta") + self.style(rest, "cyan")
|
||||||
|
@ -147,6 +152,12 @@ class Ansi:
|
||||||
)
|
)
|
||||||
|
|
||||||
def subprocess(self, output):
|
def subprocess(self, output):
|
||||||
|
"""generate output for subprocess error
|
||||||
|
|
||||||
|
Args:
|
||||||
|
output: text output from subprocess, usually from p.stdout
|
||||||
|
"""
|
||||||
|
|
||||||
new_output = [f"{self.red}->{self.end} {line}" for line in output.splitlines()]
|
new_output = [f"{self.red}->{self.end} {line}" for line in output.splitlines()]
|
||||||
|
|
||||||
sys.stdout.write("\n".join(new_output) + "\n")
|
sys.stdout.write("\n".join(new_output) + "\n")
|
||||||
|
@ -162,6 +173,12 @@ class Ansi:
|
||||||
return f" {BOX['v']} " + f" {BOX['sep']} ".join(row) + f" {BOX['v']}"
|
return f" {BOX['v']} " + f" {BOX['sep']} ".join(row) + f" {BOX['v']}"
|
||||||
|
|
||||||
def table(self, rows, header_style="cyan") -> None:
|
def table(self, rows, header_style="cyan") -> None:
|
||||||
|
"""generate a table with outline and styled header
|
||||||
|
|
||||||
|
Args:
|
||||||
|
rows: sequence of the rows, first item assumed to be header
|
||||||
|
header_style: color/style for header row
|
||||||
|
"""
|
||||||
# TODO: make this function screen size aware...either with wrapping or cropping
|
# TODO: make this function screen size aware...either with wrapping or cropping
|
||||||
|
|
||||||
sizes = [0] * len(rows[0])
|
sizes = [0] * len(rows[0])
|
||||||
|
@ -191,16 +208,19 @@ a = Ansi()
|
||||||
|
|
||||||
|
|
||||||
def error(msg, code: int = 0):
|
def error(msg, code: int = 0):
|
||||||
|
"""output error message and if code provided exit"""
|
||||||
echo(f"{a.red}error:{a.end} {msg}", hue="red")
|
echo(f"{a.red}error:{a.end} {msg}", hue="red")
|
||||||
if code:
|
if code:
|
||||||
sys.exit(code)
|
sys.exit(code)
|
||||||
|
|
||||||
|
|
||||||
def warn(msg):
|
def warn(msg):
|
||||||
|
"""output warning message to stdout"""
|
||||||
echo(f"{a.yellow}warn:{a.end} {msg}", hue="yellow")
|
echo(f"{a.yellow}warn:{a.end} {msg}", hue="yellow")
|
||||||
|
|
||||||
|
|
||||||
def echo(msg: str, hue="magenta", newline=True) -> None:
|
def echo(msg: str, hue="magenta", newline=True) -> None:
|
||||||
|
"""output general message to stdout"""
|
||||||
output = f"{a.cyan}Viv{a.end}{a.__dict__[hue]}::{a.end} {msg}"
|
output = f"{a.cyan}Viv{a.end}{a.__dict__[hue]}::{a.end} {msg}"
|
||||||
if newline:
|
if newline:
|
||||||
output += "\n"
|
output += "\n"
|
||||||
|
@ -255,9 +275,17 @@ def run(
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def get_hash(package_spec: Tuple[str, ...] | List[str], track_exe: bool) -> str:
|
def get_hash(spec: Tuple[str, ...] | List[str], track_exe: bool) -> str:
|
||||||
|
"""generate a hash of package specifications
|
||||||
|
|
||||||
|
Args:
|
||||||
|
spec: sequence of package specifications
|
||||||
|
track_exe: if true add python executable to hash
|
||||||
|
Returns:
|
||||||
|
sha256 representation of dependencies for vivenv
|
||||||
|
"""
|
||||||
pkg_hash = hashlib.sha256()
|
pkg_hash = hashlib.sha256()
|
||||||
pkg_hash.update(str(package_spec).encode())
|
pkg_hash.update(str(spec).encode())
|
||||||
|
|
||||||
# generate unique venvs for unique python exe's
|
# generate unique venvs for unique python exe's
|
||||||
if track_exe:
|
if track_exe:
|
||||||
|
@ -267,7 +295,6 @@ def get_hash(package_spec: Tuple[str, ...] | List[str], track_exe: bool) -> str:
|
||||||
|
|
||||||
|
|
||||||
class ViVenv:
|
class ViVenv:
|
||||||
# TODO: make method to generate venv from the info file?
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
spec: List[str],
|
spec: List[str],
|
||||||
|
@ -283,7 +310,11 @@ class ViVenv:
|
||||||
self.path = path if path else c.venvcache / self.name
|
self.path = path if path else c.venvcache / self.name
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, name) -> "ViVenv":
|
def load(cls, name: str) -> "ViVenv":
|
||||||
|
"""generate a vivenv from a viv-info.json file
|
||||||
|
Args:
|
||||||
|
name: used as lookup in the vivenv cache
|
||||||
|
"""
|
||||||
if not (c.venvcache / name / "viv-info.json").is_file():
|
if not (c.venvcache / name / "viv-info.json").is_file():
|
||||||
warn(f"possibly corrupted vivenv: {name}")
|
warn(f"possibly corrupted vivenv: {name}")
|
||||||
return cls(name=name, spec=[""])
|
return cls(name=name, spec=[""])
|
||||||
|
@ -351,8 +382,8 @@ def activate(*packages: str, track_exe: bool = False, name: str = "") -> None:
|
||||||
track_exe: if true make env python exe specific
|
track_exe: if true make env python exe specific
|
||||||
name: use as vivenv name, if not provided build_id is used
|
name: use as vivenv name, if not provided build_id is used
|
||||||
"""
|
"""
|
||||||
|
validate_spec(packages)
|
||||||
vivenv = ViVenv(validate_spec(packages), track_exe=track_exe, name=name)
|
vivenv = ViVenv(list(packages), track_exe=track_exe, name=name)
|
||||||
|
|
||||||
if vivenv.name not in [d.name for d in c.venvcache.iterdir()] or os.getenv(
|
if vivenv.name not in [d.name for d in c.venvcache.iterdir()] or os.getenv(
|
||||||
"VIV_FORCE"
|
"VIV_FORCE"
|
||||||
|
@ -364,17 +395,17 @@ def activate(*packages: str, track_exe: bool = False, name: str = "") -> None:
|
||||||
modify_sys_path(vivenv.path)
|
modify_sys_path(vivenv.path)
|
||||||
|
|
||||||
|
|
||||||
def validate_spec(spec) -> List[str]:
|
def validate_spec(spec):
|
||||||
to_install: List[str] = []
|
"""ensure spec is at least of sequence of strings
|
||||||
|
|
||||||
if set(map(type, spec)) == {str}:
|
Args:
|
||||||
to_install.extend(pkg for pkg in spec)
|
spec: sequence of package specifications
|
||||||
else:
|
"""
|
||||||
|
# ? make this a part of ViVenv?
|
||||||
|
if not set(map(type, spec)) == {str}:
|
||||||
error("unexepected input in package spec")
|
error("unexepected input in package spec")
|
||||||
error(f"check your packages definitions: {spec}", code=1)
|
error(f"check your packages definitions: {spec}", code=1)
|
||||||
|
|
||||||
return to_install
|
|
||||||
|
|
||||||
|
|
||||||
def modify_sys_path(new_path: Path):
|
def modify_sys_path(new_path: Path):
|
||||||
|
|
||||||
|
@ -421,7 +452,8 @@ def generate_import(
|
||||||
vivenv = ViVenv(reqs + reqs_from_file, track_exe=False, path=Path(tmpdir))
|
vivenv = ViVenv(reqs + reqs_from_file, track_exe=False, path=Path(tmpdir))
|
||||||
|
|
||||||
vivenv.create()
|
vivenv.create()
|
||||||
# populate the environment for now use custom cmd since using requirements file
|
# populate the environment for now use
|
||||||
|
# custom cmd since using requirements file
|
||||||
cmd = [
|
cmd = [
|
||||||
vivenv.path / "bin" / "pip",
|
vivenv.path / "bin" / "pip",
|
||||||
"install",
|
"install",
|
||||||
|
|
Loading…
Reference in a new issue