classification
Title: argparse: add ability to create a man page
Type: enhancement Stage: needs patch
Components: Library (Lib) Versions: Python 3.6
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Aaron.Meurer, Daniel.Walsh, Ingo.Fischer, Oz.Tiram, acucci, adregner, andialbrecht, bethard, bignose, bochecha, dmalcolm, josh.r, jwilk, louielu, matthewjohn, merwok, paul.j3, rhettinger, serhiy.storchaka, sigi, tshepang, zbysz
Priority: normal Keywords:

Created on 2012-02-23 21:15 by Daniel.Walsh, last changed 2017-04-19 12:35 by zbysz.

Files
File name Uploaded Description Edit
build_manpage.py Oz.Tiram, 2014-06-11 17:13 Add a command class to setuptools.setup
poc.py louielu, 2017-04-18 14:28
poc_2.py louielu, 2017-04-19 11:02
Pull Requests
URL Status Linked Edit
PR 1169 open louielu, 2017-04-18 14:19
Messages (21)
msg154090 - (view) Author: Daniel Walsh (Daniel.Walsh) Date: 2012-02-23 21:15
I have developed a new tool virt-sandbox-service using argparse.  Currently the argparse has the ability to print help and usage.  Being naturally lazy, I think it should be able to print out a man page also.  This would help with development and make maintaining the different documents.
msg154112 - (view) Author: Éric Araujo (merwok) * (Python committer) Date: 2012-02-24 04:50
Are you aware of help2man?  It can transmogrify the output of “your-program-that-uses-argparse --help” to a man page.  Another solution is to use docutils’ rst2man to convert some documentation file to the man format.

On the other hand, this blog post contains code implementing a custom optparse formatter for man pages, which could probably be adapted for argparse easily, so it does not look hard to implement.  (Note that the code has no licensing information.)

Steven, what do you think?  Too specialized for the stdlib or small, useful new feature?
msg154113 - (view) Author: Éric Araujo (merwok) * (Python committer) Date: 2012-02-24 04:51
Forgot the link to the blog post: https://andialbrecht.wordpress.com/2009/03/17/creating-a-man-page-with-distutils-and-optparse/
msg154125 - (view) Author: Steven Bethard (bethard) * (Python committer) Date: 2012-02-24 09:53
I think adding a new formatter for man pages would be generally useful. Assuming someone provides a patch. ;-)
msg154189 - (view) Author: Éric Araujo (merwok) * (Python committer) Date: 2012-02-25 06:05
Alright :)  I’ve contacted the author of the blog article to ask him if we can reuse his code.
msg154216 - (view) Author: Éric Araujo (merwok) * (Python committer) Date: 2012-02-25 08:57
Andi, the author of the blog post, will work on a patch.
msg220288 - (view) Author: Oz Tiram (Oz.Tiram) * Date: 2014-06-11 17:13
Hi, 

I have been wanting this feature for quite a long time. IMHO, binaries and scripts should always include a man page. The Debian developers require that. However, man pages have a 'bizarre' format. 
Long talk, short time. I did implement something. I tested it on Python 2.7 since my project currently only supports Python 2.7. 
I think it should not be complicated to port to Python 3.X. 

I doubt if the correct place for formatting a man page should be in argparse.py itself. My solution is an extension of Andial's brecht solution that uses ofcourse argparse.

You can see it in action in https://github.com/pwman3/pwman3

I am also attaching the code here. 

I hope you will find this file useful. I would appreciate your comments too. 

Regards, 
Oz
msg220380 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2014-06-12 20:09
> I have been wanting this feature for quite a long time

Me too.
msg220506 - (view) Author: Oz Tiram (Oz.Tiram) * Date: 2014-06-13 22:02
@Raymond Hettinger, 
You don't have to wait anymore. I would be happy if you review the patch, and share your opinion.
I might have posted my patch too early. I am still doing changes on the upstream, in my github posted earlier.So, please test the one upstream.
msg244981 - (view) Author: Mathieu Bridon (bochecha) * Date: 2015-06-07 23:30
Any news on this?

The code posted by Oz Tiram (I took the latest from his github repo) works quite well, even with Python 3. (I just tested it)

It would be great if argparse could include the formatter class, as well as the distutils command.
msg261371 - (view) Author: Ben Finney (bignose) Date: 2016-03-08 19:45
Oz Tiram wrote:

> I doubt if the correct place for formatting a man page should be in argparse.py itself. My solution is an extension of Andial's brecht solution

Thank you for that, Oz.

I see an easy seam to refactor this work into separate concerns.

The formatting of a man page from the parser for the command, can be coupled to the ‘argparse’ module since it is dependent only on an ArgumentParser plus some extra properties for populating the man page.

The building of one man page should not, IMO, be so tightly coupled to a Python distribution. There may be several different commands installed by one distribution. Each man page's fields should mostly come from the parser for the command, not from the distribution metadata. Instead, the build process should be told which parser to use for generating each of the man pages.

I propose to work on Oz's module and produce a man page formatter for exactly one ArgumentParser, as an enhancement for ‘argparse’.
msg263855 - (view) Author: Alessandro Cucci (acucci) * Date: 2016-04-20 18:35
I would like to work on a patch if nobody currently are working on it. I'll keep you updated
msg291836 - (view) Author: Louie Lu (louielu) * Date: 2017-04-18 14:28
Hi all, I've created a PR for this, please help for code review.

I found that previous method from Oz had a problem, that man page and general help page will share a Formatter, that cause an unexpected behavior that help page will generate with troff format (Unix man page used this format).

I switch to another method that creates a Manpage class and a private _ManpageFormatter, we just need to put parser into this Manpage, the __str__ method will generate the man page that we want.

This approach prevents help page format affect by ManpageFormatter, and the user can happily switching formatter_class to RawDescriptionHelpForatter, RawTextHelpForatter and others, since the Manpage class is separate from HelpFormatter, and _ManpageFormatter will used the formatter provide from parser.

The attach file is a dummy argparser file, you can try it by this:

  ./python poc.py > poc.1 && man ./poc.1
msg291866 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-04-19 08:02
How to use this feature? argparse is executed every time when the end user runs the program. But generating a man page is the action that should be executed at develop or build stage. The end user gets a generated man page, he doesn't need the option to generate a man page on a fly. The developer needs the ability to generate a man page rather than running the program for its main purpose. What should be the structure of the program that uses argparse for parsing arguments and for generating a man page? How generating a man page should be invoked?
msg291870 - (view) Author: Louie Lu (louielu) * Date: 2017-04-19 10:13
> How to use this feature?
> argparse is executed every time when the end user runs the program.
> But generating a man page is the action that should be executed at
> develop or build stage.
> ...
> How generating a man page should be invoked?

For now, man page will only be generated by using `print_manpage` function, and argparse won't add a shortcut like help page (-h).

Developer can use `parser.add_manpage_section` to add custom manpage section, e.g. copyright, report bugs.

The only thing that will affect it that `add_manpage_section` will be adding at runtime, but user won't used it.


> The end user gets a generated man page, he doesn't need the option to generate a man page on a fly. The developer needs the ability to generate a man page rather than running the program for its main purpose.

Yes, this patch will only offer the ability to generate man page, but if developer want to build with `setup.py`, it still need to combine them.


> What should be the structure of the program that uses argparse for parsing arguments and for generating a man page?

It won't need additional change, just used current method and it will work.
msg291871 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-04-19 10:44
But how to use print_manpage()? Can you provide a new template of a program that uses argparse?
msg291876 - (view) Author: Louie Lu (louielu) * Date: 2017-04-19 11:02
Attachment is the poc of generating man page via `print_manpage`:

    $ ./python poc_2.py > output && man ./output
msg291877 - (view) Author: Louie Lu (louielu) * Date: 2017-04-19 11:04
Also, `print_manpage` use the same infra as `print_help` and `print_usage`, so it can use the parameter `file` to output to different stream or file.
msg291879 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-04-19 11:21
Your example just prints a man page. It doesn't do anything useful besides this.

I'm asking how argparse can do two incompatible things: provide a command-line interface for an end user and generate a man page in a build script.

Do you mean that the programmer should create a separate script for generating a man page and copy a part of the code from the main program? This workflow should be documented, with examples. And it is not applicable for simple one-file scripts.
msg291882 - (view) Author: Louie Lu (louielu) * Date: 2017-04-19 12:29
Sorry that I didn't figure out what you said in the previous msg.

> provide a command-line interface for an end user

I add a parameter that developer can switch command line option for man page, if the option is on, user can do this:

    ./python foo.py --manpage

and open the manpage, but I think this isn't a good approach, since normal user will simply use `man foo.py`.

> generate a man page in a build script.
> Do you mean that the programmer should create a separate script for generating a man page and copy a part of the code from the main program? This workflow should be documented, with examples. And it is not applicable for simple one-file scripts.

I not sure if argparse need to provide a setuptools command, if need, the approach that Oz provide can be used, and developer only need to do like this in setup.py

    from argparser import build_manpage
    cmdclass={'build_manpage': build_manpage}

then at the command line, developer can build manpage as `./python setup.py build_manpage --output=foo.1 --parser=foo.parser`

If provide this is function too far for argparse, then as you said, a well-documented workflow should be provided.

----

Even if argparse provide this function, end-user still can't easily do the trick `man foo.py` or `man foo` if script point is provide in setup.py. If need to approach things like `man foo`, it may need to integrate with setuptools to put the man page file to the correct path (e.g. /usr/share/man/man1)
msg291883 - (view) Author: Zbyszek Jędrzejewski-Szmek (zbysz) * Date: 2017-04-19 12:35
If you can import the module that defines the parser, and get at the generated parser, this should be trivial to integrate with the build system. Something like:
   PYTHONPATH=. python3 -c 'import mymodule; p=mymodule.make_parser(); p.print_manpage(file="mymodule.1")'

This operation could either be done automatically during build always, or it could just be done by the developers and the man page put under version control.
History
Date User Action Args
2017-04-19 12:35:40zbyszsetmessages: + msg291883
2017-04-19 12:29:12louielusetmessages: + msg291882
2017-04-19 11:21:13serhiy.storchakasetmessages: + msg291879
2017-04-19 11:04:03louielusetmessages: + msg291877
2017-04-19 11:02:33louielusetfiles: + poc_2.py

messages: + msg291876
2017-04-19 10:44:00serhiy.storchakasetmessages: + msg291871
2017-04-19 10:13:26louielusetmessages: + msg291870
2017-04-19 08:02:19serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg291866
2017-04-18 14:28:06louielusetfiles: + poc.py
nosy: + louielu
messages: + msg291836

2017-04-18 14:19:03louielusetpull_requests: + pull_request1300
2017-01-10 00:54:07paul.j3setnosy: + paul.j3
2017-01-07 14:28:27matthewjohnsetnosy: + matthewjohn
2016-04-20 18:35:46acuccisetnosy: + acucci
messages: + msg263855
2016-04-19 19:27:52zbyszsetnosy: + zbysz
2016-03-08 19:45:50bignosesetversions: + Python 3.6, - Python 2.7
2016-03-08 19:45:39bignosesetnosy: + bignose
messages: + msg261371
2015-06-07 23:30:42bochechasetmessages: + msg244981
2015-06-07 23:00:19bochechasetnosy: + bochecha
2014-10-14 08:38:55josh.rsetnosy: + josh.r
2014-10-13 18:23:04Aaron.Meurersetnosy: + Aaron.Meurer
2014-06-13 22:02:52Oz.Tiramsetmessages: + msg220506
2014-06-12 20:09:24rhettingersetnosy: + rhettinger
messages: + msg220380
2014-06-11 17:57:18guettlisetnosy: - guettli
2014-06-11 17:13:26Oz.Tiramsetfiles: + build_manpage.py
versions: + Python 2.7, - Python 3.3
nosy: + Oz.Tiram

messages: + msg220288
2013-01-11 12:23:27guettlisetnosy: + guettli
2012-12-04 07:21:08sigisetnosy: + sigi
2012-06-12 18:41:36jwilksetnosy: + jwilk
2012-04-15 02:05:26adregnersetnosy: + adregner
2012-03-12 15:10:59Ingo.Fischersetnosy: + Ingo.Fischer
2012-02-25 08:57:06merwoksetmessages: + msg154216
2012-02-25 08:40:39andialbrechtsetnosy: + andialbrecht
2012-02-25 06:05:33merwoksetmessages: + msg154189
stage: needs patch
2012-02-24 18:04:54tshepangsetnosy: + tshepang
2012-02-24 09:53:04bethardsetmessages: + msg154125
2012-02-24 04:51:23merwoksetmessages: + msg154113
2012-02-24 04:50:59merwoksettitle: argparser should create a man page for me. -> argparse: add ability to create a man page
nosy: + merwok, bethard

messages: + msg154112

versions: + Python 3.3, - Python 2.7
components: + Library (Lib), - None
2012-02-23 21:15:59Daniel.Walshcreate