{"id":23008406,"url":"https://github.com/liquidcarbon/puppy","last_synced_at":"2025-08-14T04:31:57.856Z","repository":{"id":230447714,"uuid":"779380371","full_name":"liquidcarbon/puppy","owner":"liquidcarbon","description":"Your new best friend.","archived":false,"fork":false,"pushed_at":"2024-04-05T15:26:14.000Z","size":52,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-04-05T22:22:57.949Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/liquidcarbon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-03-29T17:48:54.000Z","updated_at":"2024-04-14T22:23:31.078Z","dependencies_parsed_at":"2024-03-29T20:23:53.348Z","dependency_job_id":"9a48b400-db1b-486b-8b58-f863f4553ac8","html_url":"https://github.com/liquidcarbon/puppy","commit_stats":null,"previous_names":["liquidcarbon/puppy"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liquidcarbon%2Fpuppy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liquidcarbon%2Fpuppy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liquidcarbon%2Fpuppy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liquidcarbon%2Fpuppy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/liquidcarbon","download_url":"https://codeload.github.com/liquidcarbon/puppy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229800407,"owners_count":18126027,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-15T09:00:54.465Z","updated_at":"2025-08-14T04:31:57.833Z","avatar_url":"https://github.com/liquidcarbon.png","language":"Shell","funding_links":[],"categories":["Libraries"],"sub_categories":["Projects Using marimo"],"readme":"# Puppy\n\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/liquidcarbon/puppy)\n\nPuppy helps you set up and manage your python projects.  It's the easiest way to get started with modern python on any platform, install packages in virtual environments, and contribute to external projects.\n\n\u003cimg alt=\"Puppy Logo\" src=\"https://github.com/liquidcarbon/puppy/assets/47034358/da604ebd-4ce3-4e5d-b88b-ef46de7367fc\" width=\"270\"\u003e\n\n\n## Get started\n\n\nYou need only `curl` / `iwr` and an empty folder; pup will handle the rest, with a little help from its powerful friends [pixi](https://github.com/prefix-dev/pixi/) and [uv](https://github.com/astral-sh/uv).\n\n\n### Linux\n\n```bash\ncurl -fsSL https://pup-py-fetch.hf.space | bash\n```\n\n\n### Windows\n\n```powershell\niex (iwr https://pup-py-fetch.hf.space).Content\n```\n\n### One Installer To Rule Them All\n\n\u003e [!NOTE]\n\u003e This installer is hosted on HuggingFace.  It's been reliable for the last 8 months or so, but every now then it returns bits of broken HTML, in that case use `https://raw.githubusercontent.com/liquidcarbon/puppy/main/pup.sh` or `https://raw.githubusercontent.com/liquidcarbon/puppy/main/pup.ps1` instead.\n\n\nThe `pup-py-fetch` API accepts query parameters that allow specifying the exact environment recipe you want to build:\n  - `python`: [3.10](https://pup-py-fetch.hf.space?python=3.10) through [3.13](https://pup-py-fetch.hf.space?python=3.13)\n  - `pixi`: [comma-separated list of pixi/Conda dependencies](https://pup-py-fetch.hf.space?pixi=jupyter,quarto)\n  - `clone`: [comma-separated list of GitHub repos to clone and build in a virtual environment](https://pup-py-fetch.hf.space?clone=marimo-team/marimo) \n  - virtual environments: [all other query parameters with comma-separated package names](https://pup-py-fetch.hf.space?env1=duckdb,pandas\u0026env2=cowsay), including:\n    - regular PyPI packages (no support for version pinning at this time)\n    - packages from GitHub repos using `\u003cusername\u003e/\u003creponame\u003e` (only GitHub at this time; repo must contain must contain buildable `pyproject.toml` in its root)\n\n\u003e [!NOTE]\n\u003e As of Dec 2024, many packages still do not support python 3.13; thus, the default version in puppy is 3.12.\n\n\nThe URLs above return installation scripts.  You can mix and match query parameters, unlocking single-command recipes for complex builds:\n\n\n```bash\ncurl -fsSL \"https://pup-py-fetch.hf.space?pixi=marimo\u0026env1=duckdb,pandas\u0026env2=cowsay\" | bash\n```\n\n```powershell\niex (iwr \"https://pup-py-fetch.hf.space?python=3.11\u0026pixi=marimo\u0026tables=duckdb,pandas,polars\").Content\n```\n\nOr just grab the base build and use pup commands:\n\nhttps://github.com/user-attachments/assets/9cdd5173-5358-404a-84cc-f569da9972f8 \n\n\n## How It Works\n\nPuppy is a transparent wrapper around [pixi](https://github.com/prefix-dev/pixi/) and [uv](https://github.com/astral-sh/uv), two widely used Rust-based tools that belong together.\n\nPuppy can be used as a CLI in a Linux or Windows shell, or as a [module](#using-pup-as-a-module-pupfetch) in any python shell/script/[notebook](#puppy--environments-in-notebooks).\n\nInstalling puppy preps the folder to house python, in complete isolation from system or any other python on your system:\n\n0) 🐍 this folder is home to one and only one python executable, managed by pixi\n1) ✨ puppy installs pixi; pixi installs core components: python, uv, [click](https://github.com/pallets/click)\n2) ⚙ [Bash](https://github.com/liquidcarbon/puppy/blob/main/pup.sh) or [Powershell](https://github.com/liquidcarbon/puppy/blob/main/pup.ps1) runner/installer is placed into `~/.pixi/bin` (the only folder that goes on PATH)\n3) 🐶 `pup.py` is the python/click CLI that wraps pixi and uv commands\n4) 🟣 `pup new` and `pup add` use uv to handle projects, packages and virtual environments\n5) 📀 `pup clone` and `pup sync` help build environments from external `pyproject.toml` project files\n\n\n\n## Using `pup` as a Module: `pup.fetch`\n\nPup can help you construct and activate python projects interactively, such as from (i)python shells, jupyter notebooks, or [marimo notebooks](https://github.com/marimo-team/marimo/discussions/2994).\n\nPup scans for folders containing valid `pyproject.toml` and python executable inside `.venv` folder.  If a venv does not exist, pup can create it.\n\n```\na@a-Aon-L1:~/Desktop/puppy$ .pixi/envs/default/bin/python\nPython 3.12.7\n\u003e\u003e\u003e import pup; pup.fetch()\n[2024-10-26 16:50:37] 🐶 said: woof! run `pup.fetch()` to get started\n[2024-10-26 16:50:37] 🐶 virtual envs available: ['tbsky', 't1/web', 't2', 'tmpl', 'test-envs/e1']\nChoose venv to fetch: t1/web\n[2024-10-26 16:51:56] 🐶 heard: pup list t1/web\n{\n  \"t1/web\": [\n    \"httpx\u003e=0.27.2\",\n    \"requests\u003e=2.32.3\"\n  ]\n}\n[2024-10-26 16:51:56] fetched packages from 't1/web': /home/a/Desktop/puppy/t1/web/.venv/lib/python3.12/site-packages added to `sys.path`\n```\n\n\nNow the \"kernel\" `t1/web` is activated.  In other words, packages installed `t1/web/.venv` are available on `sys.path`.\n\n\u003e [!NOTE]\n\u003e Folders inside pup's home folder are scanned recursively, and nested paths are supported.  Symlinks are not followed.\n\nNeed to install more packages on the go, or create a new venv?  Just provide the destination, and list of packages.\n\n```python\npup.fetch(\"myenv\")                                 # activate existing environment\npup.fetch(\"myenv\", quiet=True)                     # activate quietly (output suppressed)\npup.fetch(\"myenv\", \"duckdb\", \"pandas\", \"pyarrow\")  # create/update venv, install packages, activate\n```\n\n\nHere is the signature of `pup.fetch()`:\n```python\ndef fetch(\n    venv: str | None = None,\n    *packages: Optional[str],\n    site_packages: bool = True,\n    root: bool = False,\n    quiet: bool = False,\n) -\u003e None:\n    \"\"\"Create, modify, or fetch (activate) existing venvs.\n\n    Activating an environment means placing its site-packages folder on `sys.path`,\n    allowing to import the modules that are installed in that venv.\n\n    `venv`: folder containing `pyproject.toml` and installed packages in `.venv`\n        if venv does not exist, puppy will create it, install *packages,\n        and fetch newly created venv\n    `*packages`: names of packages to `pup add`\n    `site_packages`: if True, appends venv's site-packages to `sys.path`\n    `root`: if True, appends venv's root folder to `sys.path`\n        (useful for packages under development)\n    `quiet`: suppress output\n    \"\"\"\n```\n\nWith `root=True`, you also add new project's root folder to your environment, making its modules available for import.\nThis is useful for working with projects that themselves aren't yet packaged and built.\nYou also have the option to omit the site-packages folder with `site_packages=False`.\n\n```\npixi run python\nPython 3.12.7 | packaged by conda-forge | (main, Oct  4 2024, 16:05:46) [GCC 13.3.0] on linux\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n\u003e\u003e\u003e import pup; pup.fetch(\"test-only-root\", root=True, site_packages=False)\n[2024-11-22 13:10:49] 🐶 said: woof! run `pup.fetch()` to get started\n[2024-11-22 13:10:49] 🐶 virtual envs available: ['gr']\n[2024-11-22 13:10:49] 🐶 heard: pup new test-only-root\n[2024-11-22 13:10:49] 🐶 said: pixi run uv init /home/a/puppy/test-only-root -p /home/a/puppy/.pixi/envs/default/bin/python --no-workspace\nInitialized project `test-only-root` at `/home/a/puppy/test-only-root`\n[2024-11-22 13:10:49] 🐶 said: pixi run uv venv /home/a/puppy/test-only-root/.venv -p /home/a/puppy/.pixi/envs/default/bin/python\nUsing CPython 3.12.7 interpreter at: .pixi/envs/default/bin/python\nCreating virtual environment at: test-only-root/.venv\nActivate with: source test-only-root/.venv/bin/activate\nSpecify what to install:\n[2024-11-22 13:10:50] 🐶 virtual envs available: ['gr', 'test-only-root']\n[2024-11-22 13:10:50] fetched packages from 'test-only-root': /home/a/puppy/test-only-root added to `sys.path`\n[2024-11-22 13:10:50] 🐶 heard: pup list test-only-root\n{\n  \"test-only-root\": []\n}\n\u003e\u003e\u003e import hello; hello.main()  # `hello.py` is included in uv's project template\nHello from test-only-root!\n```\n\n## Puppy \u0026 Environments in Notebooks\n\n\u003e [!NOTE]\n\u003e Conda or PyPI packages installed with `pixi add ...` always remain on `sys.path` and stay available across all environments.  Though one could exclude them, I have yet to find a reason to do so.\n\n### Jupyter\n\nThere's a good chance you're confused about how Jupyter kernels work and find setting up kernels with virtual environments too complicated to bother.  Puppy's [v1](https://github.com/liquidcarbon/puppy/tree/v1) was addressing that problem, but in v2 (current version) this is taken care of by `pup.fetch`.  Here's the gist:\n\n1) install ONE instance of jupyter with `pixi add jupyter` per major version of python\n2) run it with `pixi run jupyter lab` or `pixi run jupyter notebook`\n3) use `pup.fetch` to build and activate your environment - THAT'S IT!\n\nFor details, scan through the [previous section](#using-pup-as-a-module-pupfetch).  In brief, `pup.fetch` creates/modifies and/or activates your venv by appending its folder to `sys.path`.  This is pretty very similar to how venvs and kernels work. A jupyter kernel is a pointer to a python executable.  Within a venv, the executable `.venv/bin/python` is just a symlink to the parent python - in our case, to pixi's python.  The activation and separation of packages is achieved by manipulating `sys.path` to include local `site-packages` folder(s).\n\n\n### Marimo\n\nWith marimo, you have more options: [Unified environment management for any computational notebooks](https://github.com/marimo-team/marimo/discussions/2994) - no more Jupyter kernels!\n\n\n## Where Pixi Shines 🎇\n\nUV is rightfully getting much love in the community, but Pixi is indispensable for:\n\n1. Conda channels support\n2. Setting up really complex build environments for multi-language projects.  For example, try pulling together what's done here in one API call (python, NodeJS, pnpm, cloned and synced repo): \n\\\n\\\n\u003cimg alt=\"Pixi build with python, Node, pnpm, and cloned repos\" src=\"https://github.com/user-attachments/assets/b372b1a5-c3d6-415c-acb2-cc65d1f90572\" width=\"480\"\u003e\n\n\n## Multi-Puppy-Verse\n\nCan I have multiple puppies?  As many as you want!  Puppy is not just a package installer, but also a system to organize multiple python projects.\n\nA pup/py home is defined by one and only one python executable, which is managed by pixi, along with tools like uv, jupyter, hatch, pytest, and conda-managed packages. We use home-specific tools through a pixi shell from anywhere within the folder, e.g. `pixi run python`, `pixi run jupyter`, or, to be explicit, by calling their absolute paths.\n\n\u003e [!NOTE]\n\u003e If you need a \"kernel\" with a different version of python, install puppy in a new folder.  **Puppy's folders are completely isolated from each other and any other python installation on your system.**  Remember, one puppy folder = one python executable, managed by Pixi.  Pup commands work the same from anywhere within a pup folder, run relative to its root, via `.pixi/envs/default/bin/python`.  Place puppy folders side-by-side, not within other puppy folders - nested puppies might misbehave.\n\n```\n# ├── puphome/  # python 3.12 lives here\n# │   ├── public-project/\n# │   │   ├── .git  # this folder may be a git repo (see pup clone)\n# │   │   ├── .venv\n# │   │   └── pyproject.toml\n# │   ├── env2/\n# │   │   ├── .venv/  # this one is in pre-git development\n# │   │   └── pyproject.toml\n# │   ├── pixi.toml\n# │   └── pup.py\n# ├── pup311torch/  # python 3.11 here\n# │   ├── env3/\n# │   ├── env4/\n# │   ├── pixi.toml\n# │   └── pup.py\n# └── pup313beta/  # 3.13 here\n#     ├── env5/\n#     ├── pixi.toml\n#     └── pup.py\n```\n\nThe blueprint for a pup/py home is in `pixi.toml`; at this level, git is usually not needed.  The inner folders are git-ready project environments managed by pup and uv.  In each of the inner folders, there is a classic `.venv` folder and a `pyproject.toml` file populated by uv.  When you run `pup list`, pup scans this folder structure and looks inside each `pyproject.toml`.  The whole setup is very easy to [containerize](examples/) (command to generate `Dockerfile` coming soon!).\n\n\u003e [!TIP]\n\u003e Use `pup list -f` to list all dependencies spelled out in `uv.lock`.\n\n## But Why\n\nPython packages, virtual environments, notebooks, and how they all play together remains a confusing and controversial topic in the python world.\n\nThe problems began when the best idea from the Zen of python was ignored by pip:\n\n```\n~$ python -c 'import this'\nThe Zen of Python, by Tim Peters\n\n...\nExplicit is better than implicit.\n...\n\n~$ pip install numpy\nCollecting numpy\n  Downloading numpy-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (60 kB)\nDownloading numpy-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (16.3 MB)\n   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 16.3/16.3 MB 62.5 MB/s eta 0:00:00\nInstalling collected packages: numpy\nSuccessfully installed numpy-2.1.2\n```\n\nThe command worked, yay! Antigravity!  But *which* pip did the work and *where* did the packages go?\n\n![confused Travolta](https://i.kym-cdn.com/photos/images/newsfeed/001/042/619/4ea.jpg)\n\nMost tools that came later followed the same pattern.\n\nPuppy makes implicitly sensible choices while being explicitly transparent.  Compare:\n\n```\nPS C:\\Users\\a\\Desktop\\code\\puppy\u003e pup add try-ml numpy\n[2024-10-13 00:02:19] 🐶 heard: pup new try-ml\n[2024-10-13 00:02:19] 🐶 said: pixi run uv init C:\\Users\\a\\Desktop\\code\\puppy\\try-ml -p C:\\Users\\a\\Desktop\\code\\puppy\\.pixi\\envs\\default\\python.exe --no-workspace\nInitialized project `try-ml` at `C:\\Users\\a\\Desktop\\code\\puppy\\try-ml`\n[2024-10-13 00:02:20] 🐶 said: pixi run uv venv C:\\Users\\a\\Desktop\\code\\puppy\\try-ml/.venv -p C:\\Users\\a\\Desktop\\code\\puppy\\.pixi\\envs\\default\\python.exe\nUsing CPython 3.12.7 interpreter at: .pixi\\envs\\default\\python.exe\nCreating virtual environment at: try-ml/.venv\nActivate with: try-ml\\.venv\\Scripts\\activate\n[2024-10-13 00:02:21] 🐶 heard: pup add try-ml numpy\n[2024-10-13 00:02:21] 🐶 said: pixi run uv add numpy --project C:\\Users\\a\\Desktop\\code\\puppy\\try-ml\nResolved 2 packages in 87ms\nInstalled 1 package in 344ms\n + numpy==2.1.2\n```\n\nThen came Jupyter notebooks, a wonderful tool that unlocked the floodgates of interest to python.  But the whole `import` thing remained a confusing mess.\n\n(to be continued) [[Medium article](https://medium.com/pythoneers/puppy-pythons-best-friend-c03578d9b491)]\n\n## Future\n\n- `pup swim` (build Dockerfiles)\n- you tell me?\n\n## Past\n\n- [v0](https://github.com/liquidcarbon/puppy/tree/b474b1cd6c63b9fc80db5d81f954536a58aeab2a) was a big Bash script\n- [v1](https://github.com/liquidcarbon/puppy/tree/v1) remains a functional CLI with `pup play` focused on Jupyter kernels\n\n## Built with Puppy\n\nSee [examples](examples/README.md).\n\n## Support\n\nThanks for checking out this repo.  Hope you try it out and like it!  Feedback, discussion, and ⭐s are welcome!\n\n```\n┌──────────────────────────────────────────────────────────────────────────────┐\n│  ~===========@     \u003e\u003e\u003e                                              .-.      │\n|                      \u003e\u003e\u003e               (___________________________()6 `-,   |\n│     %%%%%%%%%%%%%%%     \u003e\u003e\u003e            (   ______________________   /''\"`    │\n│     %site_packages%       \u003e\u003e\u003e          //\\\\                      //\\\\        |\n│     %%%%%%%%%%%%%%%                                                          |\n│                              !!!!!!!!!!!!!!!!!!!!!          +++++            │\n│  *******                     !ModuleNotFoundError!                           │\n│  *.venv*      \"\"\"            !!!!!!!!!!!!!!!!!!!!!      ~~~~~~~~~~~~~~       │\n│  *******              ../..                             ~ (base) :~$ ~       │\n│               \"\"\"              [================]       ~~~~~~~~~~~~~~       │\n│ @                     +        [ pyproject.toml ]                            │\n│  @ $$$$$$$$$$$$$$$$$  +        [================]                            │\n│ @  $ Collecting    $  +++                                         +  +       │\n│  @ $   Downloading $  +                                            +  +      │\n│    $$$$$$$$$$$$$$$$$  +++           #########################       +  +     │\n│                       + +           # \u003e\u003e\u003e from bla import * #        +  +    │\n│  @ \u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026    + +++         #########################         +  +   │\n│ @  \u0026 dist        \u0026    + +                                            +  +    │\n│  @ \u0026 ├───.tar.gz \u0026    + +++   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!        +  +     │\n│ @  \u0026 └───.whl    \u0026    +       !ERROR: ResolutionImpossible:!       +  +      │\n│  @ \u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026\u0026    +++++   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!      +  +       │\n│                                                                              │\n└──────────────────────────────────────────────────────────────────────────────┘\n  Eat fruits and vegetables.  Don't run into walls.  Don't eat your own tail.\n\n  ASCII dog by Joan Stark, the rest by author\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliquidcarbon%2Fpuppy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliquidcarbon%2Fpuppy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliquidcarbon%2Fpuppy/lists"}