# Viv
Logo

viv isn't venv


See [usage](https://github.com/daylinmorgan/viv/blob/main/docs/usage.md) for more demo gifs. ## Setup ### Manual (Recommended) Start by cloning the repo and symlinking the script for access to the CLI. By default it will symlink `./src/viv/viv.py` to `~/bin/viv`. You can set `PREFIX` to symlink to a different location. ```sh git clone git@github.com:daylinmorgan/viv.git ~/.viv cd ~/.viv make install # or PREFIX=~/.local/bin make install ``` Place this directory on the python path in your rc file. ```sh export PYTHONPATH="$PYTHONPATH:$HOME/.viv/src" ``` ### Pypi (Not Recommended) ```sh pip install viv ``` ## Usage Then in any python script with external dependencies you can add this line, to automate env creation and installation of dependencies. ```python __import__("viv").activate("click") ``` To remove all `vivenvs`: ```sh viv remove $(viv list -q) ``` ## Standalone Function The below function can be freely pasted at the top of your scripts and requires no modification of your PYTHONPATH or import of additional modules. It can be auto-generated with for example: `viv freeze rich --standalone`. The only part necessary to modify if copied verbatim from here is the call to `_viv_activate`. ```python # <<<<< auto-generated by daylinmorgan/viv (v.22.12a3) # fmt: off def _viv_activate(*pkgs: str, track_exe: bool = False, name: str = "") -> None: # noqa i,m,e = __import__,map,lambda x: True if x else False # noqa if not {*m(type, pkgs)} == {str}: raise ValueError(f"spec: {pkgs} is invalid") # noqa ge,sys,P,exe = i("os").getenv,i("sys"),i("pathlib").Path,i("sys").executable # noqa vivcache = (P(ge("XDG_CACHE_HOME",P.home()/".cache"))/"viv"/"venvs");vivcache.mkdir(parents=True, exist_ok=True) # noqa spec,exe_path = [*pkgs], (str(P(exe).resolve()) if track_exe else "N/A") # noqa hash = i("hashlib").sha256(); hash.update(str(spec).encode()) # noqa if track_exe: hash.update(exe_path.encode()) # noqa _id = hash.hexdigest() # noqa name, envpath = (lambda n: (n,vivcache/n))(name if name else _id) # noqa if name not in (d.name for d in vivcache.iterdir()) or ge("VIV_FORCE"): # noqa run = i("subprocess").run; i("venv").EnvBuilder(with_pip=True, clear=True).create(envpath) # noqa with (envpath/"pip.conf").open("w") as f:f.write("[global]\ndisable-pip-version-check = true") # noqa p = run([envpath/"bin"/"pip","install","--force-reinstall", *spec], universal_newlines=True, # noqa **dict(zip(("stdout","stderr"),[(-1,-2),(None,)*2,][e(ge("VIV_VERBOSE"))]))) # noqa if (p.returncode!=0)*envpath.is_dir():i("shutil").rmtree(str(envpath)) # noqa if p.returncode!=0:sys.stderr.write(f"pip had non zero exit ({p.returncode})\n{p.stdout}");sys.exit(p.returncode) # noqa with (envpath/"viv-info.json").open("w") as f: # noqa i("json").dump({"created":str(i("datetime").datetime.today()),"id":_id,"spec":spec,"exe":exe},f) # noqa sys.path = [p for p in (*sys.path, str(*(envpath/"lib").glob("py*/si*"))) if p!=i("site").USER_SITE] # noqa _viv_activate("markdown-it-py==2.2.0", "mdurl==0.1.2", "Pygments==2.14.0", "rich==13.3.2") # fmt: on # >>>>> code golfed with <3 ``` ## Alternatives ### [pip-run](https://github.com/jaraco/pip-run) ```sh pip-run (10.0.5) ├── autocommand (2.2.2) ├── jaraco-context (4.3.0) ├── jaraco-functools (3.6.0) │ └── more-itertools (9.1.0) ├── jaraco-text (3.11.1) │ ├── autocommand (2.2.2) │ ├── inflect (6.0.2) │ │ └── pydantic>=1.9.1 (1.10.5) │ │ └── typing-extensions>=4.2.0 (4.5.0) │ ├── jaraco-context>=4.1 (4.3.0) │ ├── jaraco-functools (3.6.0) │ │ └── more-itertools (9.1.0) │ └── more-itertools (9.1.0) ├── more-itertools>=8.3 (9.1.0) ├── packaging (23.0) ├── path>=15.1 (16.6.0) ├── pip>=19.3 (23.0.1) └── platformdirs (3.1.0) ``` ### [pipx](https://github.com/pypa/pipx/) ```sh pipx (1.1.0) ├── argcomplete>=1.9.4 (2.1.1) ├── packaging>=20.0 (23.0) └── userpath>=1.6.0 (1.8.0) └── click (8.1.3) ```