New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide a 'print' action for argparse #53645
Comments
Currently argparse has a 'version' action which can be triggered by user defined options which prints out a custom string. parser.add_argument("--version", action="version", version="test 1.2.3") Since the 'version' action can be added multiple times, it can be used to output different kinds of information, like the program's license. parser.add_argument("--license", action="version", version="This file is licensed under GPL.... [a huge amount of text]") The only drawback is that linebreaks are substituted with a normal space. So I propose a 'print' action (perhaps as a replacement for 'version'?) which respects whitespace characters. parser.add_argument("--version", action="print", message="test 1.2.3")
parser.add_argument("--license", action="print", message="This file is licensed under GPL.... [a huge amount of text, now properly formatted!]")
parser.add_argument("--insult-me", action="print", message="You sick *peep* , *peep* yourself in *peep*") Currently, the only solution is to create a custom action which is IMHO a bit overkill for just printing a simple string to stdout. |
Sounds like a good addition to me. |
Should this print to stdout or stderr? I wonder if the API should allow either, and instead look like: parser.add_argument('--license', action='write', message='...', file=sys.stdout) Where sys.stdout would be the default for the file= argument. The action would then just literally call file.write(message), so the behavior would be pretty easy to explain. Of course, at that point it makes me wonder if maybe it wouldn't just be better to have an easy way to have some arbitrary function called without having to subclass Action, e.g.: parser.add_argument('--license', action='call', callable=lambda: sys.stdout.write(message)) Basically this would be a shorthand for subclassing Action when you don't need any information about the command line. |
Either way is fine for me. |
The equivalent to optparse callback is basically to define __call__ in a subclass of Action. Pretty much the same amount of work because they both have complicated parameters. The "callable" I (not fully confidently) proposed would just be a shorthand for defining __call__ in a subclass of Action when you don't care about any of the other command line info. I guess, without further use cases for "callable" and given that you can subclass Action for other use cases, let's just do the action='write' version. Feel free to supply a patch, or I will when I get some time for argparse again. |
Here is a patch that adds a 'write' action to argparse. Usage example: >>> parser = argparse.ArgumentParser()
>>> parser.add_argument("--license", action="write", message="This file\nis licensed under \t GPL")
>>> parser.parse_args(['--license'])
This file
is licensed under GPL A linebreak will be added after the message. The Output can be redirected with the optional 'file=' argument (it defaults to sys.stdout) The parser will then exit. This is my first patch ever written, so don't be too harsh if it's utter garbage^^ |
The patch looks basically right. A few minor issues:
self.file.write(self.message)
self.file.write("\n")
parser.exit()
http://www.python.org/dev/faq/#how-do-i-get-a-checkout-of-the-repository-read-only-or-read-write Thanks! |
sys.std* should not be used as default values in a function definition, because they may be rebound to other objects. The usual idiom is to have None as default value and check it at call time. The patch also needs tests and docs. (FTR, the example for callable in this report was wrong: First, the message argument was missing in the lambda, second, there was no need for a lambda in the first place :) |
Thinking again about that, what’s wrong with argparse replacing \n with spaces and doing its own line wrapping? |
I totally forgot about this patch, sorry... Due to university and another python project I am working on I didn't find the time to look at the test suite. I would really appreciate it if someone else could do this ;-) Anyway, I added the changes proposed by Steven Bethard and Éric Araujo regarding the default argument values. (patch made against trunk) @Éric: Copyright (c) 2010, Dennis Malcorps <dennis.malcorps@gmail.com> Redistribution This is just plain ugly. |
Thanks for the new patch. It does not apply cleanly to the py3k branch, but that’s very easily corrected. self.file.write(self.message)
self.file.write('\n') Could be replaced by print will use the right EOL for the platform and is just coooler. By the way, self.file should not be rebound in __call__:
Agreed, but I did not suggest that the output be like that. In my previous message, I suggested that argparse could replace \n with spaces and do its own line wrapping, to adapt to terminal length while avoiding chunking ugliness. That’s Steven’s call anyway, I don’t have any strong feeling in favor of preserving whitespace or rewrapping. If argparse wraps lines to the terminal width in other cases (like with epilog text), I think it should do so here too. |
Argparse's wrapping behavior is determined by the formatter_class: http://docs.python.org/library/argparse.html#formatter-class Is it reasonable to assume that if you're wrapping your own messages you're already specifying formatter_class=argparse.RawTextHelpFormatter? If so, then perhaps the message should be printed via something like: formatter = parser._get_formatter()
formatter.add_text(self.message)
file.write(formatter.format_help()) This is what we do in _VersionAction, so I guess it's probably what we should do here. |
@paul what is your take on this, other opinions seem positive? |
As Steven notes, the patch lacks tests. It also lacks documentation. The 2 things that this class does different from 'version' are
There is a difference in opinion between Éric and Steven as to whether the class should use write directly or use the HelpFormatter. I don't think it needs further action at this time. There doesn't seem to be a lot of interest in it. Also there are a number of ways of accomplishing the task without adding an Action class.
I've attached a file that illustrates a number of these alternatives. It includes a 'callable' class. The discussion got me thinking about a selective version of the RAW formatting, analogous to the HTML <pre> tag. With this the user could mark a given text (description, epilog, help, version etc) as pre-formatted, without having to change the formatter_class. parser.add_argument('--license', action='version',
version=Pre(formatted_text)) I probably should submit that in a new issue. |
Marking this as closed because there has been no activity or interest for over five years. If anyone wants to revive this and write a PR, feel free to reopen. The core idea is plausible, but this doesn't seem to be a recurring need. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: