mirror of
https://github.com/daylinmorgan/viv.git
synced 2024-11-09 19:13:14 -06:00
Compare commits
73 commits
6d52afe4fe
...
852ce927c0
Author | SHA1 | Date | |
---|---|---|---|
852ce927c0 | |||
28c268b8f0 | |||
247f80921d | |||
960d7acf26 | |||
68e12d643c | |||
cf2414c0d1 | |||
303831bdb8 | |||
8aced00ace | |||
1b8bcb4454 | |||
c43f2f027c | |||
4c236e96eb | |||
c5bc03f497 | |||
8fb6648e8e | |||
f97a617ac9 | |||
9eba6a303f | |||
6ef2f765d6 | |||
0e5ac7c9c9 | |||
9d237d3b96 | |||
6357a99189 | |||
b822fe432c | |||
032e23af95 | |||
13cb21435d | |||
38b6e4d746 | |||
be3c7f83c9 | |||
5dacf8ab60 | |||
e31d401585 | |||
f53d00e8e2 | |||
f21b90d962 | |||
1bb48eedbc | |||
5fb501aa2c | |||
b2a2597816 | |||
523a9a9d06 | |||
f16ded2a83 | |||
c8051f9513 | |||
12d7f6c322 | |||
976f9fc0fa | |||
6700178d68 | |||
b378d47253 | |||
5c769fc905 | |||
96eb08af6a | |||
726cef3092 | |||
8c8bd616af | |||
3673e4940c | |||
72ca25c302 | |||
153d9fe774 | |||
873310d900 | |||
29d9d965b3 | |||
|
ad544f59d9 | ||
323a194ff0 | |||
64d55811a2 | |||
2bc512314b | |||
8986a436c0 | |||
e6741792ee | |||
134f220b4f | |||
173411dc9e | |||
c05e2ae22a | |||
|
7e5c5746ee | ||
d665f7ac6b | |||
0e262cc0f9 | |||
d71542f5d2 | |||
7286e90a36 | |||
24787a746c | |||
4b3d1fbea5 | |||
da77259862 | |||
2e916cab5f | |||
62c3270826 | |||
3fe4110e06 | |||
ac02151a51 | |||
fa04385997 | |||
cb7d90f0e1 | |||
4cdfb4fc50 | |||
68a6f3155a | |||
f91d6eb4b4 |
36 changed files with 3488 additions and 915 deletions
32
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
32
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
name: Bug Report
|
||||||
|
description: File a bug report
|
||||||
|
labels: ["bug"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
A bug is when something works differently than it is expected to.
|
||||||
|
## Remember to search before filing a new report
|
||||||
|
Please search for this bug in the issue tracker, and use a bug report title that
|
||||||
|
would have made your bug report turn up in the search results for your search query.
|
||||||
|
- type: textarea
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: "Viv & python/pip version info"
|
||||||
|
description: Please include the output of `viv manage show --system` or `python3 <(curl -fsSL viv.dayl.in/viv.py) manage show --system`
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: repro
|
||||||
|
attributes:
|
||||||
|
label: Steps to Reproduce and Observed Behavior
|
||||||
|
description: What exactly can someone else do, in order to observe the problem that you observed? Include the output and all error messages.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: expected
|
||||||
|
attributes:
|
||||||
|
label: Expected Behavior
|
||||||
|
description: What did you expect to happen instead?
|
||||||
|
validations:
|
||||||
|
required: true
|
15
.github/workflows/release.yml
vendored
15
.github/workflows/release.yml
vendored
|
@ -9,24 +9,27 @@ permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
run-tests:
|
||||||
|
uses: ./.github/workflows/test.yml
|
||||||
|
|
||||||
build-n-publish:
|
build-n-publish:
|
||||||
|
needs: run-tests
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write
|
id-token: write
|
||||||
uses: ./.github/workflows/pypi.yml
|
uses: ./.github/workflows/pypi.yml
|
||||||
|
|
||||||
create-release:
|
create-release:
|
||||||
|
needs: build-n-publish
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: update latest tag
|
- name: update latest branch
|
||||||
uses: richardsimko/update-tag@v1
|
run: |
|
||||||
with:
|
git checkout -B latest
|
||||||
tag_name: latest
|
git push --force-with-lease -u origin latest
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Generate New Release
|
- name: Generate New Release
|
||||||
run: gh release create ${{ github.ref }}
|
run: gh release create ${{ github.ref }}
|
||||||
|
|
37
.github/workflows/test.yml
vendored
Normal file
37
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
name: 🧪 Run Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
workflow_call:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'src/**/*.py'
|
||||||
|
- 'tests/**/*.py'
|
||||||
|
- 'pyproject.toml'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run-tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version: ['3.8','3.9','3.10','3.11', '3.12']
|
||||||
|
os:
|
||||||
|
- ubuntu-latest
|
||||||
|
- windows-latest
|
||||||
|
# - macos-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up PDM
|
||||||
|
uses: pdm-project/setup-pdm@v3
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version}}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pdm sync -d -G test
|
||||||
|
|
||||||
|
- name: Run Tests
|
||||||
|
run: pdm run -v pytest tests
|
||||||
|
|
||||||
|
|
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -170,8 +170,11 @@ poetry.toml
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/python
|
# End of https://www.toptal.com/developers/gitignore/api/python
|
||||||
.task.mk
|
.task.mk
|
||||||
# copy of README.md
|
|
||||||
docs/index.md
|
|
||||||
docs/cli.md
|
docs/cli.md
|
||||||
docs/viv.py
|
docs/viv.py
|
||||||
docs/svgs
|
docs/svgs
|
||||||
|
docs/public
|
||||||
|
/tests/.viv-cache
|
||||||
|
/scripts/tomli
|
||||||
|
/scripts/packaging
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
# See https://pre-commit.com for more information
|
# See https://pre-commit.com for more information
|
||||||
# See https://pre-commit.com/hooks.html for more hooks
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: 23.3.0
|
rev: v0.1.10
|
||||||
hooks:
|
|
||||||
- id: black
|
|
||||||
language_version: python
|
|
||||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
|
||||||
rev: 'v0.0.270'
|
|
||||||
hooks:
|
hooks:
|
||||||
|
- id: ruff-format
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args: [--fix, --exit-non-zero-on-fix, --show-fixes]
|
args: [ --fix ]
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
USAGE={a.bold}{a.cyan} viv tasks{a.end}:\n
|
|
||||||
PHONIFY=1
|
|
||||||
HELP_SEP={a.b_blue}>>>{a.end}
|
|
||||||
|
|
||||||
-include .task.mk
|
|
||||||
$(if $(filter help,$(MAKECMDGOALS)),$(if $(wildcard .task.mk),,.task.mk: ; curl -fsSL https://raw.githubusercontent.com/daylinmorgan/task.mk/v23.1.2/task.mk -o .task.mk))
|
|
38
Makefile
38
Makefile
|
@ -1,38 +0,0 @@
|
||||||
VERSION ?= $(shell git describe --tags --always --dirty=-dev | sed 's/^v//g')
|
|
||||||
|
|
||||||
venv: ## generate environment
|
|
||||||
pdm install
|
|
||||||
|
|
||||||
assets/viv-help.svg:
|
|
||||||
FORCE_COLOR=1 viv --help | yartsu -t 'viv --help' -w 70 -o $@
|
|
||||||
|
|
||||||
.PHONY: dev-install
|
|
||||||
dev-install:
|
|
||||||
ln -sf $(PWD)/src/viv/viv.py ~/.local/share/viv/viv.py
|
|
||||||
|
|
||||||
## docs |> update docs files
|
|
||||||
docs: docs/viv.py docs/index.md
|
|
||||||
|
|
||||||
docs/viv.py: src/viv/viv.py
|
|
||||||
@cp $< $@
|
|
||||||
|
|
||||||
docs/index.md: README.md
|
|
||||||
@printf -- '---\nhide: [navigation]\n---\n\n' > $@
|
|
||||||
@cat $< >> $@
|
|
||||||
|
|
||||||
examples/black: .FORCE
|
|
||||||
rm -f $@
|
|
||||||
viv shim black -y -s -f -o $@
|
|
||||||
|
|
||||||
clean: ## remove build artifacts
|
|
||||||
rm -rf {build,dist}
|
|
||||||
|
|
||||||
EXAMPLES = cli.py sys_path.py exe_specific.py frozen_import.py named_env.py scrape.py
|
|
||||||
generate-example-vivens: ##
|
|
||||||
for f in $(EXAMPLES); \
|
|
||||||
do python examples/$$f; done
|
|
||||||
|
|
||||||
|
|
||||||
.FORCE:
|
|
||||||
.PHONY: .FORCE
|
|
||||||
-include .task.cfg.mk
|
|
59
README.md
59
README.md
|
@ -29,20 +29,18 @@
|
||||||
|
|
||||||
Try before you buy!
|
Try before you buy!
|
||||||
```sh
|
```sh
|
||||||
python3 <(curl -fsSL viv.dayl.in/viv.py) run pycowsay -- "viv isn't venv\!"
|
python3 <(curl -fsSL viv.dayl.in/viv.py) run frogmouth -- gh daylinmorgan/viv
|
||||||
```
|
```
|
||||||
---
|
---
|
||||||
|
|
||||||
`Viv` is a standalone dependency-free `venv` creator [^1].
|
`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,
|
`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.
|
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:
|
`Viv`'s uncompromising insistence on portability means that it will always,
|
||||||
|
only use the standard library and never exceed a single script.
|
||||||
|
|
||||||
1. only use the standard library
|
See the [documentation](https://viv.dayl.in) or the [examples](https://github.com/daylinmorgan/viv/tree/main/examples) to get started.
|
||||||
2. never exceed a single script.
|
|
||||||
|
|
||||||
For that reason any usage of the `cli` can be accomplished using a remote copy as seen in the below install command.
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
|
@ -52,8 +50,9 @@ Run the below command to install `viv`.
|
||||||
python3 <(curl -fsSL viv.dayl.in/viv.py) manage install
|
python3 <(curl -fsSL viv.dayl.in/viv.py) manage install
|
||||||
```
|
```
|
||||||
|
|
||||||
To access `viv` from within scripts you should add it's location to your `PYTHONPATH`.
|
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` you can customize this with `--src`.
|
By default `viv` will be installed to `$XDG_DATA_HOME/viv` or `~/.local/share/viv`;
|
||||||
|
you can customize this with `--src`.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
export PYTHONPATH="$PYTHONPATH:$HOME/.local/share/viv"
|
export PYTHONPATH="$PYTHONPATH:$HOME/.local/share/viv"
|
||||||
|
@ -65,34 +64,48 @@ export PYTHONPATH="$PYTHONPATH:$HOME/.local/share/viv"
|
||||||
pip install viv
|
pip install viv
|
||||||
```
|
```
|
||||||
|
|
||||||
Why is this *not recommended*? Mainly, because `viv` is all about hacking your `sys.path`.
|
Why is this *not recommended?* Mainly because `viv` is all about hacking your `sys.path`.
|
||||||
Placing it in it's own virtual environment or installing in a user site directory may complicate this endeavor.
|
Placing it in its own virtual environment or installing in a user site directory may complicate this endeavor.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
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
|
||||||
viv cache remove $(viv list -q)
|
viv env remove $(viv list -q)
|
||||||
```
|
```
|
||||||
|
|
||||||
To remove `viv` all together you can use the included `purge` command:
|
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"
|
||||||
|
@ -100,7 +113,7 @@ python3 <(curl -fsSL viv.dayl.in/viv.py) run cowsay -- "moove over, pip-run"
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
python -m pip-run requests -- -c "import requests; print(requests.get('https://pypi.org/project/pip-run').status_code)"
|
python -m pip-run requests -- -c "import requests; print(requests.get('https://pypi.org/project/pip-run').status_code)"
|
||||||
python -m viv requests -b python -- -c "import requests; print(requests.get('https://pypi.org/project/viv').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/)
|
### [pipx](https://github.com/pypa/pipx/)
|
||||||
|
@ -118,19 +131,19 @@ python3 <(curl -fsSL viv.dayl.in/viv.py) run \
|
||||||
|
|
||||||
## Bonus: use `viv` with just standalone snippet (37LOC)
|
## Bonus: use `viv` with just standalone snippet (37LOC)
|
||||||
|
|
||||||
`--standalone` will auto-generate a mini function version of `viv` to accomplish the same basic task as using a local copy of `viv`.
|
`--standalone` will auto-generate a mini-function version of `viv`
|
||||||
After generating this standalone `shim` you can freely use this script across unix machines which have `python>3.8`.
|
to accomplish the same basic task as using a local copy of `viv`.
|
||||||
See [examples/black](https://github.com/daylinmorgan/viv/blob/dev/examples/black) for output of below command.
|
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 the below command.
|
||||||
|
|
||||||
`viv freeze` also supports `--standalone`
|
`viv freeze` also supports `--standalone`.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
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
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<svg class="rich-terminal shadow" viewBox="0 0 890.3333333333334 545.9333333333333" xmlns="http://www.w3.org/2000/svg">
|
<svg class="rich-terminal shadow" viewBox="0 0 890.3333333333334 521.5333333333333" xmlns="http://www.w3.org/2000/svg">
|
||||||
<!-- Generated with Rich https://www.textualize.io & yartsu https://github.com/daylinmorgan/yartsu -->
|
<!-- Generated with Rich https://www.textualize.io & yartsu https://github.com/daylinmorgan/yartsu -->
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
|
@ -19,14 +19,14 @@
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
.terminal-1538990771-matrix {
|
.terminal-4099597553-matrix {
|
||||||
font-family: Fira Code, monospace;
|
font-family: Fira Code, monospace;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
line-height: 24.4px;
|
line-height: 24.4px;
|
||||||
font-variant-east-asian: full-width;
|
font-variant-east-asian: full-width;
|
||||||
}
|
}
|
||||||
|
|
||||||
.terminal-1538990771-title {
|
.terminal-4099597553-title {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-family: arial;
|
font-family: arial;
|
||||||
|
@ -36,102 +36,98 @@
|
||||||
-webkit-filter: drop-shadow( 2px 5px 2px rgba(0, 0, 0, .7));
|
-webkit-filter: drop-shadow( 2px 5px 2px rgba(0, 0, 0, .7));
|
||||||
filter: drop-shadow( 2px 5px 2px rgba(0, 0, 0, .7));
|
filter: drop-shadow( 2px 5px 2px rgba(0, 0, 0, .7));
|
||||||
}
|
}
|
||||||
.terminal-1538990771-r1 { fill: #94e2d5;font-weight: bold }
|
.terminal-4099597553-r1 { fill: #94e2d5;font-weight: bold }
|
||||||
.terminal-1538990771-r2 { fill: #c6d0f5 }
|
.terminal-4099597553-r2 { fill: #c6d0f5 }
|
||||||
.terminal-1538990771-r3 { fill: #f5c2e7;font-weight: bold }
|
.terminal-4099597553-r3 { fill: #f5c2e7;font-weight: bold }
|
||||||
.terminal-1538990771-r4 { fill: #c6d0f5;font-weight: bold }
|
.terminal-4099597553-r4 { fill: #c6d0f5;font-weight: bold }
|
||||||
.terminal-1538990771-r5 { fill: #f9e2af;font-weight: bold }
|
.terminal-4099597553-r5 { fill: #f9e2af;font-weight: bold }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<defs>
|
<defs>
|
||||||
<clipPath id="terminal-1538990771-clip-terminal">
|
<clipPath id="terminal-4099597553-clip-terminal">
|
||||||
<rect x="0" y="0" width="853.0" height="462.59999999999997" />
|
<rect x="0" y="0" width="853.0" height="438.2" />
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-0">
|
<clipPath id="terminal-4099597553-line-0">
|
||||||
<rect x="0" y="1.5" width="854" height="24.65"/>
|
<rect x="0" y="1.5" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-1">
|
<clipPath id="terminal-4099597553-line-1">
|
||||||
<rect x="0" y="25.9" width="854" height="24.65"/>
|
<rect x="0" y="25.9" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-2">
|
<clipPath id="terminal-4099597553-line-2">
|
||||||
<rect x="0" y="50.3" width="854" height="24.65"/>
|
<rect x="0" y="50.3" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-3">
|
<clipPath id="terminal-4099597553-line-3">
|
||||||
<rect x="0" y="74.7" width="854" height="24.65"/>
|
<rect x="0" y="74.7" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-4">
|
<clipPath id="terminal-4099597553-line-4">
|
||||||
<rect x="0" y="99.1" width="854" height="24.65"/>
|
<rect x="0" y="99.1" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-5">
|
<clipPath id="terminal-4099597553-line-5">
|
||||||
<rect x="0" y="123.5" width="854" height="24.65"/>
|
<rect x="0" y="123.5" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-6">
|
<clipPath id="terminal-4099597553-line-6">
|
||||||
<rect x="0" y="147.9" width="854" height="24.65"/>
|
<rect x="0" y="147.9" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-7">
|
<clipPath id="terminal-4099597553-line-7">
|
||||||
<rect x="0" y="172.3" width="854" height="24.65"/>
|
<rect x="0" y="172.3" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-8">
|
<clipPath id="terminal-4099597553-line-8">
|
||||||
<rect x="0" y="196.7" width="854" height="24.65"/>
|
<rect x="0" y="196.7" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-9">
|
<clipPath id="terminal-4099597553-line-9">
|
||||||
<rect x="0" y="221.1" width="854" height="24.65"/>
|
<rect x="0" y="221.1" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-10">
|
<clipPath id="terminal-4099597553-line-10">
|
||||||
<rect x="0" y="245.5" width="854" height="24.65"/>
|
<rect x="0" y="245.5" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-11">
|
<clipPath id="terminal-4099597553-line-11">
|
||||||
<rect x="0" y="269.9" width="854" height="24.65"/>
|
<rect x="0" y="269.9" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-12">
|
<clipPath id="terminal-4099597553-line-12">
|
||||||
<rect x="0" y="294.3" width="854" height="24.65"/>
|
<rect x="0" y="294.3" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-13">
|
<clipPath id="terminal-4099597553-line-13">
|
||||||
<rect x="0" y="318.7" width="854" height="24.65"/>
|
<rect x="0" y="318.7" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-14">
|
<clipPath id="terminal-4099597553-line-14">
|
||||||
<rect x="0" y="343.1" width="854" height="24.65"/>
|
<rect x="0" y="343.1" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-15">
|
<clipPath id="terminal-4099597553-line-15">
|
||||||
<rect x="0" y="367.5" width="854" height="24.65"/>
|
<rect x="0" y="367.5" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-16">
|
<clipPath id="terminal-4099597553-line-16">
|
||||||
<rect x="0" y="391.9" width="854" height="24.65"/>
|
<rect x="0" y="391.9" width="854" height="24.65"/>
|
||||||
</clipPath>
|
</clipPath>
|
||||||
<clipPath id="terminal-1538990771-line-17">
|
|
||||||
<rect x="0" y="416.3" width="854" height="24.65"/>
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
</defs>
|
||||||
|
|
||||||
<rect fill="#1e1e2e" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="10.1667" y="1" width="870" height="511.6" rx="8"/><text class="terminal-1538990771-title" fill="#c6d0f5" text-anchor="middle" x="435" y="27">viv --help</text>
|
<rect fill="#1e1e2e" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="10.1667" y="1" width="870" height="487.2" rx="8"/><text class="terminal-4099597553-title" fill="#c6d0f5" text-anchor="middle" x="435" y="27">viv --help</text>
|
||||||
<g transform="translate(32,22)">
|
<g transform="translate(32,22)">
|
||||||
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
|
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
|
||||||
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
|
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
|
||||||
<circle cx="44" cy="0" r="7" fill="#28c840"/>
|
<circle cx="44" cy="0" r="7" fill="#28c840"/>
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
<g transform="translate(18.166666666666664, 41) scale(.95)" clip-path="url(#terminal-1538990771-clip-terminal)">
|
<g transform="translate(18.166666666666664, 41) scale(.95)" clip-path="url(#terminal-4099597553-clip-terminal)">
|
||||||
|
|
||||||
<g class="terminal-1538990771-matrix">
|
<g class="terminal-4099597553-matrix">
|
||||||
<text class="terminal-1538990771-r1" x="0" y="20" textLength="61" clip-path="url(#terminal-1538990771-line-0)">usage</text><text class="terminal-1538990771-r2" x="61" y="20" textLength="353.8" clip-path="url(#terminal-1538990771-line-0)">: viv [-h] [-V] <sub-cmd> ...</text><text class="terminal-1538990771-r2" x="854" y="20" textLength="12.2" clip-path="url(#terminal-1538990771-line-0)">
|
<text class="terminal-4099597553-r1" x="0" y="20" textLength="61" clip-path="url(#terminal-4099597553-line-0)">usage</text><text class="terminal-4099597553-r2" x="61" y="20" textLength="353.8" clip-path="url(#terminal-4099597553-line-0)">: viv [-h] [-V] <sub-cmd> ...</text><text class="terminal-4099597553-r2" x="854" y="20" textLength="12.2" clip-path="url(#terminal-4099597553-line-0)">
|
||||||
</text><text class="terminal-1538990771-r2" x="854" y="44.4" textLength="12.2" clip-path="url(#terminal-1538990771-line-1)">
|
</text><text class="terminal-4099597553-r2" x="854" y="44.4" textLength="12.2" clip-path="url(#terminal-4099597553-line-1)">
|
||||||
</text><text class="terminal-1538990771-r3" x="0" y="68.8" textLength="12.2" clip-path="url(#terminal-1538990771-line-2)">v</text><text class="terminal-1538990771-r1" x="12.2" y="68.8" textLength="24.4" clip-path="url(#terminal-1538990771-line-2)">iv</text><text class="terminal-1538990771-r3" x="48.8" y="68.8" textLength="12.2" clip-path="url(#terminal-1538990771-line-2)">i</text><text class="terminal-1538990771-r1" x="61" y="68.8" textLength="48.8" clip-path="url(#terminal-1538990771-line-2)">sn't</text><text class="terminal-1538990771-r3" x="122" y="68.8" textLength="12.2" clip-path="url(#terminal-1538990771-line-2)">v</text><text class="terminal-1538990771-r1" x="134.2" y="68.8" textLength="36.6" clip-path="url(#terminal-1538990771-line-2)">env</text><text class="terminal-1538990771-r2" x="854" y="68.8" textLength="12.2" clip-path="url(#terminal-1538990771-line-2)">
|
</text><text class="terminal-4099597553-r3" x="0" y="68.8" textLength="12.2" clip-path="url(#terminal-4099597553-line-2)">v</text><text class="terminal-4099597553-r1" x="12.2" y="68.8" textLength="24.4" clip-path="url(#terminal-4099597553-line-2)">iv</text><text class="terminal-4099597553-r3" x="48.8" y="68.8" textLength="12.2" clip-path="url(#terminal-4099597553-line-2)">i</text><text class="terminal-4099597553-r1" x="61" y="68.8" textLength="48.8" clip-path="url(#terminal-4099597553-line-2)">sn't</text><text class="terminal-4099597553-r3" x="122" y="68.8" textLength="12.2" clip-path="url(#terminal-4099597553-line-2)">v</text><text class="terminal-4099597553-r1" x="134.2" y="68.8" textLength="36.6" clip-path="url(#terminal-4099597553-line-2)">env</text><text class="terminal-4099597553-r2" x="854" y="68.8" textLength="12.2" clip-path="url(#terminal-4099597553-line-2)">
|
||||||
</text><text class="terminal-1538990771-r2" x="0" y="93.2" textLength="183" clip-path="url(#terminal-1538990771-line-3)">command line: `</text><text class="terminal-1538990771-r4" x="183" y="93.2" textLength="475.8" clip-path="url(#terminal-1538990771-line-3)">viv run typer rich-click -s ./script.py</text><text class="terminal-1538990771-r2" x="658.8" y="93.2" textLength="12.2" clip-path="url(#terminal-1538990771-line-3)">`</text><text class="terminal-1538990771-r2" x="854" y="93.2" textLength="12.2" clip-path="url(#terminal-1538990771-line-3)">
|
</text><text class="terminal-4099597553-r2" x="0" y="93.2" textLength="183" clip-path="url(#terminal-4099597553-line-3)">command line: `</text><text class="terminal-4099597553-r4" x="183" y="93.2" textLength="475.8" clip-path="url(#terminal-4099597553-line-3)">viv run typer rich-click -s ./script.py</text><text class="terminal-4099597553-r2" x="658.8" y="93.2" textLength="12.2" clip-path="url(#terminal-4099597553-line-3)">`</text><text class="terminal-4099597553-r2" x="854" y="93.2" textLength="12.2" clip-path="url(#terminal-4099597553-line-3)">
|
||||||
</text><text class="terminal-1538990771-r2" x="0" y="117.6" textLength="146.4" clip-path="url(#terminal-1538990771-line-4)">python api: </text><text class="terminal-1538990771-r4" x="146.4" y="117.6" textLength="536.8" clip-path="url(#terminal-1538990771-line-4)">__import__("viv").use("typer", "rich-click")</text><text class="terminal-1538990771-r2" x="854" y="117.6" textLength="12.2" clip-path="url(#terminal-1538990771-line-4)">
|
</text><text class="terminal-4099597553-r2" x="0" y="117.6" textLength="146.4" clip-path="url(#terminal-4099597553-line-4)">python api: </text><text class="terminal-4099597553-r4" x="146.4" y="117.6" textLength="536.8" clip-path="url(#terminal-4099597553-line-4)">__import__("viv").use("typer", "rich-click")</text><text class="terminal-4099597553-r2" x="854" y="117.6" textLength="12.2" clip-path="url(#terminal-4099597553-line-4)">
|
||||||
</text><text class="terminal-1538990771-r2" x="854" y="142" textLength="12.2" clip-path="url(#terminal-1538990771-line-5)">
|
</text><text class="terminal-4099597553-r2" x="854" y="142" textLength="12.2" clip-path="url(#terminal-4099597553-line-5)">
|
||||||
</text><text class="terminal-1538990771-r1" x="0" y="166.4" textLength="85.4" clip-path="url(#terminal-1538990771-line-6)">options</text><text class="terminal-1538990771-r2" x="85.4" y="166.4" textLength="12.2" clip-path="url(#terminal-1538990771-line-6)">:</text><text class="terminal-1538990771-r2" x="854" y="166.4" textLength="12.2" clip-path="url(#terminal-1538990771-line-6)">
|
</text><text class="terminal-4099597553-r1" x="0" y="166.4" textLength="85.4" clip-path="url(#terminal-4099597553-line-6)">options</text><text class="terminal-4099597553-r2" x="85.4" y="166.4" textLength="12.2" clip-path="url(#terminal-4099597553-line-6)">:</text><text class="terminal-4099597553-r2" x="854" y="166.4" textLength="12.2" clip-path="url(#terminal-4099597553-line-6)">
|
||||||
</text><text class="terminal-1538990771-r5" x="24.4" y="190.8" textLength="24.4" clip-path="url(#terminal-1538990771-line-7)">-h</text><text class="terminal-1538990771-r2" x="48.8" y="190.8" textLength="24.4" clip-path="url(#terminal-1538990771-line-7)">, </text><text class="terminal-1538990771-r5" x="73.2" y="190.8" textLength="73.2" clip-path="url(#terminal-1538990771-line-7)">--help</text><text class="terminal-1538990771-r2" x="146.4" y="190.8" textLength="463.6" clip-path="url(#terminal-1538990771-line-7)">       show this help message and exit</text><text class="terminal-1538990771-r2" x="854" y="190.8" textLength="12.2" clip-path="url(#terminal-1538990771-line-7)">
|
</text><text class="terminal-4099597553-r5" x="24.4" y="190.8" textLength="24.4" clip-path="url(#terminal-4099597553-line-7)">-h</text><text class="terminal-4099597553-r2" x="48.8" y="190.8" textLength="24.4" clip-path="url(#terminal-4099597553-line-7)">, </text><text class="terminal-4099597553-r5" x="73.2" y="190.8" textLength="73.2" clip-path="url(#terminal-4099597553-line-7)">--help</text><text class="terminal-4099597553-r2" x="146.4" y="190.8" textLength="463.6" clip-path="url(#terminal-4099597553-line-7)">       show this help message and exit</text><text class="terminal-4099597553-r2" x="854" y="190.8" textLength="12.2" clip-path="url(#terminal-4099597553-line-7)">
|
||||||
</text><text class="terminal-1538990771-r5" x="24.4" y="215.2" textLength="24.4" clip-path="url(#terminal-1538990771-line-8)">-V</text><text class="terminal-1538990771-r2" x="48.8" y="215.2" textLength="24.4" clip-path="url(#terminal-1538990771-line-8)">, </text><text class="terminal-1538990771-r5" x="73.2" y="215.2" textLength="109.8" clip-path="url(#terminal-1538990771-line-8)">--version</text><text class="terminal-1538990771-r2" x="183" y="215.2" textLength="512.4" clip-path="url(#terminal-1538990771-line-8)">    show program's version number and exit</text><text class="terminal-1538990771-r2" x="854" y="215.2" textLength="12.2" clip-path="url(#terminal-1538990771-line-8)">
|
</text><text class="terminal-4099597553-r5" x="24.4" y="215.2" textLength="24.4" clip-path="url(#terminal-4099597553-line-8)">-V</text><text class="terminal-4099597553-r2" x="48.8" y="215.2" textLength="24.4" clip-path="url(#terminal-4099597553-line-8)">, </text><text class="terminal-4099597553-r5" x="73.2" y="215.2" textLength="109.8" clip-path="url(#terminal-4099597553-line-8)">--version</text><text class="terminal-4099597553-r2" x="183" y="215.2" textLength="512.4" clip-path="url(#terminal-4099597553-line-8)">    show program's version number and exit</text><text class="terminal-4099597553-r2" x="854" y="215.2" textLength="12.2" clip-path="url(#terminal-4099597553-line-8)">
|
||||||
</text><text class="terminal-1538990771-r2" x="854" y="239.6" textLength="12.2" clip-path="url(#terminal-1538990771-line-9)">
|
</text><text class="terminal-4099597553-r2" x="854" y="239.6" textLength="12.2" clip-path="url(#terminal-4099597553-line-9)">
|
||||||
</text><text class="terminal-1538990771-r1" x="0" y="264" textLength="134.2" clip-path="url(#terminal-1538990771-line-10)">subcommands</text><text class="terminal-1538990771-r2" x="134.2" y="264" textLength="12.2" clip-path="url(#terminal-1538990771-line-10)">:</text><text class="terminal-1538990771-r2" x="854" y="264" textLength="12.2" clip-path="url(#terminal-1538990771-line-10)">
|
</text><text class="terminal-4099597553-r1" x="0" y="264" textLength="134.2" clip-path="url(#terminal-4099597553-line-10)">subcommands</text><text class="terminal-4099597553-r2" x="134.2" y="264" textLength="12.2" clip-path="url(#terminal-4099597553-line-10)">:</text><text class="terminal-4099597553-r2" x="854" y="264" textLength="12.2" clip-path="url(#terminal-4099597553-line-10)">
|
||||||
</text><text class="terminal-1538990771-r5" x="24.4" y="288.4" textLength="109.8" clip-path="url(#terminal-1538990771-line-11)"><sub-cmd></text><text class="terminal-1538990771-r2" x="854" y="288.4" textLength="12.2" clip-path="url(#terminal-1538990771-line-11)">
|
</text><text class="terminal-4099597553-r5" x="24.4" y="288.4" textLength="109.8" clip-path="url(#terminal-4099597553-line-11)"><sub-cmd></text><text class="terminal-4099597553-r2" x="854" y="288.4" textLength="12.2" clip-path="url(#terminal-4099597553-line-11)">
|
||||||
</text><text class="terminal-1538990771-r5" x="48.8" y="312.8" textLength="97.6" clip-path="url(#terminal-1538990771-line-12)">list (l)</text><text class="terminal-1538990771-r2" x="146.4" y="312.8" textLength="231.8" clip-path="url(#terminal-1538990771-line-12)">       list vivenvs</text><text class="terminal-1538990771-r2" x="854" y="312.8" textLength="12.2" clip-path="url(#terminal-1538990771-line-12)">
|
</text><text class="terminal-4099597553-r5" x="48.8" y="312.8" textLength="97.6" clip-path="url(#terminal-4099597553-line-12)">list (l)</text><text class="terminal-4099597553-r2" x="146.4" y="312.8" textLength="231.8" clip-path="url(#terminal-4099597553-line-12)">       list vivenvs</text><text class="terminal-4099597553-r2" x="854" y="312.8" textLength="12.2" clip-path="url(#terminal-4099597553-line-12)">
|
||||||
</text><text class="terminal-1538990771-r5" x="48.8" y="337.2" textLength="97.6" clip-path="url(#terminal-1538990771-line-13)">shim (s)</text><text class="terminal-1538990771-r2" x="146.4" y="337.2" textLength="439.2" clip-path="url(#terminal-1538990771-line-13)">       generate viv-powered cli apps</text><text class="terminal-1538990771-r2" x="854" y="337.2" textLength="12.2" clip-path="url(#terminal-1538990771-line-13)">
|
</text><text class="terminal-4099597553-r5" x="48.8" y="337.2" textLength="97.6" clip-path="url(#terminal-4099597553-line-13)">shim (s)</text><text class="terminal-4099597553-r2" x="146.4" y="337.2" textLength="439.2" clip-path="url(#terminal-4099597553-line-13)">       generate viv-powered cli apps</text><text class="terminal-4099597553-r2" x="854" y="337.2" textLength="12.2" clip-path="url(#terminal-4099597553-line-13)">
|
||||||
</text><text class="terminal-1538990771-r5" x="48.8" y="361.6" textLength="85.4" clip-path="url(#terminal-1538990771-line-14)">run (r)</text><text class="terminal-1538990771-r2" x="134.2" y="361.6" textLength="585.6" clip-path="url(#terminal-1538990771-line-14)">        run an app/script with an on-demand venv</text><text class="terminal-1538990771-r2" x="854" y="361.6" textLength="12.2" clip-path="url(#terminal-1538990771-line-14)">
|
</text><text class="terminal-4099597553-r5" x="48.8" y="361.6" textLength="85.4" clip-path="url(#terminal-4099597553-line-14)">run (r)</text><text class="terminal-4099597553-r2" x="134.2" y="361.6" textLength="585.6" clip-path="url(#terminal-4099597553-line-14)">        run an app/script with an on-demand venv</text><text class="terminal-4099597553-r2" x="854" y="361.6" textLength="12.2" clip-path="url(#terminal-4099597553-line-14)">
|
||||||
</text><text class="terminal-1538990771-r5" x="48.8" y="386" textLength="85.4" clip-path="url(#terminal-1538990771-line-15)">exe (e)</text><text class="terminal-1538990771-r2" x="134.2" y="386" textLength="536.8" clip-path="url(#terminal-1538990771-line-15)">        run binary/script in existing vivenv</text><text class="terminal-1538990771-r2" x="854" y="386" textLength="12.2" clip-path="url(#terminal-1538990771-line-15)">
|
</text><text class="terminal-4099597553-r5" x="48.8" y="386" textLength="85.4" clip-path="url(#terminal-4099597553-line-15)">env (e)</text><text class="terminal-4099597553-r2" x="134.2" y="386" textLength="427" clip-path="url(#terminal-4099597553-line-15)">        manage the viv vivenv cache</text><text class="terminal-4099597553-r2" x="854" y="386" textLength="12.2" clip-path="url(#terminal-4099597553-line-15)">
|
||||||
</text><text class="terminal-1538990771-r5" x="48.8" y="410.4" textLength="109.8" clip-path="url(#terminal-1538990771-line-16)">cache (c)</text><text class="terminal-1538990771-r2" x="158.6" y="410.4" textLength="402.6" clip-path="url(#terminal-1538990771-line-16)">      manage the viv vivenv cache</text><text class="terminal-1538990771-r2" x="854" y="410.4" textLength="12.2" clip-path="url(#terminal-1538990771-line-16)">
|
</text><text class="terminal-4099597553-r5" x="48.8" y="410.4" textLength="122" clip-path="url(#terminal-4099597553-line-16)">freeze (f)</text><text class="terminal-4099597553-r2" x="170.8" y="410.4" textLength="561.2" clip-path="url(#terminal-4099597553-line-16)">     create import statement from package spec</text><text class="terminal-4099597553-r2" x="854" y="410.4" textLength="12.2" clip-path="url(#terminal-4099597553-line-16)">
|
||||||
</text><text class="terminal-1538990771-r5" x="48.8" y="434.8" textLength="122" clip-path="url(#terminal-1538990771-line-17)">freeze (f)</text><text class="terminal-1538990771-r2" x="170.8" y="434.8" textLength="561.2" clip-path="url(#terminal-1538990771-line-17)">     create import statement from package spec</text><text class="terminal-1538990771-r2" x="854" y="434.8" textLength="12.2" clip-path="url(#terminal-1538990771-line-17)">
|
</text><text class="terminal-4099597553-r5" x="48.8" y="434.8" textLength="122" clip-path="url(#terminal-4099597553-line-17)">manage (m)</text><text class="terminal-4099597553-r2" x="170.8" y="434.8" textLength="268.4" clip-path="url(#terminal-4099597553-line-17)">     manage viv itself</text><text class="terminal-4099597553-r2" x="854" y="434.8" textLength="12.2" clip-path="url(#terminal-4099597553-line-17)">
|
||||||
</text><text class="terminal-1538990771-r5" x="48.8" y="459.2" textLength="122" clip-path="url(#terminal-1538990771-line-18)">manage (m)</text><text class="terminal-1538990771-r2" x="170.8" y="459.2" textLength="268.4" clip-path="url(#terminal-1538990771-line-18)">     manage viv itself</text><text class="terminal-1538990771-r2" x="854" y="459.2" textLength="12.2" clip-path="url(#terminal-1538990771-line-18)">
|
|
||||||
</text>
|
</text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
23
docs/conf.py
Normal file
23
docs/conf.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
project = "Viv"
|
||||||
|
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"]
|
||||||
|
html_extra_path = ["viv.py"]
|
||||||
|
|
||||||
|
|
||||||
|
html_theme = "shibuya"
|
||||||
|
# html_static_path = ["_static"]
|
||||||
|
html_logo = "../assets/logo.svg"
|
||||||
|
|
||||||
|
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
45
docs/configuration.md
Normal 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` 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 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`
|
||||||
|
|
||||||
|
`VIV_NO_SETUPTOOLS`
|
||||||
|
: Don't add setuptools to generated vivenvs.
|
||||||
|
: Many legacy packages expect setuptools to be available
|
||||||
|
and don't appropriately declare it as a 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
|
40
docs/index.md
Normal file
40
docs/index.md
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
---
|
||||||
|
layout: landing
|
||||||
|
cover: http://viv.dayl.in/_static/logo.svg
|
||||||
|
desciption: Viv isn't venv
|
||||||
|
---
|
||||||
|
|
||||||
|
# viv isn't venv
|
||||||
|
|
||||||
|
Try before you buy!
|
||||||
|
```sh
|
||||||
|
python3 <(curl -fsSL viv.dayl.in/viv.py) run frogmouth -- gh daylinmorgan/viv
|
||||||
|
```
|
||||||
|
|
||||||
|
:::{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,
|
||||||
|
only use the standard library and never exceed a single script.
|
||||||
|
|
||||||
|
|
||||||
|
```{toctree}
|
||||||
|
:hidden:
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
installation.md
|
||||||
|
usage.md
|
||||||
|
configuration.md
|
||||||
|
vs-others.md
|
||||||
|
cli.md
|
||||||
|
```
|
||||||
|
|
56
docs/installation.md
Normal file
56
docs/installation.md
Normal 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.
|
202
docs/usage.md
Normal file
202
docs/usage.md
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
# 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 <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`, `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
|
||||||
|
```
|
||||||
|
|
31
docs/vs-others.md
Normal file
31
docs/vs-others.md
Normal 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
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ it will generate a new vivenv.
|
||||||
It may be important to require a exe specificty if you are frequently running
|
It may be important to require a exe specificty if you are frequently running
|
||||||
different version of pythons and rely on c extension modules as in numpy.
|
different version of pythons and rely on c extension modules as in numpy.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__import__("viv").use("numpy", "plotext", track_exe=True) # noqa
|
__import__("viv").use("numpy", "plotext", track_exe=True) # noqa
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
|
@ -6,6 +6,7 @@ This import statement was generated using
|
||||||
Using viv freeze ensures future runs of this
|
Using viv freeze ensures future runs of this
|
||||||
script will use the same essential environment
|
script will use the same essential environment
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__import__("viv").use(
|
__import__("viv").use(
|
||||||
"numpy==1.24.0",
|
"numpy==1.24.0",
|
||||||
"pandas==1.5.2",
|
"pandas==1.5.2",
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
#!/usr/bin/env -S viv run -s
|
|
||||||
# In order to run, this script needs the following 3rd party libraries
|
|
||||||
#
|
|
||||||
# Script Dependencies:
|
|
||||||
# requests
|
|
||||||
# rich # Needed for the output
|
|
||||||
#
|
|
||||||
# # Not needed - just to show that fragments in URLs do not
|
|
||||||
# # get treated as comments
|
|
||||||
# pip @ https://github.com/pypa/pip/archive/1.3.1.zip#sha1=2e15a2d4e7e9f394a9c7a6c905c6a239402a6442
|
|
||||||
|
|
||||||
import requests
|
|
||||||
from rich.pretty import pprint
|
|
||||||
|
|
||||||
resp = requests.get("https://peps.python.org/api/peps.json")
|
|
||||||
data = resp.json()
|
|
||||||
pprint([(k, v["title"]) for k, v in data.items()][:10])
|
|
15
examples/pep723.py
Executable file
15
examples/pep723.py
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env -S viv run -s
|
||||||
|
# /// script
|
||||||
|
# requires-python = ">=3.11"
|
||||||
|
# dependencies = [
|
||||||
|
# "requests<3",
|
||||||
|
# "rich",
|
||||||
|
# ]
|
||||||
|
# ///
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from rich import print
|
||||||
|
|
||||||
|
resp = requests.get("https://peps.python.org/api/peps.json")
|
||||||
|
data = resp.json()
|
||||||
|
print([(k, v["title"]) for k, v in data.items()][:10])
|
17
examples/pep723_run.py
Executable file
17
examples/pep723_run.py
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# /// script
|
||||||
|
# requires-python = ">=3.11"
|
||||||
|
# dependencies = [
|
||||||
|
# "requests<3",
|
||||||
|
# "rich",
|
||||||
|
# ]
|
||||||
|
# ///
|
||||||
|
|
||||||
|
__import__("viv").run()
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from rich import print
|
||||||
|
|
||||||
|
resp = requests.get("https://peps.python.org/api/peps.json")
|
||||||
|
data = resp.json()
|
||||||
|
print([(k, v["title"]) for k, v in data.items()][:10])
|
0
examples/stopwatch.py
Executable file → Normal file
0
examples/stopwatch.py
Executable file → Normal file
|
@ -2,14 +2,13 @@
|
||||||
"""
|
"""
|
||||||
Embed the viv.py on the sys.path at runtime rather than using PYTHONPATH
|
Embed the viv.py on the sys.path at runtime rather than using PYTHONPATH
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
old_sys_path = sys.path.copy() # noqa
|
old_sys_path = sys.path.copy() # noqa
|
||||||
|
|
||||||
|
|
||||||
__import__("sys").path.append(
|
__import__("sys").path.append(__import__("os").path.expanduser("~/.local/share/viv")) # noqa # isort: off
|
||||||
__import__("os").path.expanduser("~/.local/share/viv")
|
|
||||||
) # noqa # isort: off
|
|
||||||
__import__("viv").use("rich") # noqa # isort: off
|
__import__("viv").use("rich") # noqa # isort: off
|
||||||
|
|
||||||
from difflib import unified_diff
|
from difflib import unified_diff
|
||||||
|
|
35
mkdocs.yml
35
mkdocs.yml
|
@ -1,35 +0,0 @@
|
||||||
site_name: viv
|
|
||||||
site_url: https://viv.dayl.in
|
|
||||||
repo_url: https://github.com/daylinmorgan/viv
|
|
||||||
edit_uri: edit/main/docs/
|
|
||||||
repo_name: daylinmorgan/viv
|
|
||||||
|
|
||||||
nav:
|
|
||||||
- home: index.md
|
|
||||||
- cli: cli.md
|
|
||||||
|
|
||||||
theme:
|
|
||||||
name: material
|
|
||||||
logo: https://raw.githubusercontent.com/daylinmorgan/viv/main/assets/logo.svg
|
|
||||||
favicon: https://raw.githubusercontent.com/daylinmorgan/viv/main/assets/logo.svg
|
|
||||||
features:
|
|
||||||
- navigation.tabs
|
|
||||||
- navigation.indexes
|
|
||||||
|
|
||||||
palette:
|
|
||||||
# Palette toggle for dark mode
|
|
||||||
- scheme: slate
|
|
||||||
primary: deep purple
|
|
||||||
toggle:
|
|
||||||
icon: material/brightness-4
|
|
||||||
name: Switch to light mode
|
|
||||||
|
|
||||||
# Palette toggle for light mode
|
|
||||||
- scheme: default
|
|
||||||
primary: deep purple
|
|
||||||
toggle:
|
|
||||||
icon: material/brightness-7
|
|
||||||
name: Switch to dark mode
|
|
||||||
|
|
||||||
markdown_extensions:
|
|
||||||
- footnotes
|
|
18
noxfile.py
18
noxfile.py
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import nox
|
import nox
|
||||||
|
@ -42,11 +43,11 @@ def docs(session):
|
||||||
if not Path("docs/svgs").is_dir():
|
if not Path("docs/svgs").is_dir():
|
||||||
svgs(session)
|
svgs(session)
|
||||||
|
|
||||||
session.run("make", "docs", external=True)
|
shutil.copyfile("src/viv/viv.py", "docs/viv.py")
|
||||||
if session.interactive:
|
if session.interactive:
|
||||||
session.run("mkdocs", "serve")
|
session.run("sphinx-autobuild", "docs", "site", "--port", "8787")
|
||||||
else:
|
else:
|
||||||
session.run("mkdocs", "build")
|
session.run("sphinx-build", "docs", "site")
|
||||||
|
|
||||||
|
|
||||||
@nox.session
|
@nox.session
|
||||||
|
@ -54,10 +55,7 @@ def release(session):
|
||||||
session.run("./scripts/release.py", external=True)
|
session.run("./scripts/release.py", external=True)
|
||||||
|
|
||||||
|
|
||||||
# @nox.session(
|
@nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12"])
|
||||||
# python=["3.8", "3.9", "3.10", "3.11"]
|
def test(session):
|
||||||
# )
|
pdm_install(session, "test")
|
||||||
# def test(session):
|
session.run("pytest", "tests/")
|
||||||
# pdm_install(session,'test')
|
|
||||||
# session.run('pytest')
|
|
||||||
#
|
|
||||||
|
|
|
@ -21,18 +21,28 @@ viv = "viv:main"
|
||||||
|
|
||||||
[tool.pdm]
|
[tool.pdm]
|
||||||
version = { source = "scm" }
|
version = { source = "scm" }
|
||||||
|
# need python 3.9 for these which I usually have anyways
|
||||||
|
ignore_package_warnings = ["sphinx*", "myst-parser"]
|
||||||
|
|
||||||
[tool.pdm.dev-dependencies]
|
[tool.pdm.dev-dependencies]
|
||||||
dev = [
|
dev = [
|
||||||
"pre-commit>=3",
|
|
||||||
"mypy>=0.991",
|
"mypy>=0.991",
|
||||||
|
"astor>=0.8.1",
|
||||||
]
|
]
|
||||||
docs = [
|
docs = [
|
||||||
"mkdocs-material>=9.1.15",
|
"sphinx",
|
||||||
"yartsu"
|
"sphinx-autobuild",
|
||||||
|
"sphinx-copybutton",
|
||||||
|
"myst-parser",
|
||||||
|
"shibuya",
|
||||||
|
"yartsu",
|
||||||
]
|
]
|
||||||
|
test = [
|
||||||
|
"pytest",
|
||||||
|
"sampleproject"
|
||||||
|
]
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff.lint]
|
||||||
select = ["E","F","I"]
|
select = ["E","F","I"]
|
||||||
ignore = ["E402"]
|
ignore = ["E402"]
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ CLI_DOC_PATH = DOCS_PATH / "cli.md"
|
||||||
cmds := dict.fromkeys(
|
cmds := dict.fromkeys(
|
||||||
(
|
(
|
||||||
"list",
|
"list",
|
||||||
"exe",
|
|
||||||
"manage",
|
"manage",
|
||||||
"freeze",
|
"freeze",
|
||||||
"shim",
|
"shim",
|
||||||
|
@ -24,7 +23,10 @@ CLI_DOC_PATH = DOCS_PATH / "cli.md"
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
).update(
|
).update(
|
||||||
{"manage": ["update", "purge", "show", "install"], "cache": ["info", "remove"]},
|
{
|
||||||
|
"manage": ["update", "purge", "show", "install"],
|
||||||
|
"env": ["exe", "info", "remove"],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,7 +35,7 @@ cli_doc = """\
|
||||||
hide: [navigation]
|
hide: [navigation]
|
||||||
---
|
---
|
||||||
|
|
||||||
# cli
|
# CLI Reference
|
||||||
|
|
||||||
![help](./svgs/viv-help.svg)
|
![help](./svgs/viv-help.svg)
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -46,11 +46,14 @@ def release():
|
||||||
next = f"{datetime.now().year}.{inc_build(build)}"
|
next = f"{datetime.now().year}.{inc_build(build)}"
|
||||||
msg = f"bump {current} -> {next}"
|
msg = f"bump {current} -> {next}"
|
||||||
FILE.write_text(
|
FILE.write_text(
|
||||||
re.sub(r'__version__ = "[\d\.]+"', f'__version__ = "{next}"', FILE.read_text())
|
re.sub(r'__version__ = ".*"', f'__version__ = "{next}"', FILE.read_text())
|
||||||
)
|
)
|
||||||
subprocess.run(["git", "add", FILE])
|
subprocess.run(["git", "add", FILE])
|
||||||
subprocess.run(["git", "commit", "-m", msg, "--no-verify"])
|
subprocess.run(["git", "commit", "-m", msg, "--no-verify"])
|
||||||
subprocess.run(["git", "tag", f"v{next}"])
|
subprocess.run(["git", "tag", f"v{next}"])
|
||||||
|
FILE.write_text(
|
||||||
|
re.sub(r'__version__ = ".*"', f'__version__ = "{next}-dev"', FILE.read_text())
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
222
scripts/vendor.py
Executable file
222
scripts/vendor.py
Executable file
|
@ -0,0 +1,222 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import ast
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import textwrap
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
import astor
|
||||||
|
|
||||||
|
|
||||||
|
def remove_docs_and_comments(code):
|
||||||
|
parsed = ast.parse(code)
|
||||||
|
for node in ast.walk(parsed):
|
||||||
|
if isinstance(node, ast.Expr) and isinstance(node.value, ast.Str):
|
||||||
|
# set value to empty string which should be ignored by astor.to_source
|
||||||
|
node.value = ast.Constant(value="")
|
||||||
|
elif (
|
||||||
|
(isinstance(node, ast.FunctionDef) or isinstance(node, ast.ClassDef))
|
||||||
|
and len(node.body) == 1
|
||||||
|
and isinstance(node.body[0], ast.Expr)
|
||||||
|
and isinstance(node.body[0].value, ast.Constant)
|
||||||
|
):
|
||||||
|
# add pass to empty functions and class definition
|
||||||
|
node.body = [ast.Pass()]
|
||||||
|
formatted_code = astor.to_source(parsed)
|
||||||
|
pattern = r'^.*"""""".*$' # remove empty """"""
|
||||||
|
formatted_code = re.sub(pattern, "", formatted_code, flags=re.MULTILINE)
|
||||||
|
return formatted_code
|
||||||
|
|
||||||
|
|
||||||
|
class Package:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
url: str,
|
||||||
|
files: List[tuple[str, List[List[int]]]],
|
||||||
|
rev: str,
|
||||||
|
basepath: Path,
|
||||||
|
imports: str = "",
|
||||||
|
prefix: str = "",
|
||||||
|
suffix: str = "",
|
||||||
|
indent: bool = False,
|
||||||
|
):
|
||||||
|
self.name = name
|
||||||
|
self.files = files
|
||||||
|
self.url = url
|
||||||
|
self.rev = rev
|
||||||
|
self.basepath = basepath
|
||||||
|
self.imports = imports
|
||||||
|
self.prefix = prefix
|
||||||
|
self.suffix = suffix
|
||||||
|
self.indent = indent
|
||||||
|
|
||||||
|
self.ensure()
|
||||||
|
self.generate_vendored_source()
|
||||||
|
self.replace_identifiers()
|
||||||
|
|
||||||
|
def ensure(self):
|
||||||
|
dir = Path(__file__).parent / self.name
|
||||||
|
if not dir.is_dir():
|
||||||
|
subprocess.run(["git", "clone", self.url, dir])
|
||||||
|
subprocess.run(["git", "-C", dir, "checkout", self.rev])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def start_delim(self) -> str:
|
||||||
|
return f"#### START VENDORED {self.name.upper()} ####"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def end_delim(self) -> str:
|
||||||
|
return f"#### END VENDORED {self.name.upper()} ####"
|
||||||
|
|
||||||
|
def generate_vendored_source(self):
|
||||||
|
self.src_text = ""
|
||||||
|
for f, slices in self.files:
|
||||||
|
og_text = (self.basepath / f"{f}.py").read_text()
|
||||||
|
for indices in slices:
|
||||||
|
self.src_text = "\n".join(
|
||||||
|
(
|
||||||
|
self.src_text,
|
||||||
|
*[
|
||||||
|
line
|
||||||
|
for line in og_text.splitlines()[slice(*indices)]
|
||||||
|
if line.strip("\r\n")
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def replace_identifiers(self):
|
||||||
|
patterns = set.union(
|
||||||
|
*[
|
||||||
|
set(re.findall(regex, self.src_text, re.MULTILINE))
|
||||||
|
for regex in (
|
||||||
|
r"^class (?P<class>[a-zA-Z_]*)(?:\(.*\))?:",
|
||||||
|
r"^(?P<ident>[a-zA-Z_]*) =",
|
||||||
|
r"^def (?P<function>[a-zA-Z_]+)\(",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
) - {
|
||||||
|
"Key",
|
||||||
|
} # prevent KeyError false positive by leaving Key alone
|
||||||
|
|
||||||
|
for pat in patterns:
|
||||||
|
self.src_text = re.sub(
|
||||||
|
r'(?P<lead>[\s("\[={])' + pat,
|
||||||
|
f"\g<lead>v_{self.name}_{pat}",
|
||||||
|
self.src_text,
|
||||||
|
)
|
||||||
|
|
||||||
|
def insert(self, base_text: str) -> str:
|
||||||
|
start, rest = re.split(self.start_delim, base_text)
|
||||||
|
_, rest = re.split(self.end_delim, base_text)
|
||||||
|
src = textwrap.indent(
|
||||||
|
remove_docs_and_comments(self.src_text.strip()),
|
||||||
|
prefix=" " * (4 if self.indent else 0),
|
||||||
|
)
|
||||||
|
return "\n".join(
|
||||||
|
(
|
||||||
|
start.strip(),
|
||||||
|
"\n",
|
||||||
|
self.start_delim,
|
||||||
|
self.prefix + self.imports + src + self.suffix,
|
||||||
|
self.end_delim,
|
||||||
|
"\n",
|
||||||
|
rest.strip(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
PACKAGES = [
|
||||||
|
Package(
|
||||||
|
name="packaging",
|
||||||
|
url="https://github.com/pypa/packaging.git",
|
||||||
|
# v24.0
|
||||||
|
rev="7a983f7f0068669ead9d4f7571be24d6c0d83eb9",
|
||||||
|
files=(
|
||||||
|
("_structures", [[5, 61]]),
|
||||||
|
("version", [[17, 563]]),
|
||||||
|
("utils", [[54, 100]]),
|
||||||
|
("specifiers", [[18, 1017]]),
|
||||||
|
),
|
||||||
|
basepath=Path(__file__).parent / "packaging/src/packaging",
|
||||||
|
prefix="""
|
||||||
|
# MODIFIED FROM https://github.com/pypa/packaging
|
||||||
|
# see repo for original licenses
|
||||||
|
# This software is made available under the terms of *either* of the licenses
|
||||||
|
# found in LICENSE.APACHE or LICENSE.BSD. Contributions to this software is made
|
||||||
|
# under the terms of *both* these licenses.
|
||||||
|
""",
|
||||||
|
imports="""
|
||||||
|
import abc # noqa
|
||||||
|
import itertools # noqa
|
||||||
|
import re # noqa
|
||||||
|
from typing import ( # noqa
|
||||||
|
Any,
|
||||||
|
Callable,
|
||||||
|
Iterable,
|
||||||
|
Iterator,
|
||||||
|
List,
|
||||||
|
NamedTuple,
|
||||||
|
Optional,
|
||||||
|
Set,
|
||||||
|
SupportsInt,
|
||||||
|
Tuple,
|
||||||
|
TypeVar,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
suffix="""
|
||||||
|
Version = v_packaging_Version
|
||||||
|
SpecifierSet = v_packaging_SpecifierSet
|
||||||
|
""",
|
||||||
|
),
|
||||||
|
Package(
|
||||||
|
name="tomli",
|
||||||
|
url="https://github.com/hukkin/tomli.git",
|
||||||
|
# rev="2.0.1",
|
||||||
|
rev="a6138675bcca68eea5b8abec7c2ec06d57f965a0",
|
||||||
|
files=(
|
||||||
|
("_types", [[7, 11]]),
|
||||||
|
("_re", [[14, 107]]),
|
||||||
|
("_parser", [[20, 691]]),
|
||||||
|
),
|
||||||
|
prefix="""
|
||||||
|
if sys.version_info >= (3, 11):
|
||||||
|
from tomllib import loads as toml_loads
|
||||||
|
else:
|
||||||
|
# MODIFIED FROM https://github.com/hukkin/tomli
|
||||||
|
# see below for original license
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# SPDX-FileCopyrightText: 2021 Taneli Hukkinen
|
||||||
|
# Licensed to PSF under a Contributor Agreement.
|
||||||
|
""",
|
||||||
|
imports="""
|
||||||
|
import string # noqa
|
||||||
|
from collections.abc import Iterable # noqa
|
||||||
|
from functools import lru_cache # noqa
|
||||||
|
from datetime import date, datetime, time, timedelta, timezone, tzinfo # noqa
|
||||||
|
from types import MappingProxyType # noqa
|
||||||
|
from typing import IO, Any, Callable, NamedTuple # noqa
|
||||||
|
""",
|
||||||
|
basepath=Path(__file__).parent / "tomli/src/tomli",
|
||||||
|
suffix="""
|
||||||
|
toml_loads = v_tomli_loads
|
||||||
|
""",
|
||||||
|
indent=True,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
viv_source_path = Path(__file__).parent.parent / "src/viv/viv.py"
|
||||||
|
viv_source = viv_source_path.read_text()
|
||||||
|
|
||||||
|
for pkg in PACKAGES:
|
||||||
|
viv_source = pkg.insert(viv_source)
|
||||||
|
|
||||||
|
viv_source_path.write_text(viv_source)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -1 +1 @@
|
||||||
from .viv import __version__, use, main # noqa
|
from .viv import __version__, use, main, run # noqa
|
||||||
|
|
2311
src/viv/viv.py
2311
src/viv/viv.py
File diff suppressed because it is too large
Load diff
45
task
Executable file
45
task
Executable file
|
@ -0,0 +1,45 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# VERSION = $(git describe --tags --always --dirty=-dev | sed 's/^v//g')
|
||||||
|
|
||||||
|
function task:venv {
|
||||||
|
: "setup up pdm venv"
|
||||||
|
pdm install
|
||||||
|
}
|
||||||
|
|
||||||
|
function task:dev-install {
|
||||||
|
: "symlink development version"
|
||||||
|
mkdir -p ~/.local/share/viv
|
||||||
|
mkdir -p ~/.local/bin
|
||||||
|
ln -sf "$(pwd)/src/viv/viv.py" ~/.local/share/viv/viv.py
|
||||||
|
ln -sf ~/.local/share/viv/viv.py ~/.local/bin/viv
|
||||||
|
}
|
||||||
|
|
||||||
|
function task:_black {
|
||||||
|
: "generate black example shim"
|
||||||
|
rm -f examples/black
|
||||||
|
viv shim black -y -s -f -o examples/black
|
||||||
|
}
|
||||||
|
|
||||||
|
function task:clean {
|
||||||
|
: "clean build artifacts"
|
||||||
|
rm -rf build dist
|
||||||
|
}
|
||||||
|
|
||||||
|
function task:examples {
|
||||||
|
: "run examples to generate vivenvs"
|
||||||
|
examples="cli sys_path exe_specific frozen_import named_env scrape"
|
||||||
|
for f in $examples; do
|
||||||
|
python "examples/$f.py"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function task:_help-logo {
|
||||||
|
FORCE_COLOR=1 viv --help | yartsu -t 'viv --help' -w 70 -o assets/viv-help.svg
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- do-task boilerplate ----
|
||||||
|
function task:help { : "Show this help"; echo "do:";w=$(("$(compgen -A function | wc -L)" - 3));while read -r name; do [[ ! $name =~ ^task:_ ]] && [[ $name =~ ^task: ]] && paste <(printf '\033[1;32m%*s\033[0m\n' "$w" "${name#task:}") <(type "$name" | sed -nEe 's/^[[:space:]]*: ?"(.*)";/\1/p'); done < <(compgen -A function); }
|
||||||
|
while read -r name; do [[ $name == "task:$1" ]] && { shift; task="$name"; }; done < <(compgen -A function)
|
||||||
|
[[ -n "$1" && -z "$task" ]] && printf "\033[1;31m%s\033\0[m is not a task\n" "$1"
|
||||||
|
"${task:-task:help}" "$@" && exit "$?"
|
12
tests/conftest.py
Normal file
12
tests/conftest.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
cache = (Path(__file__).parent / ".viv-cache").absolute()
|
||||||
|
if cache.is_dir():
|
||||||
|
shutil.rmtree(cache)
|
||||||
|
|
||||||
|
# remove local settings
|
||||||
|
os.environ = {k: v for k, v in os.environ.items() if not k.startswith("VIV_")}
|
||||||
|
|
||||||
|
os.environ["VIV_CACHE"] = str(cache)
|
52
tests/test_readers.py
Normal file
52
tests/test_readers.py
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import pytest
|
||||||
|
from viv.viv import _read_metadata_block, _uses_viv, _Viv_Mode
|
||||||
|
|
||||||
|
RUN_METADATA_SCRIPT = """
|
||||||
|
#!/usr/bin/env -S viv run -s
|
||||||
|
# /// script
|
||||||
|
# requires-python = ">3.10"
|
||||||
|
# dependencies = [
|
||||||
|
# "rich"
|
||||||
|
# ]
|
||||||
|
# ///
|
||||||
|
"""
|
||||||
|
|
||||||
|
USE_SCRIPT = """
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
__import__("viv").use("rich")
|
||||||
|
|
||||||
|
from rich import print
|
||||||
|
print("pretty!")
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_metadata():
|
||||||
|
metadata = _read_metadata_block(RUN_METADATA_SCRIPT)
|
||||||
|
assert metadata == {"requires-python": ">3.10", "dependencies": ["rich"]}
|
||||||
|
|
||||||
|
|
||||||
|
def test_uses():
|
||||||
|
assert _uses_viv(RUN_METADATA_SCRIPT) == _Viv_Mode.NONE
|
||||||
|
assert (
|
||||||
|
_uses_viv(RUN_METADATA_SCRIPT + """\n__import__("viv").run()\n""")
|
||||||
|
== _Viv_Mode.RUN
|
||||||
|
)
|
||||||
|
assert _uses_viv(USE_SCRIPT) == _Viv_Mode.USE
|
||||||
|
assert _uses_viv("# from viv import use") == _Viv_Mode.NONE
|
||||||
|
|
||||||
|
|
||||||
|
def test_uses_fail(caplog):
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
_uses_viv("""__import__("viv").run()\n__import__("viv").use()""")
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
_uses_viv("""__import__("viv").unknown()""")
|
||||||
|
|
||||||
|
assert [
|
||||||
|
(
|
||||||
|
"viv",
|
||||||
|
40,
|
||||||
|
"Unexpected number of viv references in script.\n"
|
||||||
|
"Expected only 1, found: run, use",
|
||||||
|
),
|
||||||
|
("viv", 40, "Unknown function unknown associated with viv."),
|
||||||
|
] == caplog.record_tuples
|
17
tests/test_use.py
Normal file
17
tests/test_use.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from viv import use
|
||||||
|
|
||||||
|
|
||||||
|
def test_use():
|
||||||
|
with pytest.raises(ImportError):
|
||||||
|
import pyjokes # noqa
|
||||||
|
|
||||||
|
use("pyjokes")
|
||||||
|
import pyjokes # noqa
|
||||||
|
|
||||||
|
with pytest.raises(ImportError):
|
||||||
|
from sample.simple import add_one # noqa
|
||||||
|
|
||||||
|
assert len([p for p in sys.path if "site-packages" in p]) == 1
|
17
tests/test_vendored.py
Normal file
17
tests/test_vendored.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from viv.viv import SpecifierSet, Version, toml_loads
|
||||||
|
|
||||||
|
|
||||||
|
def test_packaging():
|
||||||
|
assert Version("3.6") in SpecifierSet(">=3.6")
|
||||||
|
|
||||||
|
|
||||||
|
def test_tomli():
|
||||||
|
assert {"requires-python": ">3.6", "dependencies": ["rich", "typer"]} == toml_loads(
|
||||||
|
"""
|
||||||
|
requires-python = ">3.6"
|
||||||
|
dependencies = [
|
||||||
|
"rich",
|
||||||
|
"typer"
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
)
|
Loading…
Reference in a new issue