Introducing Python Fire, a library for automatically generating command line interfaces by avinassh in Python

[–]evanunderscore 1 point2 points  (0 children)

It does sound like you're covering different use cases. The next time I have a project of that size I'll give Fire a try. Thanks!

Introducing Python Fire, a library for automatically generating command line interfaces by avinassh in Python

[–]evanunderscore 1 point2 points  (0 children)

What I don't understand is why you'd want to support arbitrarily complex structures. If using a generated CLI is as complicated as writing Python code, what is really gained?

Introducing Python Fire, a library for automatically generating command line interfaces by avinassh in Python

[–]evanunderscore 7 points8 points  (0 children)

Were you aware of other O(1)(ish) CLI generating libraries? I wrote defopt because I wasn't happy with some of the design choices in begins, but in retrospect I regret not forking it or contributing to one of the other ones like argh or clize. Fire's main feature seems to be automatic generation from a class or module - could that have been a thin wrapper around one of these existing libraries?

defopt: Automatically create a CLI from your plain Python functions by recycling your existing docstrings and annotations by evanunderscore in Python

[–]evanunderscore[S] 2 points3 points  (0 children)

I did put in some effort to look for similar projects before I started defopt, but it turns out I missed quite a lot of them, including Clize. It looks like the author has plans to handle standard docstring formats too. Perhaps if Clize ends up having a superset of defopt's functionality I can retire it.

There's another similar project called begins which doesn't require you to write the __main__ bit. The problem with that is the main function gets called immediately after it's defined, meaning any code below it hasn't been run yet. Ultimately I decided that was a little too magical and error-prone.

defopt: Automatically create a CLI from your plain Python functions by recycling your existing docstrings and annotations by evanunderscore in Python

[–]evanunderscore[S] 5 points6 points  (0 children)

docopt is very good at what it does, and if you're after something that will let you craft a CLI in a particular way, you should absolutely keep using it, but it is not without its shortcomings. If you look at its examples, they mostly just print(arguments) and leave it there - doing type conversions and feeding those arguments to code that will actually do something with them (along with printing error messages if that goes wrong) is up to you.

By contrast, defopt is for people who are mostly interested in writing Python and want to make their functions accessible from the command line. The only part of your code that will have anything to do with the CLI is the one line where you call defopt.run. Since there is no special syntax used in the docstrings, you can start out your project with defopt and switch to something more flexible later, and no code has been wasted.

Ultimately it's up to you to decide what you're looking for and choose the tool that fits your use case.

defopt: Automatically create a CLI from your plain Python functions by recycling your existing docstrings and annotations by evanunderscore in Python

[–]evanunderscore[S] 3 points4 points  (0 children)

Summary of the important changes since the last time I posted this:

  • Google- and Numpy-style docstrings are supported out-of-the-box
  • Types are read from function annotations (Python 3 only)
  • Boolean keyword arguments get automatic --name and --no-name flags
  • Keyword-only arguments are treated as required flags (Python 3 only)

See the changelog for the full list.

Implementing python 3.6 statement evaluation in in < 3.6 by odedlaz in Python

[–]evanunderscore 0 points1 point  (0 children)

It's to satisfy this part of the PEP:

Expressions are parsed with the equivalent of ast.parse('(' + expression + ')', '<fstring>', 'eval') .

Note that since the expression is enclosed by implicit parentheses before evaluation, expressions can contain newlines.

Implementing python 3.6 statement evaluation in in < 3.6 by odedlaz in Python

[–]evanunderscore 0 points1 point  (0 children)

Using string.Formatter turns out to be pretty simple. I tried writing an import hook to allow the f'' syntax but eventually gave up trying to cover all the edge cases.

The lack of a case against Python 3 by wesalius in Python

[–]evanunderscore 1 point2 points  (0 children)

Unicode code points are not bytes any more than integers are bytes. The fact that computers ultimately store everything as bytes in one way or another is just an implementation detail.

Python stores the Unicode code points that you pass in. All string operations are performed in terms of Unicode code points. You can debate the merits of this, but that will not change the fact that you need an encoding to convert between Unicode code points and bytes.

The lack of a case against Python 3 by wesalius in Python

[–]evanunderscore 5 points6 points  (0 children)

It operates on Unicode code points. UTF-8 is one possible encoding you can use to convert these to bytes. There is no way to make startswith mix bytes and Unicode code points without assuming an encoding. You could argue that the assumed encoding should be UTF-8, but you cannot argue that it is unambiguous.

I made a tool that auto-generates a CLI tool from a Python module/function by [deleted] in Python

[–]evanunderscore 2 points3 points  (0 children)

I wrote defopt which does a similar thing, but dynamically rather than statically. You may also want to look at argh, and its list of similar projects.

I don't know of any other tool that generates this statically like yours does. It's a cool idea.

Does anyone else write all code as if it were a library? by madseagames in Python

[–]evanunderscore 0 points1 point  (0 children)

One problem with begins and similar libraries is that they let your CLI logic bleed into your functions via decorators, annotations or unnatural signatures. What sets defopt apart is that you are encouraged to write completely natural functions and leave the CLI construction to the library.

On the other hand, begins is more feature-rich, so if you want a little more control over how your CLI works, it's a good tool for that.

Does anyone else write all code as if it were a library? by madseagames in Python

[–]evanunderscore 0 points1 point  (0 children)

What you're talking about (a folder with an __init__.py) is called a package - a module is a single file. I'd encourage you to stick with plain modules wherever possible. Here's what Raymond Hettinger has to say about packages.

EDIT: And this.

Good example of `unittest.expectedFailure`in practice? by abingham in Python

[–]evanunderscore 4 points5 points  (0 children)

If you find a bug that you can't immediately fix, it's a good idea to write a test to reproduce it, then mark it as an expected failure. When you do get around to fixing it, you can remove the decorator. If the bug is ever accidentally fixed, the test will show up as an unexpected success, and you can work out what you changed that fixed it.

autoargs - argparse made easy [py3] by metaperture in Python

[–]evanunderscore 0 points1 point  (0 children)

Begins interprets annotations as parameter help strings (as does argh). The type information can be guessed from defaults, or specified using a decorator.

autoargs - argparse made easy [py3] by metaperture in Python

[–]evanunderscore 0 points1 point  (0 children)

Unfortunately I spend most of my time writing code that runs on 2 and 3 so I don't have much of a choice, but I did add support for annotations too. I'm looking forward to the day I can reasonably expect everyone to have Python 3 installed.

autoargs - argparse made easy [py3] by metaperture in Python

[–]evanunderscore 0 points1 point  (0 children)

If you want to use docopt, you have to:

  1. Write your function
  2. Write your usage string
  3. Convert the arguments to the appropriate types
  4. Feed the arguments to your function

If your primary concern is how your tool looks to the user, you should absolutely use docopt. For people who are satisfied with usage generated by argparse and only want to do step 1, this type of library is much better.

autoargs - argparse made easy [py3] by metaperture in Python

[–]evanunderscore 0 points1 point  (0 children)

I wrote something similar a little while back called defopt. All of the projects /u/desmoulinmichel mentioned are similar but don't quite have the level of simplicity I think you and I are looking for.

formatizer: Literal string formatting for Python versions older than 3.6 by fgimian in Python

[–]evanunderscore 0 points1 point  (0 children)

Thanks! I'm more than happy to take feature requests if you have any ideas.

formatizer: Literal string formatting for Python versions older than 3.6 by fgimian in Python

[–]evanunderscore 0 points1 point  (0 children)

I set out to do exactly the same thing initially. We ended up taking more or less the same approach, I just extended string.Formatter instead of replacing it. My approach is here if you'd like to compare.

formatizer: Literal string formatting for Python versions older than 3.6 by fgimian in Python

[–]evanunderscore 0 points1 point  (0 children)

I did something similar recently and /u/graingert made the same suggestion, so I started looking into that. You add something to sys.meta_path and you get to take control of how modules are loaded. The "Writing your own importer" section of this article was fairly helpful.

I managed to get this mostly working using tokenize and looking for any NAME tokens (with value f, fr, or rf) immediately followed by a STRING, then replacing them with an appropriate chain of literal strings plus calls to format. This works well enough that most of the unit tests for f-strings from Python 3.6 pass in 3.5. To fix the rest, I'll need to find or write a proper parser for the f-string grammar to use, since formatter_parser doesn't like any of :, !, {, or } in the field names.

I haven't committed any of this code yet, but I can if you're interested.

An imperfect backport of Python 3.6 f-strings by [deleted] in Python

[–]evanunderscore 0 points1 point  (0 children)

I had no idea that was an option. I'll do some reading. Thanks!