2015-08-16 3 views
6

Я пытаюсь использовать Django's call_command способом, очень похожим на this question without an answer.Требуется аргумент call_command

Как я звоню это:

args = [] 
    kwargs = { 
     'solr_url': 'http://127.0.0.1:8983/solr/collection1', 
     'type': 'opinions', 
     'update': True, 
     'everything': True, 
     'do_commit': True, 
     'traceback': True, 
    } 
    call_command('cl_update_index', **kwargs) 

В теории, это должно работать, в соответствии с the docs. Но это не работает, просто нет.

Здесь пока это add_arguments метод для моего класса Command:

def add_arguments(self, parser): 
    parser.add_argument(
     '--type', 
     type=valid_obj_type, 
     required=True, 
     help='Because the Solr indexes are loosely bound to the database, ' 
      'commands require that the correct model is provided in this ' 
      'argument. Current choices are "audio" or "opinions".' 
    ) 
    parser.add_argument(
     '--solr-url', 
     required=True, 
     type=str, 
     help='When swapping cores, it can be valuable to use a temporary ' 
      'Solr URL, overriding the default value that\'s in the ' 
      'settings, e.g., http://127.0.0.1:8983/solr/swap_core' 
    ) 

    actions_group = parser.add_mutually_exclusive_group() 
    actions_group.add_argument(
     '--update', 
     action='store_true', 
     default=False, 
     help='Run the command in update mode. Use this to add or update ' 
      'items.' 
    ) 
    actions_group.add_argument(
     '--delete', 
     action='store_true', 
     default=False, 
     help='Run the command in delete mode. Use this to remove items ' 
      'from the index. Note that this will not delete items from ' 
      'the index that do not continue to exist in the database.' 
    ) 
    parser.add_argument(
     '--optimize', 
     action='store_true', 
     default=False, 
     help='Run the optimize command against the current index after ' 
      'any updates or deletions are completed.' 
    ) 
    parser.add_argument(
     '--do-commit', 
     action='store_true', 
     default=False, 
     help='Performs a simple commit and nothing more.' 
    ) 

    act_upon_group = parser.add_mutually_exclusive_group() 
    act_upon_group.add_argument(
     '--everything', 
     action='store_true', 
     default=False, 
     help='Take action on everything in the database', 
    ) 
    act_upon_group.add_argument(
     '--query', 
     help='Take action on items fulfilling a query. Queries should be ' 
      'formatted as Python dicts such as: "{\'court_id\':\'haw\'}"' 
    ) 
    act_upon_group.add_argument(
     '--items', 
     type=int, 
     nargs='*', 
     help='Take action on a list of items using a single ' 
      'Celery task' 
    ) 
    act_upon_group.add_argument(
     '--datetime', 
     type=valid_date_time, 
     help='Take action on items newer than a date (YYYY-MM-DD) or a ' 
      'date and time (YYYY-MM-DD HH:MM:SS)' 
    ) 

Независимо от того, что я делаю здесь, я получаю:

CommandError: Error: argument --type is required

Любые идеи? Если вам действительно интересно, вы можете see the entire code here.

+0

action = store_true и default = False противоречат друг другу. 'store_true' является псевдонимом для' store_const' с 'const = True' – Incognos

ответ

10

Вы определили аргумент с флагом '--type' и сделали его required. Для этой командной строки потребуется строка или строки, которые выглядят как --type avalue.

Это выглядит как соответствующая часть call_command:

def call_command(name, *args, **options): 
    .... 
    parser = command.create_parser('', name) 
    if command.use_argparse: 
     # Use the `dest` option name from the parser option 
     opt_mapping = {sorted(s_opt.option_strings)[0].lstrip('-').replace('-', '_'): s_opt.dest 
         for s_opt in parser._actions if s_opt.option_strings} 
     arg_options = {opt_mapping.get(key, key): value for key, value in options.items()} 
     defaults = parser.parse_args(args=args) 
     defaults = dict(defaults._get_kwargs(), **arg_options) 
     # Move positional args out of options to mimic legacy optparse 
     args = defaults.pop('args',()) 

Это создает парсер, используя его собственные аргументы, плюс те, которые вы добавляете.

parser._actions if s_opt.option_strings - это аргументы (действия), которые принимают флаг опции (начинаются с - или -). opt_mapping - это карта между строками флага (минус ведущая -s) и атрибутом «dest».

arg_options преобразует ваш **kwargs в нечто, что можно объединить с выходом parser.

defaults = parser.parse_args(args=args) действительно ли синтаксический анализ. То есть, это единственный код, который фактически использует механизм разбора argparse. Таким образом, часть вашего вызова имитирует генерацию sys.argv[1:] от интерактивного вызова.

Исходя из этого чтения я думаю, что это должно работать:

args = [ 
    '--solr-url', 'http://127.0.0.1:8983/solr/collection1', 
    '--type', 'opinions', 
    '--update' 
    '--everything', 
    '--do_commit', 
    '--traceback', 
} 
call_command('cl_update_index', *args) 

Вместо **kwargs я передаю значений в виде списка строк. Или два требуется аргументы могут быть переданы в args, а остальное в **kwargs.

args = ['--solr-url', 'http://127.0.0.1:8983/solr/collection1', 
    '--type', 'opinions'] 
kwargs = { 
    'update': True, 
    'everything': True, 
    'do_commit': True, 
    'traceback': True, 
} 
call_command('cl_update_index', *args, **kwargs) 

Если аргумент required он должен прошли через *args. **kwargs обходит синтаксический анализатор, заставляя его оспаривать отсутствующие аргументы.


Я скачал последнюю django, но еще не установили его.Но вот симуляция call_command, который должен проверить параметры вызова:

import argparse 

def call_command(name, *args, **options): 
    """ 
    Calls the given command, with the given options and args/kwargs. 
    standalone simulation of django.core.mangement call_command 
    """ 
    command = name 
    """ 
    .... 
    """ 
    # Simulate argument parsing to get the option defaults (see #10080 for details). 
    parser = command.create_parser('', name) 
    if command.use_argparse: 
     # Use the `dest` option name from the parser option 
     opt_mapping = {sorted(s_opt.option_strings)[0].lstrip('-').replace('-', '_'): s_opt.dest 
         for s_opt in parser._actions if s_opt.option_strings} 
     arg_options = {opt_mapping.get(key, key): value for key, value in options.items()} 
     defaults = parser.parse_args(args=args) 
     defaults = dict(defaults._get_kwargs(), **arg_options) 
     # Move positional args out of options to mimic legacy optparse 
     args = defaults.pop('args',()) 
    else: 
     # Legacy optparse method 
     defaults, _ = parser.parse_args(args=[]) 
     defaults = dict(defaults.__dict__, **options) 
    if 'skip_checks' not in options: 
     defaults['skip_checks'] = True 

    return command.execute(*args, **defaults) 

class BaseCommand(): 
    def __init__(self): 
     self.use_argparse = True 
     self.stdout= sys.stdout 
     self.stderr=sys.stderr 
    def execute(self, *args, **kwargs): 
     self.handle(*args, **kwargs) 
    def handle(self, *args, **kwargs): 
     print('args: ', args) 
     print('kwargs: ', kwargs) 
    def create_parser(self, *args, **kwargs): 
     parser = argparse.ArgumentParser() 
     self.add_arguments(parser) 
     return parser 
    def add_arguments(self, parser): 
     parser.add_argument('--type', required=True) 
     parser.add_argument('--update', action='store_true') 
     parser.add_argument('--optional', default='default') 
     parser.add_argument('foo') 
     parser.add_argument('args', nargs='*') 

if __name__=='__main__': 

    testcmd = BaseCommand() 
    # testcmd.execute('one','tow', three='four') 

    call_command(testcmd, '--type','typevalue','foovalue', 'argsvalue', update=True) 

    args = ['--type=argvalue', 'foovalue', '1', '2'] 
    kwargs = { 
     'solr_url': 'http://127.0.0.1...', 
     'type': 'opinions', 
     'update': True, 
     'everything': True, 
    } 
    call_command(testcmd, *args, **kwargs) 

, который производит:

python3 stack32036562.py 
args: ('argsvalue',) 
kwargs: {'optional': 'default', 'type': 'typevalue', 'update': True, 'skip_checks': True, 'foo': 'foovalue'} 
args: ('1', '2') 
kwargs: {'optional': 'default', 'update': True, 'foo': 'foovalue', 'type': 'opinions', 'skip_checks': True, 'everything': True, 'solr_url': 'http://127.0.0.1...'} 

С кучей окурков, я могу сделать свою clCommand работы с моим BaseCommand, и следующая телефонные переговоры:

clupdate = Command() 
args = ['--type','opinions','--solr-url','dummy'] 
kwargs = { 
    'solr_url': 'http://127.0.0.1:8983/solr/collection1', 
    #'type': 'opinions', 
    'update': True, 
    'everything': True, 
    'do_commit': True, 
    'traceback': True, 
} 
call_command(clupdate, *args, **kwargs) 

Выполнение заглушки everything.

Running in update mode... 
everything 
args: () 
options: {'type': 'opinions', 'query': None, 'solr_url': 'http://127.0.0.1:8983/solr/collection1', 'items': None, 'do_commit': True, 'update': True, 'delete': False, 'datetime': None, 'optimize': False, 'skip_checks': True, 'everything': True, 'traceback': True} 
+0

Да, документы не велики, но я пробовал в обоих направлениях. – mlissner

+1

Основываясь на чтении кода 'django', я думаю, что' обязательные' аргументы должны быть заданы с помощью '* args', а не' ** kwargs'. – hpaulj

+0

Отличный ответ, хотя я все еще не мог ничего передать как диктофон. Даже материал, который вы сказали *, должен * работать? Не работает. Только так это работает для меня, это передать все как список. – mlissner

Смежные вопросы