Is it possible to create subparameters in the django control command?

The name really says it all, but currently I have it, but it doesn't work:

class Command(BaseCommand): help = ("Functions related to downloading, parsing, and indexing the " "content") def add_arguments(self, parser): subparsers = parser.add_subparsers() download_parser = subparsers.add_parser( 'download', help='Using a local CSV, download the XML data for content. ' 'Output is sent to the log.' ) download_parser.add_argument( '--start_line', type=int, default=0, help='The line in the file where you wish to start processing.' ) # Add an argparse parser for parsing the content. Yes, this is # a bit confusing. content_parser_parser = subparsers.add_parser( 'parse', help="Look at the file system and parse everything you see so that " "we have content in the databse." ) content_parser_parser.add_argument( '--start_item', type=int, default=0, help="Assuming the content is sorted by file name, this item is " "the one to start on." ) 

My special idea is to create one command with subcommands to load XML content or to parse it into a database.

+5
source share
2 answers

It is possible, but it requires a little work:

 from django.core.management.base import BaseCommand, CommandParser class Command(BaseCommand): [...] def add_arguments(self, parser): cmd = self class SubParser(CommandParser): def __init__(self, **kwargs): super(SubParser, self).__init__(cmd, **kwargs) subparsers = parser.add_subparsers(title="subcommands", parser_class=SubParser) 

When you call add_subparsers by default, argparse creates a new parser that has the same class as the parser you called add_subparser . It so happens that the parser that you get in parser is an instance of CommandParser (defined in django.core.management.base ). The CommandParser class requires a cmd up to **kwargs (whereas the default parser class provided by argparse only accepts **kwargs ):

 def __init__(self, cmd, **kwargs): 

Therefore, when you try to add subparser, it fails because the constructor is only called with **kwargs and the cmd argument is missing.

The above code fixes the problem by passing a class in the parser_class argument that adds the missing parameter.

What to consider:

  • In the above code, I am creating a new class because the name parser_class assumes that what should be passed is a real class. However, this also works:

     def add_arguments(self, parser): cmd = self subparsers = parser.add_subparsers( title="subcommands", parser_class=lambda **kw: CommandParser(cmd, **kw)) 

    I am not running into any issues at this time, but it is possible that a change in argparse in the future could cause the lambda to fail, and not the real class. Since the argument is called parser_class , and not something like parser_maker or parser_manufacture , I believe that such a change should be an honest game.

  • Is it possible to simply pass one of the argparse stock argparse instead of passing the custom class to parser_class ? There would be no immediate problem, but there would be unintended consequences. The comments in CommandParser show that the behavior of the argparse stick parser is undesirable for Django commands. In particular, docstring for class states:

     """ Customized ArgumentParser class to improve some error messages and prevent SystemExit in several occasions, as SystemExit is unacceptable when a command is called programmatically. """ 

    This is the problem that Jerzyk answer suffers from. The solution here is to avoid this problem by getting from CommandParser and thus ensuring the correct behavior required by Django.

+7
source

you can add it and it was pretty simple:

 class Command(BaseCommand): help = 'dump/restore/diff' def add_arguments(self, parser): parser.add_argument('-s', '--server', metavar='server', type=str, help='server address') parser.add_argument('-d', '--debug', help='Print lots of debugging') subparsers = parser.add_subparsers(metavar='command', dest='command', help='sub-command help') subparsers.required = True parent_parser = argparse.ArgumentParser(add_help=False) parent_parser.add_argument('machine', metavar='device', type=str) parent_parser.add_argument('-e', '--errors', action='store_true') parser_dump = subparsers.add_parser('dump', parents=[parent_parser], cmd=self) parser_dump.add_argument('-i', '--indent', metavar='indent', type=int, default=None, help='file indentation') parser_restore = subparsers.add_parser('restore', parents=[parent_parser], cmd=self) parser_restore.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin) parser_diff = subparsers.add_parser('diff', parents=[parent_parser], cmd=self) parser_diff.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin) 
+1
source

Source: https://habr.com/ru/post/1247392/


All Articles