mirror of
https://github.com/daylinmorgan/viv.git
synced 2024-12-22 02:30:44 -06:00
viv isn't venv
docs | ||
examples | ||
src/viv | ||
.gitignore | ||
.pre-commit-config.yaml | ||
.task.cfg.mk | ||
LICENSE | ||
Makefile | ||
pdm.lock | ||
pyproject.toml | ||
README.md | ||
todo.md |
Viv
See usage 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.
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.
export PYTHONPATH="$PYTHONPATH:$HOME/.viv/src"
Pypi (Not Recommended)
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.
__import__("viv").activate("click")
To remove all vivenvs
:
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
.
# <<<<< 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") # noqa
# fmt: on
# >>>>> code golfed with <3
Alternatives
pip-run
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
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)