# 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 `--`: ```sh viv run frogmouth -- gh daylinmorgan/viv ``` Run a python module use the `-b/--bin` flag and specify `python`: ```sh viv run rich -b python -- -m rich ``` Make an ephemeral `jupyter` environment with your needed deps: ```sh viv run jupyter pandas -r requirements-dev.txt -- notebook ``` Generate an executable shell script that will on demand create a vivenv as needed: ```sh viv shim ruff ``` Output: ```python #!/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: ```sh viv run rich typer -b python -- ./cli.py --help ``` Using `-s/--script`: ```sh 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: ```python #!/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 ::: :::{seealso} Check out [PEP723](https://peps.python.org/pep-0723/) 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. ```python __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. ```python __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: ```sh viv freeze rich typer ``` Output: ```python __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: ```sh viv freeze rich typer --path rel ``` Output: ```python __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`: ```sh viv env remove d4b342b3 ``` To get more information about vivenvs you can use `viv list --verbose` or `viv env info ` :::{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: ```sh viv list --filter "created-before:2024-01-01" ``` Associated with a particular file: ```sh viv list --filter "files:./script.py" ``` Or no files: ```sh 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: ```sh viv env remove $(viv list -q) ``` To remove `viv` all together you can use the included `purge` command: ```sh 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](https://github.com/daylinmorgan/viv/blob/dev/examples/black) for output of below command. `viv freeze` also supports `--standalone` ```sh python3 <(curl -fsSL viv.dayl.in/viv.py) shim black -o ./black --standalone --freeze ```