docs: actually document the things

This commit is contained in:
Daylin Morgan 2024-01-03 15:58:44 -06:00
parent 5dacf8ab60
commit be3c7f83c9
Signed by: daylin
GPG Key ID: C1E52E7DD81DF79F
8 changed files with 338 additions and 163 deletions

View File

@ -3,6 +3,7 @@ copyright = "2023, Daylin Morgan"
author = "Daylin Morgan"
extensions = ["myst_parser", "sphinx_copybutton"]
myst_enable_extensions = ["colon_fence", "deflist"]
templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
@ -13,4 +14,10 @@ html_theme = "shibuya"
# html_static_path = ["_static"]
html_logo = "../assets/logo.svg"
html_theme_options = {"github_url": "https://github.com/daylinmorgan/viv"}
html_theme_options = {
"github_url": "https://github.com/daylinmorgan/viv",
"nav_links": [
{"title": "Documentation", "url": "installation"},
{"title": "CLI Reference", "url": "cli"},
],
}

45
docs/configuration.md Normal file
View File

@ -0,0 +1,45 @@
# Configuration
## Environment Variables
`VIV_RUN_MODE`
: **ephemeral** (default):
: `viv run` will generate a temporary directory that is removed following execution
: **semi-ephemeral**
: `viv run` will set the `VIV_CACHE` the directory to `$TEMPDIR/viv-ephemeral-cache-$USER`
: persist
: `viv run` will always use the standard `VIV_CACHE` which maximizes reusable vivenvs
`VIV_CACHE`
: Path to use for vivenv cache by default `$XDG_CACHE_HOME/viv` or `$HOME/.cache/viv`
`VIV_LOG_PATH`
: Path to use log file by default `$XDG_DATA_HOME/viv/viv.log` or `$HOME/.local/share/viv/viv.log`
`VIV_BIN_DIR`
: Path to use for shims by default `$HOME/.local/bin`
`VIV_NO_SETUPTOOLS`
: Don't add setuptools to generated vivenvs.
: Many legacy packages expect setuptools to be available
and don't appropriate declare it as dependency.
To minimize frustration `setuptools` is added to every dependency
list.
`VIV_FORCE`
: Remove existence check and recreate vivenv
`VIV_SPEC`
: Space separated list of dependencies in addition to those in script
`VIV_VERBOSE`
: Show `pip` output in real time
`VIV_DEBUG`
: Set log level to `DEBUG`
`FORCE_COLOR`
: Force output to use ANSI escape codes
`NO_COLOR`
: Remove all ANSI escape codes from output

View File

@ -1,5 +1,7 @@
---
hide-toc: true
layout: landing
cover: http://viv.dayl.in/_static/logo.svg
desciption: Viv isn't venv
---
# viv isn't venv
@ -8,24 +10,32 @@ Try before you buy!
```sh
python3 <(curl -fsSL viv.dayl.in/viv.py) run pycowsay -- "viv isn't venv\!"
```
---
`Viv` is a standalone dependency-free `venv` creator [^1].
:::{container} buttons
[Docs](/installation)
[Github](https://github.com/daylinmorgan/viv)
:::
`Viv` is a standalone dependency-free `venv` creator (just needs python + pip).
`Viv` helps you ignore silly things like managing temporary or rarely used virtual environments,
while still unleashing the full power of python scripting with it's entire ecosystem at your disposal.
`Viv`'s uncompromising insistence on portability means that it will always:
1. only use the standard library
2. never exceed a single script.
`Viv`'s uncompromising insistence on portability means that it will always,
only use the standard library and never exceed a single script.
Documentation is currently a WIP please see the [cli reference](./cli.md) and the [README](https://github.com/daylinmorgan/viv)
```{toctree}
:hidden:
:maxdepth: 2
installation.md
usage.md
configuration.md
vs-others.md
cli.md
```

56
docs/installation.md Normal file
View File

@ -0,0 +1,56 @@
# Installation
## Automated
Run the below command to install `viv`.
```sh
python3 <(curl -fsSL viv.dayl.in/viv.py) manage install
```
To access `viv` from within scripts you should add its location to your `PYTHONPATH`.
By default `viv` will be installed to `$XDG_DATA_HOME/viv` or `~/.local/share/viv`,
and symlinked to `$XDG_BIN_HOME` or `~/.local/bin/.`
You can customize these locations at install with with `--src` and `--cli` respectively.
```sh
export PYTHONPATH="$PYTHONPATH:$HOME/.local/share/viv"
# or
export PYTHONPATH="$PYTHONPATH:$(viv manage show --pythonpath)"
```
:::{note}
You can install an older version by specifying `--ref`
:::
## Manual
Viv is a single standalone script meaning all that's really necessary is
that it exists locally and is appropriately added to your path.
You can get the latest stable version from [here](https://viv.dayl.in/viv.py)
or from [github](https://github.com/daylinmorgan/viv/blob/latest/src/viv/viv.py).
Must be added to your `$PATH` for use as a CLI app and `$PYTHONPATH` for uses as a python module.
## Never
Viv is a standalone script accessible at `https://viv.dayl.in/viv.py`
meaning it's not strictly necessary you every actually install it.
Every instance of the `viv` CLI can be seamlessly replaced with `python3 <(curl -fsSL viv.dayl.in/viv.py)`.
## PyPI Options (Not Recommended)
Why is this *not recommended?*
Mainly because `viv` is all about hacking your `sys.path`.
Placing it in its own virtual environment
or installing in a user site directory may complicate this endeavor.
```sh
pip install viv
# or
pipx install viv
```
*Note*: If installed by `pipx`, it should still be possible to
use `viv` as a module by adding it to the `$PYTHONPATH`.
See above for more info.

View File

@ -1,12 +1,181 @@
# Usage
In any python script with external dependencies you can add this line,
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
```
To 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 <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:
```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`, and `files`.
To remove all `vivenvs` you can use the below command:
```sh
@ -18,35 +187,8 @@ To remove `viv` all together you can use the included `purge` command:
```sh
python3 <(curl -fsSL viv.dayl.in/viv.py) manage purge
```
## Equivalent commands from alternatives
### [pip-run](https://github.com/jaraco/pip-run)
```sh
pip-run cowsay -- -m cowsay "moove over, pip-run"
python3 <(curl -fsSL viv.dayl.in/viv.py) run cowsay -- "moove over, pip-run"
```
```sh
python -m pip-run requests -- -c "import requests; print(requests.get('https://pypi.org/project/pip-run').status_code)"
python -m viv run requests -b python -- -c "import requests; print(requests.get('https://pypi.org/project/viv').status_code)"
```
### [pipx](https://github.com/pypa/pipx/)
```sh
pipx install pycowsay
viv shim pycowsay
```
```sh
pipx run https://gist.githubusercontent.com/cs01/fa721a17a326e551ede048c5088f9e0f/raw/6bdfbb6e9c1132b1c38fdd2f195d4a24c540c324/pipx-demo.py
python3 <(curl -fsSL viv.dayl.in/viv.py) run \
-s https://gist.githubusercontent.com/cs01/fa721a17a326e551ede048c5088f9e0f/raw/6bdfbb6e9c1132b1c38fdd2f195d4a24c540c324/pipx-demo.py
```
## Bonus: use `viv` with just standalone snippet (37LOC)
## 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`.
@ -58,16 +200,3 @@ See [examples/black](https://github.com/daylinmorgan/viv/blob/dev/examples/black
python3 <(curl -fsSL viv.dayl.in/viv.py) shim black -o ./black --standalone --freeze
```
[^1]: You do need to have `pip` but surely you have `pip` already.
[conda-shield]: https://img.shields.io/conda/vn/conda-forge/viv
[conda-url]: https://anaconda.org/conda-forge/viv
[pypi-shield]: https://img.shields.io/pypi/v/viv
[pypi-url]: https://pypi.org/project/viv
[stars-shield]: https://img.shields.io/github/stars/daylinmorgan/viv.svg
[stars-url]: https://github.com/daylinmorgan/viv/stargazers
[issues-shield]: https://img.shields.io/github/issues/daylinmorgan/viv.svg
[issues-url]: https://github.com/daylinmorgan/viv/issues
[license-shield]: https://img.shields.io/github/license/daylinmorgan/viv.svg
[license-url]: https://github.com/daylinmorgan/viv/blob/main/LICENSE

31
docs/vs-others.md Normal file
View File

@ -0,0 +1,31 @@
# Vs Others
## Equivalent commands from alternatives
### [pip-run](https://github.com/jaraco/pip-run)
```sh
pip-run cowsay -- -m cowsay "moove over, pip-run"
python3 <(curl -fsSL viv.dayl.in/viv.py) run cowsay -- "moove over, pip-run"
```
```sh
python -m pip-run requests -- -c "import requests; print(requests.get('https://pypi.org/project/pip-run').status_code)"
python -m viv run requests -b python -- -c "import requests; print(requests.get('https://pypi.org/project/viv').status_code)"
```
### [pipx](https://github.com/pypa/pipx/)
```sh
pipx install pycowsay
viv shim pycowsay
```
```sh
pipx run https://gist.githubusercontent.com/cs01/fa721a17a326e551ede048c5088f9e0f/raw/6bdfbb6e9c1132b1c38fdd2f195d4a24c540c324/pipx-demo.py
python3 <(curl -fsSL viv.dayl.in/viv.py) run \
-s https://gist.githubusercontent.com/cs01/fa721a17a326e551ede048c5088f9e0f/raw/6bdfbb6e9c1132b1c38fdd2f195d4a24c540c324/pipx-demo.py
```

106
pdm.lock
View File

@ -5,7 +5,7 @@
groups = ["default", "dev", "docs", "test"]
strategy = ["cross_platform"]
lock_version = "4.4.1"
content_hash = "sha256:67b99f093f433bb1a56dc393d51c615b65e94ea9ad397a5460c5a2a29a21cb22"
content_hash = "sha256:527163383ae4b3489c9082bc814dacd347ee94ad6615c214ba63496eb1bdad2a"
[[package]]
name = "alabaster"
@ -50,16 +50,6 @@ files = [
{file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"},
]
[[package]]
name = "cfgv"
version = "3.4.0"
requires_python = ">=3.8"
summary = "Validate configuration and produce human readable error messages."
files = [
{file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"},
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
]
[[package]]
name = "charset-normalizer"
version = "3.3.2"
@ -155,15 +145,6 @@ files = [
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "distlib"
version = "0.3.8"
summary = "Distribution utilities"
files = [
{file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
{file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
]
[[package]]
name = "docutils"
version = "0.20.1"
@ -184,26 +165,6 @@ files = [
{file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"},
]
[[package]]
name = "filelock"
version = "3.13.1"
requires_python = ">=3.8"
summary = "A platform independent file lock."
files = [
{file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"},
{file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"},
]
[[package]]
name = "identify"
version = "2.5.33"
requires_python = ">=3.8"
summary = "File identification library for Python"
files = [
{file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"},
{file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"},
]
[[package]]
name = "idna"
version = "3.6"
@ -436,19 +397,6 @@ files = [
{file = "myst_parser-2.0.0.tar.gz", hash = "sha256:ea929a67a6a0b1683cdbe19b8d2e724cd7643f8aa3e7bb18dd65beac3483bead"},
]
[[package]]
name = "nodeenv"
version = "1.8.0"
requires_python = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
summary = "Node.js virtual environment builder"
dependencies = [
"setuptools",
]
files = [
{file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"},
{file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"},
]
[[package]]
name = "packaging"
version = "23.2"
@ -468,16 +416,6 @@ files = [
{file = "peppercorn-0.6.tar.gz", hash = "sha256:96d7681d7a04545cfbaf2c6fb66de67b29cfc42421aa263e4c78f2cbb85be4c6"},
]
[[package]]
name = "platformdirs"
version = "4.1.0"
requires_python = ">=3.8"
summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
files = [
{file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"},
{file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"},
]
[[package]]
name = "pluggy"
version = "1.3.0"
@ -488,23 +426,6 @@ files = [
{file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"},
]
[[package]]
name = "pre-commit"
version = "3.5.0"
requires_python = ">=3.8"
summary = "A framework for managing and maintaining multi-language pre-commit hooks."
dependencies = [
"cfgv>=2.0.0",
"identify>=1.0.0",
"nodeenv>=0.11.1",
"pyyaml>=5.1",
"virtualenv>=20.10.0",
]
files = [
{file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"},
{file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"},
]
[[package]]
name = "pygments"
version = "2.17.2"
@ -632,16 +553,6 @@ files = [
{file = "sampleproject-3.0.0.tar.gz", hash = "sha256:117ed88e5db073bb92969a7545745fd977ee85b7019706dd256a64058f70963d"},
]
[[package]]
name = "setuptools"
version = "69.0.3"
requires_python = ">=3.8"
summary = "Easily download, build, install, upgrade, and uninstall Python packages"
files = [
{file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"},
{file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"},
]
[[package]]
name = "shibuya"
version = "2024.1.2"
@ -840,21 +751,6 @@ files = [
{file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"},
]
[[package]]
name = "virtualenv"
version = "20.25.0"
requires_python = ">=3.7"
summary = "Virtual Python Environment builder"
dependencies = [
"distlib<1,>=0.3.7",
"filelock<4,>=3.12.2",
"platformdirs<5,>=3.9.1",
]
files = [
{file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"},
{file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"},
]
[[package]]
name = "yartsu"
version = "23.5.1b1"

View File

@ -21,20 +21,21 @@ viv = "viv:main"
[tool.pdm]
version = { source = "scm" }
# need python 3.9 for these which I usually have anyways
ignore_package_warnings = ["sphinx*", "myst-parser"]
[tool.pdm.dev-dependencies]
dev = [
"pre-commit>=3",
"mypy>=0.991",
"astor>=0.8.1",
]
docs = [
"sphinx",
"sphinx-autobuild",
"sphinx-copybutton",
"myst-parser",
"shibuya",
"yartsu"
"sphinx",
"sphinx-autobuild",
"sphinx-copybutton",
"myst-parser",
"shibuya",
"yartsu",
]
test = [
"pytest",