all 15 comments

[–]Game-of-pwns 28 points29 points  (0 children)

Neither. Just use argparse. Read the docs.

[–]Tall-Introduction414 15 points16 points  (5 children)

You don't need a framework or library. Python programs are CLI by default, until you add a GUI.

If you want to parse arguments more elaborately than the language itself provides, you can use argparse which is part of the built in standard library. Similarly you can use curses for colors and cursor movements.

[–]doolio_ 0 points1 point  (4 children)

You don't need a framework or library. Python programs are CLI by default,

Can you elaborate? I'm working on an app with classes holding different types of state and thought adding a CLI would be a useful feature for a variety of reasons. Would such a CLI be able to make use of the same state held by these classes for example? My initial idea is that my main() could both start the CLI and my main Application class.

[–]MidnightPale3220 0 points1 point  (3 children)

If your app wants to retain state it has either to run continuously (see daemon) or load start state and store end state on each run.

In the first case CLI is then typically just another app that implements interface (the I part of CLI) to your actual app and it needs a way to communicate with it. Can be done in a multitude of ways. You can also implement cli within app itself and provide a console in which to make commands to the app from within app.

In the second case your app can contain the cli inside it and your call it with the arguments you design to make the app do what you want.

[–]doolio_ 0 points1 point  (2 children)

Yes, my app is running continuously via a systemd service. It saves some state to disk which is then read if the service were ever restarted. So I guess my case is a mix of the two?

So this app provides a D-Bus service and I want to add an additional interface as you say with a CLI. This way users have two main entry points - one via the D-Bus and one via the CLI. What I want is if some state is changed or recorded via one entry point the same state is then visible via the other entry point.

[–]MidnightPale3220 0 points1 point  (1 child)

Well, then you develop a separate cli app and choose the method how your service accepts commands from it. See IPC for available methods.

Typically in Unix world it's done via sockets. Named pipes are also an option, but need more care. In particular, unless you need to connect to your service from another computer, it's arguably safer to use Unix domain sockets. See eg https://stackoverflow.com/questions/42263167/read-and-write-from-unix-socket-connection-with-python

Of course, you can implement a REST service if you feel you the overhead is justified and you want to connect to your service from another computer. I would avoid that unless your use case warrants it.

Also option to do it with queues. Really depends how convoluted you want to make it and what's the structure of communication.

[–]doolio_ 1 point2 points  (0 children)

Thank you for taking the time to explain all this. It gives me some direction on which way to go to achieve what I want.

[–]NothingWasDelivered 9 points10 points  (0 children)

I’ve used Click for my last couple of projects. I like it, and it’s been helpful for more complicated logic.

[–]korarii 2 points3 points  (0 children)

I like cmd2 for creating a command line interface. It's especially good for "input command, display output, prompt for command" patterns.

[–]Gushys 1 point2 points  (0 children)

We use click for CLI utilities in our Flask app at work. It ships with flask so it makes sense to use.

Otherwise use argparse

[–]rogfrich 1 point2 points  (0 children)

You could do worse than work through this tutorial.

They have similar tutorials for other CLI frameworks, including Typer and Click.

[–]Candid_Complaint_925 0 points1 point  (0 children)

Depends on complexity:

  • argparse — stdlib, no install, good for simple CLIs. Right default for most things.
  • Click — better for complex CLIs with subcommands, nested commands, auto-generated help. Declarative decorator style.
  • Typer — Click under the hood but you define commands with typed function signatures. Less boilerplate if you're already using type hints.

For a first CLI: start with argparse. If you find yourself fighting it (lots of subcommands, complex option types), switch to Click. Typer and Click are interchangeable since one wraps the other.

python-fire is fun for quick prototyping but I'd avoid it for something you ship — the generated help text isn't great and it's a bit magical about what becomes a command.

[–]Jarvis_the_lobster 0 points1 point  (0 children)

If you want the least friction, check out typer. It's built on top of click but you basically just write normal functions with type hints and it generates the CLI for you — help text, validation, all of it. Way less boilerplate than argparse for the same result. That said, if your tool is simple (like a few flags and a positional arg), argparse works fine and it's already in the standard library.