Compare commits

..

6 commits

6 changed files with 59 additions and 33 deletions

View file

@ -2,9 +2,13 @@ name: 🧪 Run Tests
on: on:
pull_request: pull_request:
push:
workflow_call: workflow_call:
workflow_dispatch: workflow_dispatch:
push:
paths:
- 'src/**/*.py'
- 'tests/**/*.py'
- 'pyproject.toml'
jobs: jobs:
run-tests: 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. 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 ## Setup
Run the below command to install `viv`. 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 In any Python script with external dependencies you can add this line
to automate `vivenv` creation and installation of dependencies. to automate `vivenv` creation and installation of dependencies.
As a cli:
```sh
viv run frogmouth -- gh daylinmorgan/viv
```
As a python module:
```python ```python
__import__("viv").use("click") __import__("viv").use("click")
``` ```
As an app installer:
```sh
viv shim ruff
```
To remove all `vivenvs` you can use the below command: To remove all `vivenvs` you can use the below command:
```sh ```sh
@ -89,11 +113,11 @@ To remove `viv` altogether you can use the included `purge` command:
```sh ```sh
python3 <(curl -fsSL viv.dayl.in/viv.py) manage purge python3 <(curl -fsSL viv.dayl.in/viv.py) manage purge
``` ```
## Equivalent commands from alternatives ## Equivalent commands from alternatives
### [pip-run](https://github.com/jaraco/pip-run) ### [pip-run](https://github.com/jaraco/pip-run)
```sh ```sh
pip-run cowsay -- -m cowsay "moove over, pip-run" pip-run cowsay -- -m cowsay "moove over, pip-run"
python3 <(curl -fsSL viv.dayl.in/viv.py) run 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 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-shield]: https://img.shields.io/conda/vn/conda-forge/viv
[conda-url]: https://anaconda.org/conda-forge/viv [conda-url]: https://anaconda.org/conda-forge/viv
[pypi-shield]: https://img.shields.io/pypi/v/viv [pypi-shield]: https://img.shields.io/pypi/v/viv

View file

@ -6,7 +6,7 @@
: **ephemeral** (default): : **ephemeral** (default):
: `viv run` will generate a temporary directory that is removed following execution : `viv run` will generate a temporary directory that is removed following execution
: **semi-ephemeral** : **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 : persist
: `viv run` will always use the standard `VIV_CACHE` which maximizes reusable vivenvs : `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` : Path to use for vivenv cache by default `$XDG_CACHE_HOME/viv` or `$HOME/.cache/viv`
`VIV_LOG_PATH` `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` `VIV_BIN_DIR`
: Path to use for shims by default `$HOME/.local/bin` : Path to use for shims by default `$HOME/.local/bin`
@ -22,7 +22,7 @@
`VIV_NO_SETUPTOOLS` `VIV_NO_SETUPTOOLS`
: Don't add setuptools to generated vivenvs. : Don't add setuptools to generated vivenvs.
: Many legacy packages expect setuptools to be available : 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 To minimize frustration `setuptools` is added to every dependency
list. 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, `Viv`'s uncompromising insistence on portability means that it will always,
only use the standard library and never exceed a single script. 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} ```{toctree}
:hidden: :hidden:

View file

@ -3,10 +3,10 @@
Viv works by ensuring scripts or a given Viv works by ensuring scripts or a given
command are run in an appropriate environment with all specified dependencies. command are run in an appropriate environment with all specified dependencies.
```{tip} :::{tip}
`viv` is a single script and available at viv.dayl.in/viv.py `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)` meaning every instance of `viv` in these examples could be `python3 <(curl -fsSL viv.dayl.in/viv.py)`
``` :::
## Run CLI Apps ## 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 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 ```sh
viv run rich -b python -- -m rich 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 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. 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 In any python script with external dependencies you can also add this line prior to imports
to automate `vivenv` creation and installation of dependencies. 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>` 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 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. 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: You can list vivenvs given a criteria using `--filter` for example:
@ -168,13 +168,13 @@ Or no files:
viv list --filter "files:None" viv list --filter "files:None"
``` ```
```{note} :::{note}
`--filter "files:None"` will also apply to vivenvs `--filter "files:None"` will also apply to vivenvs
in which the original file is no longer on the disk in which the original file is no longer on the disk
``` :::
The available filtering criteria are `accessed-after`, 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: To remove all `vivenvs` you can use the below command:

View file

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