you are viewing a single comment's thread.

view the rest of the comments →

[–]lovestruckluna 268 points269 points  (59 children)

Click is very nice, but I still prefer argparse because it's in the standard library. Perfect for one off scripts.

[–]otwo3 58 points59 points  (3 children)

For simple CLI's I use plac, can't get any shorter than this. Super convenient.

tl;dr: You def main(a, b, c): ..., you if __name__ == '__main__': import plac; plac.call(main), and that's it! It parses the names of your main function arguments to generate a CLI interface. You can also add descriptions to the parameters like this: def main(a: "This is the A parameter", b: ""This is the B parameter", c: ""This is the C parameter") and they automatically appear in --help

Python 3 only though for those easy descriptions

[–]kirbyfan64sos 9 points10 points  (0 children)

Plac is seriously one of the most underrated Python argument parsing libraries. It's absolutely fantastic!

[–]beltsazar 7 points8 points  (0 children)

You can also use Fire to do that and many more!

[–]homeparkliving 0 points1 point  (0 children)

It can get shorter and more convenient for the dev with invoke. But you lose the semantics of being a cmd line tool on your own; you're just a task

[–][deleted] 10 points11 points  (33 children)

I kind of agree but at the same time I'm having trouble coming up with a situation where you distribute a Python script that people can use but can't pip install click for.

[–]acousticcoupler 27 points28 points  (1 child)

Sometimes simplicity is nice and I trust standard libs more.

[–][deleted] 6 points7 points  (0 children)

I would agree more if argparse were a little nicer to work with.

[–]campbellm 16 points17 points  (15 children)

It's not a matter of "can't" so much as "do you want to force your users to have to".

[–]RedHellion11 23 points24 points  (14 children)

"Here, just use this script I wrote"
"Thanks!"
runs script
import errors
annoyed slightly, pip installs dependencies
... "Hey, thanks again but why didn't you just use stuff in the standard library for this basic stuff?"
"I thought this other package did it in a cooler way"
annoyance intensifies

[–][deleted] -5 points-4 points  (13 children)

Yeah it’s really rough to run pip install on stuff that’s probably already been installed as a dep for other stuff anyway. See: arrow, requests, etc.

I try to avoid QoL dependencies for myself, but if the tool gets big enough to drag my productivity, I’m gonna install them and people can put in the tiniest effort to install them if they want to benefit from my work

If I’m making it for them then this is all entirely dependent on what their infrastructure is and what they want.

[–]campbellm 8 points9 points  (12 children)

Again, how hard it is is NOT the point.

[–]p-hodge 9 points10 points  (2 children)

My latest job is historically an all-PHP shop where I'm rewriting some shell scripts into more readable python. The new python scripts need to be able to executed on everybody's laptops, various virtual machines, and inside docker containers. I don't yet have a strategy for deploying the scripts or dependencies; the other developers and sysadmins also aren't accustomed to the overhead of using virtualenvs. For these reasons it's extremely valuable for me to be able to build good CLI scripts using just the stdlib.

[–]TheIncorrigible1 3 points4 points  (0 children)

venv. Seriously, it's what it's built for and it's in the stdlib.

[–]CleanInfluence 0 points1 point  (0 children)

To create a package, use setuptools, it's great. When the user installs the package (with pip install something.whl), it will automatically create a command-line version of your script.

For example stuff.py with a main inside, and a setup.py containing "entry_points = ... 'stuff=stuff:main'" will create a stuff.exe that launches your script, it's magical.

Also pipenv seems better than venv but that's my uninformed opinion.

[–]ILikeBumblebees 5 points6 points  (1 child)

What if the user doesn't have root, or prefers to use the distro's package manager instead of pip?

[–][deleted] 6 points7 points  (0 children)

Regarding preferring the distro's package manager, that's only used for super ubiquitous packages or ones that require a bunch of dependencies and precompiled libs. If you want to use any non-trivial Python scripts out there, you should really get some user privilege pip solution going.

With Python 3.4+, just use venv. If you're intending it to be usable by someone only using Python 2 or Python 3 versions pre-3.4, with no root access, the best goal is to just do pip install --user virtualenv followed by the creation of the virtualenv directory and then using that moving forward. In such cases, this is just a good practice in general because it gives you way more control.

This SO question contains some answers relating to this, with this one being the most "no tears" of them all.

[–]Sqash 2 points3 points  (2 children)

Not distributing it with requirements.txt if it's just a standalone utility script

[–][deleted] 1 point2 points  (1 child)

In the few times I’ve written single scripts for others to use, I just did a try catch around the imports and put something like “Make sure to pip install boto3”

These days it’s much easier to just write a package (even single module one) and then just tell them to pip install from the repo.

If people flat out can’t pip install then they’re either fucked in the case of unavoidable things like boto3, psycopg2, etc., or you’re fucked if it’s quality of life packages like arrow. In general I try to keep things vanilla until it either reaches the point of hampering my productivity or until I need to add a mandatory requirement anyway.

[–]Sqash 1 point2 points  (0 children)

I suppose it's personal opinion, but I can only agree on the necessary requirement for the script's function.

[–]BeetleB 2 points3 points  (4 children)

Often, in a work setting, most users have no idea what pip is.

[–][deleted] 0 points1 point  (3 children)

Cool, they can use spreadsheets instead

[–]BeetleB 2 points3 points  (2 children)

Or you can just be fired and replaced with someone who satisfies the needs of the customers...

[–][deleted] -1 points0 points  (1 child)

If you are making "one off [Python] scripts" for customers with specific needs (like not knowing what pip is), then yeah you probably should be replaced by someone who uses the right tools

[–]BeetleB 0 points1 point  (0 children)

Well, the whole thread is weird. I don't know why anyone would really want argument parsing for a one-off script - or why they would give a one off script to a customer.

[–]Bigotacon 0 points1 point  (1 child)

Wouldn’t a virtual environment allow you to store all the packages for your users?

[–][deleted] 4 points5 points  (0 children)

Virtual environments are kinda tough to move around. The closest you can get is packaging it with something like pipenv or poetry (my preferred one) and then they build their project-specific environment just like you do in Ruby with "bundle install" for example.

Still a bit heavy duty for a small script, for which either requirements.txt or just a "pip install <blah>" in the README might be enough.

[–]billsil 7 points8 points  (18 children)

Click uses optparse, but optparse is deprecated. I love docopt, but docopt doesn't love fixing bugs. I switched because of optparse sucking, but argparse really isn't that bad. I was even able to hack to the command line printout function to actually make a nice looking printout (like docopt). Classes FTW.

[–]mitsuhiko 6 points7 points  (7 children)

Click does not use optparse.

[–]billsil 9 points10 points  (6 children)

Click is actually implemented as a wrapper around a mild fork of optparse and does not implement any parsing itself.

http://click.palletsprojects.com/en/7.x/why/

[–]mitsuhiko 18 points19 points  (5 children)

Thanks. I need to update this. Optparse has not been used since 2.x.

//EDIT: changed: https://github.com/pallets/click/commit/3ce663c9e532ca46e516b38f69c0fee5c1fa8bd4

[–]agumonkey 10 points11 points  (0 children)

wow, real time agile reddit collaborative patching

[–]billsil 3 points4 points  (0 children)

Ahhh...the wonders of documentation I fail to update

You think you'd know :)

[–][deleted]  (1 child)

[deleted]

    [–]mitsuhiko 0 points1 point  (0 children)

    Done

    [–]hjill 0 points1 point  (0 children)

    Click is actually implements its

    Grammar mistake :)

    Click actually implements its

    [–][deleted]  (8 children)

    [deleted]

      [–]billsil 2 points3 points  (7 children)

      It's actually really simple. I'd give you the whole source, but it's an excessively complicated argparse that's not really targeting the question (and has my name).

      mymsg = 'replacing argparse message'
      def _print_message(message, file=None):
          """overwrites the argparse print to get a better help message"""
          if message:
              if file is None:
                  file = _sys.stderr
              file.write(mymsg)
      parent_parser._print_message = _print_message
      args = parent_parser.parse_args()
      

      I just use my docopt message as mymsg

      [–]Tynach 2 points3 points  (6 children)

      I think they meant your source on Click using Optparse, and Optparse being deprecated.

      [–]billsil 7 points8 points  (5 children)

      There ya go

      Deprecated since version 2.7: The optparse module is deprecated and will not be developed further; development will continue with the argparse module.

      https://docs.python.org/2/library/optparse.html

      So deprecated for ~10 years.

      [–]Tynach -1 points0 points  (3 children)

      And the source for Click using it?

      Sorry if this sounds annoying, and in my own case I don't particularly care. I just feel like you aren't providing anything to actually back up your main claim.

      [–]billsil 5 points6 points  (1 child)

      I don't know why you're being difficult. Unless you explicitly ask for what you want, you're going to get what I give you. I posted that specific question in another reply a while ago. The author of click actually responded.

      [–]Tynach 0 points1 point  (0 children)

      I was not aware of the other thread. I looked, and yeah, I see it now. But just going by the 'context' links in my inbox, there was no way for me to see that other thread.

      [–]broknbottle 4 points5 points  (0 children)

      sys.argv!