51 comments

[ 2.3 ms ] story [ 117 ms ] thread
That `locals` block is really freaking neat.
Rich is probably the biggest lifestyle change I've ever had because of a single library.

Every one of my scripts now has quick and easy progress bars, console management (including saving a copy of console output), tables with columns, rows, and headers, "Processing..." blocks, colours, error logging, emoji, and on and on and on. It's really an amazing project that does a ton of stuff and makes it all easy to do.

If nothing else, add "from rich import print" to the top of your script (assuming you use print() statements) and see how your output looks afterwards, with highlighted numbers/floats, IP addresses, etc., formatted and syntax-highlighted JSON and repr output, and so on.

Thanks for the suggestion. I occasionally add progress % to some of my scripts, but anything more advanced I can’t be bothered. Excited to check out the library, thanks for the print() suggestion.
I so appreciate the little things, like `console.log` printing not only discretely naming the filename and line, but also providing a link to it.
Or the logging output only outputting timestamps when they're different so you can clearly see what happens and when.
Question: How horribly does the world break if you pipe the output to a file instead of stdout?
I would assume the lib authors accounted for this, it's pretty easy to check with sys.stdout.isatty(). If not you could alias it yourself.
(comment deleted)
Rich McGugan (author of Rich) talks about a lot of different design aspects of Rich on an episode of Talk Python [0] last October. I've used it in a few projects since then and for what I've been using it for the output is still easily consumable. Rich is a game changer for output in Python and it pairs nicely with CLI libs like Click. McGugan also is putting a lot of effort into Textual [1] which is fantastic for TUI apps.

[0] https://talkpython.fm/episodes/show/336/terminal-magic-with-... [1] https://github.com/Textualize/textual

*Will McGugan :)
Oh man, fail on my part. Apologies Will! I think now's a great time for me to donate. ¯\_(ツ)_/¯

Edit: Tried to sponsor your linked Ko-fi from what's listed in the rich repo, but the link provided doesn't work and searching your name doesn't pull anything up. Sent you an email to find a better way.

Glad you find it useful!
Curious to know if anything exists like this for Go?

I've been finding myself writing more and more CLI programs in Go (used to use python, but it's a bit harder to distribute python bundles around...), and so far I've just been starting with Cobra and going from there.

These are nifty! Thanks for sharing!
What's the use case for `inspect`?

Do I need to manually choose what to inspect in case of exception?

If it can be done by simply turn on a switch and all the exception will automatically colorful, then I can see it being somewhat useful; but for my toy script I would just run it in debugger which is even better for debugging.

I have been using it in an environment where I could not hook in IDE debugger but could sprinkle in breakpoint()s and rich.inspect away to my heart's content.
Which environment is that? So far I have been able to use a debugger everywhere.

If all fails use pdb.trace()

I had no way to punch holes through a bunch of nested ssh sessions on a tightened down production environment
If you're fortunate enough to use Python 3.7 or newer, then you can forego the importing of 'pdb' and using 'pdb.set_trace()' (I think you had a small omission there) in favor of just writing 'breakpoint()'[1] directly.

---

[1]: https://docs.python.org/3/whatsnew/changelog.html#id325

What is the difference? Set trace will basically hold the code at that line (breakpoint) and drop you into the interactive debugger session. It seems like syntactic sugar.

edit: but what seems like interesting concept is to overwrite sys.breakpoint_hook to start a custom debug server allowing for remote debugger attachment.

> It seems as though more and more of the simple command-line tools and small scripts that used to be bash or small c programs are slowly turning into python programs.

Is this a trend? How do people manage packages like Rich for use in their one-off scripts? It's been years since I've done Python, but IIRC installing packages globally was pretty brittle.

>but IIRC installing packages globally was pretty brittle.

The current trick is to use pipx[0]. Pipx will create an individual virtual environment for every executable tool you have, so there is no chance of conflicts.

You do `pipx install httpie` or `pipx install black` and then both utilities will be on your PATH, installed with whatever dependencies they require. I have never run into any issues with it.

Ninja edit: it also makes upgrades trivial: `pipx upgrade-all`

[0] https://pypa.github.io/pipx/

This might be an old man yelling at clouds, but I feel like virtual environments should be used for development and testing, but not for deployment. I'm development and testing, virtual environments let you test the package against many different versions of the dependencies. Using it for deployment, though, means that after a security hotfix, the admin needs to hunt down each utility's copy of a dependency, rather than just updating the one shared copy of the dependencies.
While everything about Python packaging is still a mess (but we now have a walrus operator, win?), I view virtual environment distribution as nothing more than a clunky static vs dynamic linking situation. Trust the system or bring your own.

I see the rise of Docker as indication that static linking won.

But dependencies should be pinned for every application anyway to not break compatibility when sysadmin goes and updates all dependencies.

There are two sides of the coin :)

For a language like Python, the pipx venv is similar to a Go static link. Same model of problem.
Dammit, I'm programming in python since a while and only just realized, that there are coroutines (asyc/await)!
So what's the best way to pack up a python cli app in a single artifact?

Right now I have an interactive python script that wraps a bunch of config files and has a few pip dependencies. currently i batch it in a docker container which is pretty heavyweight, and realistically needs its own wrapper script for users.

If there was an unfussy way to wrap that as a single artifact I'd look into making the whole thing python.

I’ve used pyinstaller with some success to do what you’ve described. It does end up bundling an entire Python runtime but it worked for me.

Nuitka is another option I haven’t tried.

Thanks for the response. I understand pythons popularity especially with the "batteries included" philosophy, but when it runs out of batteries the headaches can multiply quickly.

I'll check out pyinstaller and nuitka.

I've seen .EXE builders for Python that produce binaries for Windows, it'd be cool to have something similar in the *nix world.

Been seeing a lot of people who think Go is just better because you can build a single binary. Go is a pretty decent language but its weird that one feature seems to trump everything to far too many people I know.

Thanks for the response. I was thinking something similar. This particular cli is a client to an app i wrote in kotlin/java that tracks particular kubernetes pods.

There were a ton of hoops to jump through on both sides and then someone asked why I didn't just write it in go.

Well, this was consolidating some other functionality on both sides and I was extending/migrating the apps as we moved from colo to cloud, and it just... didn't occur to me, and we don't really have anything golang based, so no expertise or infrastructure and the migrations were happening regardless.

In hindsight this might have been better done that way, but I don't know that I've got the bandwidth to rewrite it all.

Distributing a shell runscript to run a docker image works because everyone in my space uses docker, and most of the teams are single language focused and most aren't python.

Its still an issue to keep everyone's run script updated, but maybe not enough to introduce a new language and toolchain.

You can produce binaries for macOS and Linux with PyInstaller.
There’s https://github.com/facebookincubator/xar - but cross platform could be a pain. Basically static link “binary” for Python (or other).
Looks cool despite being a facebook thing but hit this mammoth caveat:

>This requires a one-time installation of a driver for this file system (SquashFS).

Yeah. Depends on your use case I suppose. If you’re after cross platform or non-Linux, then it’s not an answer.
(comment deleted)
How does Textual compares to Urwid? And Rich to Blessed?

I'm currently using my own implementation for style/colors and tables in my main CLI tool, including highlighting with Pygments, and I'm wondering if it would make sense to move to Rich (it would a least bring Windows and Mac support).

Regarding progress bars, Python Prompt Toolkit already implements them, thus I have the feeling that Rich is quite redundant. Any feedback from experienced user?