diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index f56b85a..855fdea 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -12,6 +12,11 @@ "name": "gitea-tea", "source": "./plugins/gitea-tea", "description": "Gitea über die tea-CLI verwalten: Issues, PRs, Releases, Repos vom Terminal." + }, + { + "name": "uv", + "source": "./plugins/uv", + "description": "uv statt pip/python/venv: Skripte mit uv run, Deps mit uv add, inline Script-Metadata für Standalone-Skripte." } ] } diff --git a/plugins/uv/.claude-plugin/plugin.json b/plugins/uv/.claude-plugin/plugin.json new file mode 100644 index 0000000..7b6be2e --- /dev/null +++ b/plugins/uv/.claude-plugin/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "uv", + "version": "0.1.0", + "description": "uv statt pip/python/venv: Skripte mit uv run, Deps mit uv add, inline Script-Metadata für Standalone-Skripte.", + "author": { + "name": "inmedias.it" + } +} diff --git a/plugins/uv/skills/uv/SKILL.md b/plugins/uv/skills/uv/SKILL.md new file mode 100644 index 0000000..1026426 --- /dev/null +++ b/plugins/uv/skills/uv/SKILL.md @@ -0,0 +1,37 @@ +--- +name: uv +description: "Use `uv` instead of pip/python/venv. Run scripts with `uv run script.py`, add deps with `uv add`, use inline script metadata for standalone scripts." +--- + +## Quick Reference + +```bash +uv run script.py # Run a script +uv run --with requests script.py # Run with ad-hoc dependency +uv run python -m ast foo.py >/dev/null # Verify syntax without writing __pycache__ +uv add requests # Add dependency to project +uv init --script foo.py # Create script with inline metadata +``` + +## Inline Script Dependencies + +```python +# /// script +# requires-python = ">=3.12" +# dependencies = ["requests"] +# /// +``` + +See [scripts.md](scripts.md) for full details on running scripts, locking, and reproducibility. + +## Build Backend + +Use `uv_build` for pure Python packages: + +```toml +[build-system] +requires = ["uv_build>=0.9.28,<0.10.0"] +build-backend = "uv_build" +``` + +See [build.md](build.md) for project structure, namespaces, and file inclusion. diff --git a/plugins/uv/skills/uv/build.md b/plugins/uv/skills/uv/build.md new file mode 100644 index 0000000..0801b5a --- /dev/null +++ b/plugins/uv/skills/uv/build.md @@ -0,0 +1,65 @@ +# uv Build Backend + +Use `uv_build` for pure Python packages. For extension modules, use `hatchling` instead. + +## pyproject.toml + +```toml +[project] +name = "my-package" +version = "0.1.0" +requires-python = ">=3.12" +dependencies = [] + +[build-system] +requires = ["uv_build>=0.9.28,<0.10.0"] +build-backend = "uv_build" +``` + +## Project Structure + +Default layout uses `src//__init__.py`: + +``` +pyproject.toml +src/ +└── my_package/ + └── __init__.py +``` + +Package name is normalized: `Foo-Bar` → `foo_bar`. + +### Custom Module Location + +```toml +[tool.uv.build-backend] +module-name = "mymodule" +module-root = "" # Use project root instead of src/ +``` + +### Namespace Packages + +For `foo.bar` namespace: + +``` +src/foo/bar/__init__.py # No __init__.py in foo/ +``` + +```toml +[tool.uv.build-backend] +module-name = "foo.bar" +``` + +## File Inclusion/Exclusion + +Excludes `__pycache__`, `*.pyc`, `*.pyo` by default. + +```toml +[tool.uv.build-backend] +source-include = ["assets/**"] +source-exclude = ["/dist", "tests/**"] +``` + +- Includes are anchored (`pyproject.toml` = only root) +- Excludes are not anchored (`__pycache__` = all dirs named that) +- Use `/prefix` to anchor excludes diff --git a/plugins/uv/skills/uv/scripts.md b/plugins/uv/skills/uv/scripts.md new file mode 100644 index 0000000..23e76cc --- /dev/null +++ b/plugins/uv/skills/uv/scripts.md @@ -0,0 +1,106 @@ +# Running Scripts with uv + +## Basic Usage + +```bash +uv run script.py # Run a script +uv run script.py arg1 arg2 # With arguments +uv run --python 3.10 script.py # Specific Python version +echo 'print("hi")' | uv run - # From stdin +``` + +In a project directory, use `--no-project` to skip installing the project: + +```bash +uv run --no-project script.py +``` + +## Syntax Verification (No `__pycache__`) + +Use the AST parser instead of `python -m py_compile`: + +```bash +uv run python -m ast script.py >/dev/null +``` + +## Ad-hoc Dependencies + +```bash +uv run --with requests script.py +uv run --with 'requests>2,<3' script.py +uv run --with requests --with rich script.py +``` + +## Inline Script Metadata (Recommended) + +Declare dependencies directly in the script: + +```python +# /// script +# requires-python = ">=3.12" +# dependencies = [ +# "requests<3", +# "rich", +# ] +# /// + +import requests +from rich import print +``` + +Then just: `uv run script.py` + +### Managing Dependencies + +```bash +uv init --script example.py --python 3.12 # Create script with metadata +uv add --script example.py requests rich # Add dependencies +``` + +### Alternative Index + +```bash +uv add --index "https://example.com/simple" --script example.py requests +``` + +Adds to metadata: + +```python +# [[tool.uv.index]] +# url = "https://example.com/simple" +``` + +## Locking Dependencies + +```bash +uv lock --script example.py # Creates example.py.lock +``` + +## Reproducibility + +Pin resolution date: + +```python +# /// script +# dependencies = ["requests"] +# [tool.uv] +# exclude-newer = "2023-10-16T00:00:00Z" +# /// +``` + +## Executable Scripts (Shebang) + +```python +#!/usr/bin/env -S uv run --script +# /// script +# dependencies = ["httpx"] +# /// + +import httpx +print(httpx.get("https://example.com")) +``` + +```bash +chmod +x myscript +./myscript +```