Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Python's many command-line utilities (pythonmorsels.com)
128 points by todsacerdoti on June 3, 2024 | hide | past | favorite | 44 comments


My favorite and probably most useful? `python3 -m venv ./venv` Honestly, forget about conda, poetry, virtualenvwrapper etc and just use that one.


I like to add `--upgrade-deps` as well. This automatically updates pip and setuptools within the venv after creation.


Didn't know about this .. thanks!


Exactly. People complain about Python's package management story, but for 99% of use cases a workflow that consists of Python's built-in venv, pip, requirements.txt, and constraints.txt is completely fine.


Even more if you use the legendary "pip-chill" to trim down the requirements file ;-)

Sorry. Shameless plug.


Poetry tracks your direct vs transient dependencies for you, and poetry run is stateless and easier to work with than a stateful activated venv


Or `uv venv`, `uv pip install` for a free, pretty extreme speedup. https://github.com/astral-sh/uv/


To save 4 seconds when installing dependencies?


My work saw a 5x speedup (~2min to ~20s) with a cold cache and like 200-500x (~20s to <0.1s) with a hot cache in our CI pipelines when we switched to uv.


Completely agree


Another handy trick is to use "-c" for executing the string as a command[0]. You can separate the commands by newlines or ";" if you're lazy (like me).

This is really handy when you're moving around environments and you want to get the path or location for a module:

>>> python3 -c "import httpx; print(httpx.__path__)"

or

>>> python3 -c "import httpx; print(httpx.__file__)"

[0] https://docs.python.org/3/using/cmdline.html


You can also call '__import__' as a function to save yourself a few characters worth of rsi

  >>> python3 -c "print(__import__('httpx').__path__)"


Found this one recently:

    If you have python and curl you can extract tag and its contents out of html file curl -s http://www.google.com/ | python3 -c 'import sys; s=sys.stdin.read(); e=""; print(s[s.find(e)+len(e):s.find("")])'


I subscribed to pythonmorsels, and I must say that Trey Hunner gives great product. Simple, one-page exercises that nevertheless make one think, and a polished user experience. Worth a look for anyone who'd come here.


Trey Hunner has created a ton of useful and interesting Python articles. Although I've been programming in it for 20+ years, I always learn new things. He's a national treasure.

Pythonmorsels is a great subscribe.


Thank you so much for your kind words! I'm really glad you found Python Morsels useful.


RES IPSA LOQUITUR


I recognize this is the most trivial example cited, but on a Mac, you can also use the `open` command to open an URL:

    open "http://example.com"


Some Linux distros offer a similar (though far less memorably named) "xdg-open".

It doesn't do any of the other really handy things the MacOS "open" command can do, like "open -f" slurping stdin into a fresh instance of your default text editor.


Recent distros have `open` as a symlink to `xdg-open` instead of the old `openvt`.


I believe that’ll be deprecated by `gio open` soon.


AIUI xdg-open is the standard tool which then forwards to the (equivalent of the?) desktop-specific tools. For KDE it's `kioclient exec`.

I wouldn't be surprised the GNOME people try to break this standard tool too.


This is correct. Unfortunately, xdg-tools is a set of almost forgotten scripts that need some more eyes and collaboration to polish. I've seen many problems there. Nobody is actively maintaining it, but a couple developers could get the ball rolling. (I'm interested)


On Windows, you can do this from the run dialogue!

[WIN]+R -> https://google.com


also, open . opens your current directory in Finder


That’s not what httpx does.


Was this maybe in reference to my top-level comment? If so, I just used httpx as an example of a module most people would have installed.


httpx was not referenced in the original article.


If you need to mess with semantic versioning, `python -m semver`.


It's a third party package, though.


I could probably figure it out, or find it documented, but it would be nice to have concise instructions on creating a Python command-line utility.


As long as your python program checks for __name__ like this:

  if __name__ == "__main__":
      # Your code here
Then it should mostly "just work". Use the argparse module to parse command line arguments if necessary. Create a setup.py and use pip to install it, if you want.


if you get lost using argparse, give docopt a try, it's self documenting.


I've been making zero-cost Python CLIs with this for years:

https://github.com/google/python-fire


Click is a nice option too. Slightly less magic than docopt, though docopt is great for quick hacks.


if you want complex subcommands and a truly fluent CLI interface, go with a click. https://click.palletsprojects.com/

else: argparse is more than enough https://docs.python.org/3/library/argparse.html


Or go a step beyond and get typer (which builds on click IIRC)

https://typer.tiangolo.com/

If you use Poetry and a pyproject.toml, you can even make your package installable with something like pipx straight from Github. Its a trick I use often for little command line utilities.

https://python-poetry.org/docs/pyproject/#scripts


What value does poetry add to this? A simple cli should be trivially packageable.


Just any properly packaged Python project is installable from git by pip. No deps needed.


I've not personally stumbled on a UI where Click was used to make something nicer than argparse could. I'm not saying those don't exist, just that I haven't seen one.

Every time I've seen someone use Click at work, it was to implement some simple args that argparse could handle identically. "Why are we using Click here?" "Because it's nice!" "In what way?" "It's nice!" "But we're not actually using the nice parts." "Click is nice!"

Click is nice. IMO it's used way too often in cases where argparse would do just as well.


I've reached for click when I need to create a layered command scheme .. ex where `mytool command1 --help` and `mytool command2 --help` would provide two different sets of arguments.

Similar to what the `git` suite provides.


The argparse version of that is `add_subparsers`: https://docs.python.org/3/library/argparse.html#argparse.Arg...


There is also a (unofficial) Google project called fire [1]:

> Python Fire is a library for automatically generating command line interfaces (CLIs) from absolutely any Python object.

[1] https://github.com/google/python-fire


The great tiangolo (creator of FastAPI) has a library just for this which makes it easy:

https://github.com/tiangolo/typer




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: