Programming on J. Fernando Sánchezhttps://balkian.com/categories/programming/Recent content in Programming on J. Fernando SánchezHugo -- gohugo.ioen-usMon, 17 Feb 2025 23:02:47 +0100uv - One rust tool to rule all pythonshttps://balkian.com/p/uv-one-rust-tool-to-rule-all-pythons/Mon, 17 Feb 2025 23:02:47 +0100https://balkian.com/p/uv-one-rust-tool-to-rule-all-pythons/<img src="https://balkian.com/img/uv.png" alt="Featured image of post uv - One rust tool to rule all pythons" /><p>Long story short: I&rsquo;m now using <a class="link" href="https://github.com/astral-sh/uv" target="_blank" rel="noopener" >uv</a>, and so should you. It is a great replacement for pip, pip-tools, pipx, poetry, pyenv, twine, virtualenv, and more.</p> <h2 id="context">Context </h2><p>For years, my strategy to manage python projects has been a mix of a custom <code>setup.py</code>, several hand-crafted <code>requirements.txt</code> files (through <code>pip freeze</code>), a custom virtualenv per project, and multiple tools to upload to PyPI. Although this works, this setup has many drawbacks:</p> <ul> <li>It requires user intervention (creating a venv, sourcing it, handling new deps). This isn&rsquo;t ideal if you want new (probably inexperienced) users to use your projects.</li> <li>On a similar note, the whole process needs to be well documented if you want other users to contribute or maintain the code.</li> <li>Pinning dependency versions is finicky, and I&rsquo;ve run into problems beause of that.</li> <li>Creating a new project involves a template, or copying files from an older project.</li> </ul> <p>Of course, this is nothing new. There is a whole site dedicated to <a class="link" href="https://packaging.python.org/en/latest/" target="_blank" rel="noopener" >packaging your Python project</a>. A plethora of different projects have come and go, with varying degrees of success.</p> <h2 id="alternatives-poetry">Alternatives (poetry) </h2><p>About a year before trying <code>uv</code>, I tried to catch up with the ecosystem and get to know the <code>blessed new way</code>. However, the task proved to be a little more difficult, as the landscape is filled with a myriad of alternatives, each with their own set of drawbacks and detractors. Packaging has historically been a weak spot, in ironical contradiction to the Zen of Python&rsquo;s &ldquo;There should be one&ndash; and preferably only one &ndash;obvious way to do it&rdquo;,</p> <p>I eventually settled on <a class="link" href="https://python-poetry.org/" target="_blank" rel="noopener" >poetry</a>. Mostly because it seemed like the most popular alternative.</p> <p>There are many things I liked about it. First of all, having a convention for dependencies (<code>pyproject.toml</code>) and a tool that properly handles them was nice. It also removed the need to remember specific incantations to build and publish my Python projects. Lastly, I mixed it <code>poetry2nix</code> to create reproducible python environments using nix. This makes for a very powerful experience.</p> <p>However, there were multiple hiccups. First of all, it took me some time to figure out which specific fields to use (each tool can define ad-hoc properties in a the <code>pyproject.toml</code> file), and some of them seemed redundant with the more generic ones. Full disclosure, this specific point might be a mistake on my side, and I do not remember the details. The second one is speed. (Re-)creating an environment took a non-negligible amount of time.</p> <h2 id="enter-light-uv">Enter <del>light</del> <code>uv</code> </h2><p>According to its repository, <code>uv </code>can replace pip, pip-tools, pipx, poetry, pyenv, twine, virtualenv, and more. Not only that, but it also claims to do that 10-100 times faster than pip. I must admit that it being written in rust was a another selling point for me, as I&rsquo;m looking for excuses to collaborate in a decently-sized rust projejct.</p> <p>Installing it is dead simple: simply download the binary (e.g., with curl) or run <code>pip install uv</code>. You won&rsquo;t need much more: <code>uv</code> seems to just do the right thing out of the box. And it does it really, really fast. The rest of the time it gets out of the way.</p> <p>My only gripe so far is that I don&rsquo;t seem to find a built-in command to drop into a shell, but that is nothing that <code>uv run $SHELL</code> cannot fix.</p> <h2 id="common-operations">Common operations </h2><h3 id="initialize-a-repository">Initialize a repository </h3><div class="highlight"><div class="chroma"> <table class="lntable"><tr><td class="lntd"> <pre tabindex="0" class="chroma"><code><span class="lnt">1 </span></code></pre></td> <td class="lntd"> <pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">uv init </span></span></code></pre></td></tr></table> </div> </div><h3 id="adding-dependencies">Adding dependencies </h3><div class="highlight"><div class="chroma"> <table class="lntable"><tr><td class="lntd"> <pre tabindex="0" class="chroma"><code><span class="lnt">1 </span></code></pre></td> <td class="lntd"> <pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">uv add senpy </span></span></code></pre></td></tr></table> </div> </div><h3 id="running-commands-inside-the-environment">Running commands inside the environment </h3><div class="highlight"><div class="chroma"> <table class="lntable"><tr><td class="lntd"> <pre tabindex="0" class="chroma"><code><span class="lnt">1 </span><span class="lnt">2 </span><span class="lnt">3 </span><span class="lnt">4 </span></code></pre></td> <td class="lntd"> <pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">uv run &lt;COMMAND&gt; </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl"># e.g., run a shell using your python version and dependencies </span></span><span class="line"><span class="cl">uv run $SHELL </span></span></code></pre></td></tr></table> </div> </div><h3 id="dependency-tree">Dependency tree </h3><div class="highlight"><div class="chroma"> <table class="lntable"><tr><td class="lntd"> <pre tabindex="0" class="chroma"><code><span class="lnt"> 1 </span><span class="lnt"> 2 </span><span class="lnt"> 3 </span><span class="lnt"> 4 </span><span class="lnt"> 5 </span><span class="lnt"> 6 </span><span class="lnt"> 7 </span><span class="lnt"> 8 </span><span class="lnt"> 9 </span><span class="lnt">10 </span><span class="lnt">11 </span><span class="lnt">12 </span><span class="lnt">13 </span><span class="lnt">14 </span><span class="lnt">15 </span><span class="lnt">16 </span><span class="lnt">17 </span><span class="lnt">18 </span><span class="lnt">19 </span></code></pre></td> <td class="lntd"> <pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">uv shell </span></span><span class="line"><span class="cl">Resolved 44 packages in 1ms </span></span><span class="line"><span class="cl">my-project v0.1.0 </span></span><span class="line"><span class="cl">├── fastapi[standard] v0.115.8 </span></span><span class="line"><span class="cl">│ ├── pydantic v2.10.6 </span></span><span class="line"><span class="cl">│ │ ├── annotated-types v0.7.0 </span></span><span class="line"><span class="cl">│ │ ├── pydantic-core v2.27.2 </span></span><span class="line"><span class="cl">│ │ │ └── typing-extensions v4.12.2 </span></span><span class="line"><span class="cl">│ │ └── typing-extensions v4.12.2 </span></span><span class="line"><span class="cl">│ ├── starlette v0.45.3 </span></span><span class="line"><span class="cl">│ │ └── anyio v4.8.0 </span></span><span class="line"><span class="cl">│ │ ├── exceptiongroup v1.2.2 </span></span><span class="line"><span class="cl">│ │ ├── idna v3.10 </span></span><span class="line"><span class="cl">│ │ ├── sniffio v1.3.1 </span></span><span class="line"><span class="cl">│ │ └── typing-extensions v4.12.2 </span></span><span class="line"><span class="cl">│ ├── typing-extensions v4.12.2 </span></span><span class="line"><span class="cl">│ ├── email-validator v2.2.0 (extra: standard) </span></span><span class="line"><span class="cl">│ │ ├── dnspython v2.7.0 </span></span><span class="line"><span class="cl">... </span></span></code></pre></td></tr></table> </div> </div>Pythonhttps://balkian.com/python/Mon, 01 Jan 0001 00:00:00 +0000https://balkian.com/python/<img src="https://balkian.com/img/python.png" alt="Featured image of post Python" /><h2 id="interesting-libraries">Interesting libraries </h2><h3 id="tqdm"><a class="link" href="https://github.com/tqdm/tqdm" target="_blank" rel="noopener" >TQDM</a> </h3><p>From tqdm&rsquo;s github repository:</p> <blockquote> <p>tqdm means &ldquo;progress&rdquo; in Arabic (taqadum, تقدّم) and an abbreviation for &ldquo;I love you so much&rdquo; in Spanish (te quiero demasiado).</p></blockquote> <p><img src="https://raw.githubusercontent.com/tqdm/tqdm/master/images/tqdm.gif" loading="lazy" alt="TQDM in action" ></p> <h2 id="tools">Tools </h2><h3 id="uv"><a class="link" href="https://github.com/astral-sh/uv" target="_blank" rel="noopener" >uv</a> </h3><p>🚀 A single tool to replace pip, pip-tools, pipx, poetry, pyenv, twine, virtualenv, and more. ⚡️ 10-100x faster than pip.</p> <ul> <li>Provides comprehensive project management, with a universal lockfile.</li> <li>Runs scripts, with support for inline dependency metadata.</li> <li>Installs and manages Python versions.</li> <li>Runs and installs tools published as Python packages.</li> <li>Includes a pip-compatible interface for a performance boost with a familiar CLI.</li> <li>Supports Cargo-style workspaces for scalable projects.</li> <li>Disk-space efficient, with a global cache for dependency deduplication.</li> <li>Installable without Rust or Python via curl or pip.</li> <li>Supports macOS, Linux, and Windows.</li> </ul>