Lo-Fi Python

Feb 16, 2024

Make Your Python Installs Faster With uv

For several years, pip and pip-tools have become distinguished in Python packaging for their usability and ubiquity. Recently there has been some interesting new developments in the realm of Python packaging tools. In a trend that started around 2022, there has been an ongoing "Rustification" of Python tooling.

uv is designed as a drop-in replacement for pip and pip-tools, and is ready for production use today in projects built around those workflows.

- Charlie Marsh, "uv: Python Packaging in Rust", https://astral.sh/blog/uv

First, Rye was released in pursuit of a "cargo for Python". Cargo is Rust's package manager. It seems to have inspired Python developers to keep trying to improve on what we have with pip.

While this was happening, in secret Astral Software and Charlie Marsh were also working on yet another hybrid Rust + Python package manager named uv. There's seemingly no end to this man and the Astral team's projects! ruff quickly supplanted the incumbent Python linters to become a favorite among Python developers. Could lightning strike twice for the creators of ruff? Seems they won't be a one-hit wonder when it comes to developing hit Python packages.

Improving Python packaging is an audacious and challenging task. Part of the problem is that out of the box Python installs can be tough to reason about for new Python developers, not to mention the hassle of explaining the purpose of virtual environments in Python coding via venv. One perk of uv is that it includes virtual environments in its workflow.

uv is 8-10x faster than pip and pip-tools without caching, and 80-115x faster when running with a warm cache

- Charlie Marsh, "uv: Python Packaging in Rust", https://astral.sh/blog/uv

A new space of potential optimization is now accessible to Python developers. We can now use uv to make our development environment build faster. A modest 8x speedup in Python library installs might shave off a shocking amount of time it takes your freshly minted Docker image to build, especially if you have lots of Python library dependencies. Now, imagine an 80-115x speedup with caching. Docker images also use caching after an image is built the first time. They are an optimization use case along with building your development environment in general. In some development shops, this could cut a lot of time installing developer tooling. It's a potential incredible improvement we can now make with uv!

optimizing code with uv tweet

In the case of Rye and uv, two developers simultaneously identified the same opportunity and are now combining their efforts. Sounds like a win for all Python developers. Armin Ronacher, the creator of the Flask web framework and Charlie Marsch with the proven success of ruff are converging to tackle one of Python's biggest pain points. They could be merged into a "cargo for Python" super tool eventually:

Will Rye be retired for uv? Not today, but the desire is that these tools eventually converge into one.

- Armin Ronacher, "Rye Grows with uv", https://lucumr.pocoo.org/2024/2/15/rye-grows-with-uv/

Per Armin's recent blog post, Rye is probably not the final solution. He thinks Rye will get absorbed into a more fleshed out project like uv. It seems Python packaging will continue evolving and improving, a welcome sight for Pythonistas!

optimize Python installs with uv

Image Source: "uv: Python Packaging in Rust", https://astral.sh/blog/uv

Install uv and rye

pip install uv
pip install rye

# Alternative install for uv with curl
curl -LsSf https://astral.sh/uv/install.sh | sh
# Alternative Install for rye on Linux and Mac
curl -sSf https://rye-up.com/get | bash

Create a Virtual Environment With uv

uv venv  # Create a virtual environment at .venv.
# Activate venv on macOS and Linux.
source .venv/bin/activate

Installing a New Module With uv

uv pip install requests

pip sync a requirements.txt file with uv

uv pip sync requirements.txt  # Install from a requirements.txt file.

Optional: Configure Rye on Top of uv

rye config --set-bool behavior.use-uv=true

Create a New Python project With Rye

rye init my-project
rye pin 3.10
rye add black
rye sync
rye run black

uv and rye Documentation and Blog Links

uv: Python Packaging in Rust

uv Github Repo

Rye Grows with uv

Rye User Guide

Aug 13, 2023

How to Install Python 3.11 or 3.12 on a Linux Computer

Below are the steps I followed to install both Python 3.11 and Python 3.12 in my Ubuntu Linux shell. Make sure to adjust your Python version to match 3.11 or 3.12 in all commands.

I downloaded the .tgz file from Python.org, not sure initially how to build Python from it. Once I unpacked the compressed files, I saw the build instructions in the README.rst to build a functional Python 3.11 on my Ubuntu computer. Here's how to install the speedier Python versions 3.11 or 3.12.

How to Install Python 3.11 or 3.12

Install Linux build libraries.

I followed this step posted on this blog. If you don't do this, you'll likely see an error about C not being found when running the ./configure command.

sudo apt install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev

Install sqllite Libraries (Django Requirement)

If you wish to make a Django website, install sqllite libraries before you build Python.

sudo apt install sqlite3 libsqlite3-dev

Use curl to download the Python gzip file.

curl https://www.python.org/ftp/python/3.11.0/Python-3.11.0.tgz --output Python-3.11.0.tgz
download Python with curl

Unpack gzip file to folder.

tar -xvzf Python-3.11.0.tgz

Change directory, read the README + find build commands.

cd Python-3.11.0
cat README.rst

Build Python.

# Build Python on Unix, Linux, BSD, macOS, and Cygwin:
./configure --enable-optimizations
make
make test
sudo make install

Building Python on Various Platforms

This will install Python as python3.

You can pass many options to the configure script; run ./configure --help to find out more. On macOS case-insensitive file systems and on Cygwin, the executable is called python.exe; elsewhere it's just python.

Building a complete Python installation requires the use of various additional third-party libraries, depending on your build platform and configure options. Not all standard library modules are buildable or useable on all platforms. Refer to the Install dependencies section of the Developer Guide for current detailed information on dependencies for various Linux distributions and macOS.

On macOS, there are additional configure and build options related to macOS framework and universal builds. Refer to Mac/README.rst.

On Windows, see PCbuild/readme.txt.

- Python 3.11 Linux README.rst

Sep 15, 2022

Retrieve Random Numbers Via Python's random Module + range() Built-in

There are usually many ways to do most things in Python. I've retrieved random numbers a few different ways at various times within the random module, often after reading a Stack Overflow post. This time in my most recent search for random digits, I discovered in the Python docs the random.sample() function with its k parameter:

Return a k length list of unique elements chosen from the population sequence or set. Used for random sampling without replacement.

https://docs.python.org/3/library/random.html#random.sample

When combined with the range() built-in, it makes doing this easy. Being able to specify a length and return a list of random numbers is mighty convenient. This function seems a Pythonic way to randomize to me. Have a look!

1
2
3
4
5
6
7
import random
# Returns a list of 5 random numbers.
numbers = random.sample(range(10000000), k=5)
print(numbers)
# Returns a single random number.
number = random.sample(10000000), k=1)[0]
print(number)
Python Random Number Code

To choose a sample from a range of integers, use a range() object as an argument.

"This is especially fast and space efficient for sampling from a large population":

1
sample(range(10000000), k=60)

- Python Docs, https://docs.python.org/3/library/random.html#random.sample

Sep 23, 2021

What I Learned from Black, Python's "Uncompromising" Code Formatter

Black is a code formatting tool that I have been testing out recently to see what the hype is about. It is the defacto "uncompromising code formatter in Python". I normally do not use any code formatters since I'm not required to use them. This short post aims to convince you that Black is an insightful way to see the parts of your code that are dangerously unreadable.

I have found it interesting to see what black does with my gnarliest code. It has taught me what is considered "good formatting" by some Pythonistas. The areas where I see the most improvement is how it enforces PEP-8's characters per line limit. Often before, I didn't know how to break my code into several lines. My scripts tended to have one-liners trailing off the edge of my text editor. Black teaches you new ways to organize your code and makes it easier to understand. Now I write my code like Black the first time instead of letting it trail off the screen.

Initially I was hesitant to try Black because I didn't want to sabotage my own code style. But since running Black on a few of my scripts, it has taught me new ways to write code. Give Black a chance and you will learn how to write more readable Python.

Here's the project on GitHub: https://github.com/psf/black

Sep 13, 2020

Delete All Your Tweets with Tweepy and the Twitter API

You may want to download an archive of your tweets before deleting them. I did this and it took about a day to get my archive download.

How To Purge Your Tweet History with Python

  1. Per the Tweepy library documentation, install tweepy with pip. It worked fine in my python 3.8 virtual environment.
pip install tweepy
  1. Sign up for a Twitter Developer account and create an app. I named mine "tweetcleanr".
  2. Find your app under "Projects & Apps". Edit your app's permissions to "Read + Write + Direct Messages".
  3. After you update your permissions, select the "Keys and tokens" tab. Then regenerate new API keys. Then paste them in the below script.
Twitter Dev UX
  1. Save the below script as a python file. In command prompt or terminal, run python delete_tweets.py or whatever you want to name it!
  2. You'll be asked to go to a link and enter an authorization code. Then you'll see your tweets being deleted like pictured below.

delete_tweets.py

I found this Github Gist via Google and updated the print and input statements to Python 3. I also added the traceback module in case you need to debug it. Initially, I received an error telling me to complete step 3 above. I didn't see the error message at first, until adding traceback.print_exc() like you see below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import tweepy
import traceback

"""Delete All Your Tweets - Github Gist by davej
Credit: https://gist.github.com/davej/113241
Ported to Python 3 by Lo-Fi Python: https://lofipython.com/delete-all-your-tweets-with-tweepy-and-the-twitter-api/
"""
CONSUMER_KEY = "get_from_dev_portal"
CONSUMER_SECRET = "get_from_dev_portal"


def oauth_login(consumer_key, consumer_secret):
    """Authenticate with twitter using OAuth"""

    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
    auth_url = auth.get_authorization_url()

    verify_code = input(
        "Authenticate at %s and then enter you verification code here > " % auth_url
    )
    auth.get_access_token(verify_code)

    return tweepy.API(auth)


def batch_delete(api):
    print(
        "You are about to delete all tweets from the account @%s."
        % api.verify_credentials().screen_name
    )
    print("Does this sound ok? There is no undo! Type yes to carry out this action.")
    do_delete = input("> ")
    if do_delete.lower() == "yes":
        for status in tweepy.Cursor(api.user_timeline).items():
            try:
                api.destroy_status(status.id)
                print("Deleted:", status.id)
            except Exception:
                traceback.print_exc()
                print("Failed to delete:", status.id)


if __name__ == "__main__":
    api = oauth_login(CONSUMER_KEY, CONSUMER_SECRET)
    print("Authenticated as: %s" % api.me().screen_name)

    batch_delete(api)
Python Script Deleting Tweets

Twitter Cleanse Complete

Twitter has a really slick developer dashboard. Its API combined with the tweepy library got the job done for me. It's great when stuff just works. And it only cost me about 1 hour to complete. Time to start a clean slate. Here's to looking forward.

Supplementary Reading

Tweepy Documentation Tutorial

Twitter's API Tutorials

Twitter Postman Tutorial