Usage¶
Viv works by ensuring scripts or a given command are run in an appropriate environment with all specified dependencies.
Tip
viv
is a single script and available at viv.dayl.in/viv.py
meaning every instance of viv
in these examples could be python3 <(curl -fsSL viv.dayl.in/viv.py)
Run CLI Apps¶
Run a python app that provides an entrypoint and separate args with --
:
viv run frogmouth -- gh daylinmorgan/viv
Run a python module use the -b/--bin
flag and specify python
:
viv run rich -b python -- -m rich
Make an ephemeral jupyter
environment with your needed deps:
viv run jupyter pandas -r requirements-dev.txt -- notebook
Generate an executable shell script that will on demand create a vivenv as needed:
viv shim ruff
Output:
#!/usr/bin/env python3
# AUTOGENERATED by viv (v2023.1003)
# see `python3 <(curl -fsSL viv.dayl.in/viv.py) --help`
import subprocess
import sys
if __name__ == "__main__":
vivenv = __import__("viv").use("ruff") # noqa
sys.exit(subprocess.run([vivenv / "bin" / "ruff", *sys.argv[1:]]).returncode)
Run Python Scripts¶
It’s possible to use the viv
CLI to run a python script.
There are several options for invoking a script.
Using the interpreter:
viv run rich typer -b python -- ./cli.py --help
Using -s/--script
:
viv run rich typer -s ./cli.py -- --help
# or with a remote script
viv run rich -s https://raw.githubusercontent.com/Textualize/rich/master/examples/fullscreen.py
If viv
is available on your path it’s possible to
invoke it with embedded metadata thanks to shebangs:
#!/usr/bin/env -S viv run --keep --script
# /// script
# requires-python = ">3.10"
# dependencies = [
# "matplotlib",
# "pandas"
# ]
# ///
Note
If using a shebang on a python script -s/--script
must be the last argument
See also
Check out PEP723 for more info about inline script metadata.
In any python script with external dependencies you can also add this line prior to imports
to automate vivenv
creation and installation of dependencies.
__import__("viv").use("click")
If your dependencies are sensitive to the version of python
(numpy, cpython-based apps, etc. ) then you can specify track_exe
.
Which will lead to viv
creating a unique vivenv based on the detected python executable.
__import__("viv").use("numpy", track_exe=True)
If you’d like to pin your dependencies to a resolved environment you
can use the convenience command viv freeze
to output a list of pinned packages.
Command:
viv freeze rich typer
Output:
__import__("viv").use("rich==13.7.0", "typer==0.9.0", "click==8.1.7", "markdown-it-py==3.0.0", "Pygments==2.17.2", "typing_extensions==4.9.0", "mdurl==0.1.2") # noqa
Additionally, you can make this work regardless of PYTHONPATH
by using --path
.
Command:
viv freeze rich typer --path rel
Output:
__import__("sys").path.append(__import__("os").path.expanduser("~/.local/share/viv/")) # noqa
__import__("viv").use("rich==13.7.0", "typer==0.9.0", "click==8.1.7", "markdown-it-py==3.0.0", "Pygments==2.17.2", "typing_extensions==4.9.0", "mdurl==0.1.2") # noqa
Manage Viv¶
Interacting with the viv cache¶
Depending on how you invoke viv
, it will persist it’s virtual environments (vivenvs).
To see all currently existing vivenvs use can use viv list
.
Viv will attempt to track any usages of the vivenvs including the scripts that invoke them.
You can remove any existing vivenvs using viv env remove
:
viv env remove d4b342b3
To get more information about vivenvs you can use viv list --verbose
or viv env info <hash>
Note
For commands that expect a vivenv hash/name you can use as few characters as you
as you like and viv
will match it against the existing vivenvs in the cache.
You can list vivenvs given a criteria using --filter
for example:
Created before 2024-01-01:
viv list --filter "created-before:2024-01-01"
Associated with a particular file:
viv list --filter "files:./script.py"
Or no files:
viv list --filter "files:None"
Note
--filter "files:None"
will also apply to vivenvs
in which the original file is no longer on the disk
The available filtering criteria are accessed-after
,
accessed-before
, created-before
, created-after
, spec
and files
.
To remove all vivenvs
you can use the below command:
viv env remove $(viv list -q)
To remove viv
all together you can use the included purge
command:
python3 <(curl -fsSL viv.dayl.in/viv.py) manage purge
Bonus: viv
standalone¶
--standalone
will auto-generate a mini function version of viv
to accomplish the same basic task as using a local copy of viv
.
After generating this standalone shim
you can freely use this script across unix machines which have python>3.8
.
See examples/black for output of below command.
viv freeze
also supports --standalone
python3 <(curl -fsSL viv.dayl.in/viv.py) shim black -o ./black --standalone --freeze