Compare commits

...

6 commits

6 changed files with 59 additions and 33 deletions

View file

@ -2,9 +2,13 @@ name: 🧪 Run Tests
on:
pull_request:
push:
workflow_call:
workflow_dispatch:
push:
paths:
- 'src/**/*.py'
- 'tests/**/*.py'
- 'pyproject.toml'
jobs:
run-tests:

View file

@ -44,6 +44,16 @@ while still unleashing the full power of Python scripting with its entire ecosys
For that reason, any usage of the CLI can be accomplished using a remote copy as seen in the below install command.
`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,
only use the standard library and never exceed a single script.
See the [documentation](https://viv.dayl.in/viv.py) or the [examples](https://github.com/daylinmorgan/viv/tree/main/examples) to get started.
## Setup
Run the below command to install `viv`.
@ -74,10 +84,24 @@ Placing it in its own virtual environment or installing in a user site directory
In any Python script with external dependencies you can add this line
to automate `vivenv` creation and installation of dependencies.
As a cli:
```sh
viv run frogmouth -- gh daylinmorgan/viv
```
As a python module:
```python
__import__("viv").use("click")
```
As an app installer:
```sh
viv shim ruff
```
To remove all `vivenvs` you can use the below command:
```sh
@ -89,11 +113,11 @@ To remove `viv` altogether 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"
@ -132,9 +156,6 @@ for output of the below command.
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

View file

@ -6,7 +6,7 @@
: **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`
: `viv run` will set the `VIV_CACHE` directory to `$TEMPDIR/viv-ephemeral-cache-$USER`
: persist
: `viv run` will always use the standard `VIV_CACHE` which maximizes reusable vivenvs
@ -14,7 +14,7 @@
: 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`
: Path to use for 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`
@ -22,7 +22,7 @@
`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.
and don't appropriately declare it as a dependency.
To minimize frustration `setuptools` is added to every dependency
list.

View file

@ -26,7 +26,6 @@ while still unleashing the full power of python scripting with it's entire ecosy
`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:

View file

@ -3,10 +3,10 @@
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
:::{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
@ -16,7 +16,7 @@ Run a python app that provides an entrypoint and separate args with `--`:
viv run frogmouth -- gh daylinmorgan/viv
```
To run a python module use the `-b/--bin` flag and specify `python`:
Run a python module use the `-b/--bin` flag and specify `python`:
```sh
viv run rich -b python -- -m rich
@ -79,13 +79,13 @@ invoke it with embedded metadata thanks to shebangs:
# ///
```
```{note}
:::{note}
If using a shebang on a python script `-s/--script` must be the last argument
```
:::
```{seealso}
:::{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.
@ -146,10 +146,10 @@ viv env remove d4b342b3
To get more information about vivenvs you can use `viv list --verbose` or `viv env info <hash>`
```{note}
:::{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:
@ -168,13 +168,13 @@ Or no files:
viv list --filter "files:None"
```
```{note}
:::{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`.
`accessed-before`, `created-before`, `created-after`, `spec` and `files`.
To remove all `vivenvs` you can use the below command:

View file

@ -54,7 +54,7 @@ from typing import (
Union,
)
__version__ = "2024.1004"
__version__ = "2024.1004-dev"
#### START VENDORED TOMLI ####
@ -1363,7 +1363,7 @@ class v_packaging_Specifier(v_packaging_BaseSpecifier):
)
self._prereleases = prereleases
@property
@property # type: ignore
def prereleases(self) -> bool:
if self._prereleases is not None:
return self._prereleases
@ -1805,20 +1805,17 @@ class Env:
class System:
def __init__(self) -> None:
self._windows = platform.system() == "Windows"
(self.bin_dir, *_) = ("Scripts",) if self._windows else ("bin",)
self.is_win = platform.system() == "Windows"
(self.bin_dir, *_) = ("Scripts",) if self.is_win else ("bin",)
def bin(self, exe: str) -> str:
return f"{exe}.exe" if self._windows else exe
return f"{exe}.exe" if self.is_win else exe
system = System()
class Cfg:
def __init__(self) -> None:
self.windows = platform.system() == "Windows"
@property
def src(self) -> Path:
p = Path(Env().xdg_data_home) / "viv" / "viv.py"
@ -2602,7 +2599,7 @@ class ViVenv:
self.path,
prompt=f"viv-{self.name}",
clear=True,
symlinks=platform.system() != "Windows",
symlinks=not system.is_win,
)
self.meta.created = str(datetime.today())
@ -2924,7 +2921,7 @@ def _read_metadata_block(script: str) -> dict:
return {}
def _check_python(requires: str):
def _check_python(requires: str) -> None:
version = Version(platform.python_version())
if version not in SpecifierSet(requires):
err_quit(
@ -3277,6 +3274,7 @@ class Viv:
"Pip": subprocess_run(
["pip", "--version"], check_output=True
).strip(),
"PYTHONPATH": os.getenv("PYTHONPATH", ""),
}
)
@ -3868,7 +3866,11 @@ class Cli:
)
def _no_traceback_excepthook(exc_type, exc_val, traceback):
def _no_traceback_excepthook(
exc_type: type[BaseException],
exc_val: BaseException,
traceback: TracebackType | None,
) -> None:
# https://stackoverflow.com/questions/7073268/remove-traceback-in-python-on-ctrl-c
pass