summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Leonhardt <todd.leonhardt@gmail.com>2018-10-06 19:07:00 -0400
committerTodd Leonhardt <todd.leonhardt@gmail.com>2018-10-06 19:07:00 -0400
commite018924a28443e8e6f608d9b9796b2b826653490 (patch)
tree5dee77d4ae99e99f71b1fba1a33a206c5933f903
parenta77be185c245e4cd04fe348e050a177b9b327471 (diff)
downloadcmd2-git-e018924a28443e8e6f608d9b9796b2b826653490.tar.gz
Added documentation stating that parsers passed to argparse decorators need to be unique
Also: - Modified table_display.py to demonstrate a workaround
-rw-r--r--cmd2/cmd2.py4
-rw-r--r--docs/argument_processing.rst16
-rwxr-xr-xexamples/table_display.py26
3 files changed, 33 insertions, 13 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 4502c53a..c000fb80 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -193,7 +193,7 @@ def with_argparser_and_unknown_args(argparser: argparse.ArgumentParser, preserve
"""A decorator to alter a cmd2 method to populate its ``args`` argument by parsing arguments with the given
instance of argparse.ArgumentParser, but also returning unknown args as a list.
- :param argparser: given instance of ArgumentParser
+ :param argparser: unique instance of ArgumentParser
:param preserve_quotes: if True, then the arguments passed to arparse be maintain their quotes
:return: function that gets passed parsed args and a list of unknown args
"""
@@ -234,7 +234,7 @@ def with_argparser(argparser: argparse.ArgumentParser, preserve_quotes: bool=Fal
"""A decorator to alter a cmd2 method to populate its ``args`` argument by parsing arguments
with the given instance of argparse.ArgumentParser.
- :param argparser: given instance of ArgumentParser
+ :param argparser: unique instance of ArgumentParser
:param preserve_quotes: if True, then the arguments passed to arparse be maintain their quotes
:return: function that gets passed parsed args
"""
diff --git a/docs/argument_processing.rst b/docs/argument_processing.rst
index 8aed7498..9d13a7c8 100644
--- a/docs/argument_processing.rst
+++ b/docs/argument_processing.rst
@@ -25,10 +25,10 @@ Using the argument parser decorator
===================================
For each command in the ``cmd2`` subclass which requires argument parsing,
-create an instance of ``argparse.ArgumentParser()`` which can parse the
+create a unique instance of ``argparse.ArgumentParser()`` which can parse the
input appropriately for the command. Then decorate the command method with
the ``@with_argparser`` decorator, passing the argument parser as the
-first parameter to the decorator. This changes the second argumen to the command method, which will contain the results
+first parameter to the decorator. This changes the second argument to the command method, which will contain the results
of ``ArgumentParser.parse_args()``.
Here's what it looks like::
@@ -54,6 +54,16 @@ Here's what it looks like::
for i in range(min(repetitions, self.maxrepeats)):
self.poutput(arg)
+.. warning::
+
+ It is important that each command which uses the ``@with_argparser`` decorator be passed a unique instance of a
+ parser. This limitation is due to bugs in CPython prior to Python 3.7 which make it impossible to make a deep copy
+ of an instance of a ``argparse.ArgumentParser``.
+
+ See the table_display_ example for a work-around that demonstrates how to create a function which returns a unique
+ instance of the parser you want.
+
+
.. note::
The ``@with_argparser`` decorator sets the ``prog`` variable in
@@ -61,6 +71,8 @@ Here's what it looks like::
This will override anything you specify in ``prog`` variable when
creating the argument parser.
+.. _table_display: https://github.com/python-cmd2/cmd2/blob/master/examples/table_display.py
+
Help Messages
=============
diff --git a/examples/table_display.py b/examples/table_display.py
index 63447377..7541e548 100755
--- a/examples/table_display.py
+++ b/examples/table_display.py
@@ -11,7 +11,6 @@ You can quit out of the pager by typing "q". You can also search for text withi
WARNING: This example requires the tableformatter module: https://github.com/python-tableformatter/tableformatter
- pip install tableformatter
"""
-import argparse
from typing import Tuple
import cmd2
@@ -142,6 +141,21 @@ def high_density_objs(row_obj: CityInfo) -> dict:
return opts
+def make_table_parser() -> cmd2.argparse_completer.ACArgumentParser:
+ """Create a unique instance of an argparse Argument parser for processing table arguments.
+
+ NOTE: The two cmd2 argparse decorators require that each parser be unique, even if they are essentially a deep copy
+ of each other. For cases like that, you can create a function to return a unique instance of a parser, which is
+ what is being done here.
+ """
+ table_parser = cmd2.argparse_completer.ACArgumentParser()
+ table_item_group = table_parser.add_mutually_exclusive_group()
+ table_item_group.add_argument('-c', '--color', action='store_true', help='Enable color')
+ table_item_group.add_argument('-f', '--fancy', action='store_true', help='Fancy Grid')
+ table_item_group.add_argument('-s', '--sparse', action='store_true', help='Sparse Grid')
+ return table_parser
+
+
class TableDisplay(cmd2.Cmd):
"""Example cmd2 application showing how you can display tabular data."""
@@ -169,18 +183,12 @@ class TableDisplay(cmd2.Cmd):
formatted_table = tf.generate_table(rows=rows, columns=columns, grid_style=grid, row_tagger=row_stylist)
self.ppaged(formatted_table, chop=True)
- table_parser = argparse.ArgumentParser()
- table_item_group = table_parser.add_mutually_exclusive_group()
- table_item_group.add_argument('-c', '--color', action='store_true', help='Enable color')
- table_item_group.add_argument('-f', '--fancy', action='store_true', help='Fancy Grid')
- table_item_group.add_argument('-s', '--sparse', action='store_true', help='Sparse Grid')
-
- @cmd2.with_argparser(table_parser)
+ @cmd2.with_argparser(make_table_parser())
def do_table(self, args):
"""Display data in iterable form on the Earth's most populated cities in a table."""
self.ptable(EXAMPLE_ITERABLE_DATA, COLUMNS, args, high_density_tuples)
- @cmd2.with_argparser(table_parser)
+ @cmd2.with_argparser(make_table_parser())
def do_object_table(self, args):
"""Display data in object form on the Earth's most populated cities in a table."""
self.ptable(EXAMPLE_OBJECT_DATA, OBJ_COLS, args, high_density_objs)