muscles-cli 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,778 @@
1
+ from __future__ import annotations
2
+ import typing
3
+ from typing import Any, Callable, Dict, List, cast
4
+ from functools import wraps
5
+ import os
6
+ import shutil
7
+ from .colory import Colors
8
+ from .func import argsparse, parse_arguments
9
+ from .cli import CliCommand
10
+
11
+
12
+ def print_help(instance):
13
+ """
14
+ Выводит подсказу в качестве результата работы команды
15
+
16
+ :param instance:
17
+ :return:
18
+ """
19
+ try:
20
+ size = shutil.get_terminal_size(fallback=(100, 50))
21
+ rows, columns = size.lines, size.columns
22
+ except:
23
+ rows = 50
24
+ columns = 100
25
+
26
+ def split_str(string, length):
27
+ if len(string) <= length:
28
+ yield string
29
+ else:
30
+ for i in range(0, len(string), length):
31
+ yield string[i:i + length].strip()
32
+
33
+ print(f"\n")
34
+ print(f"{Colors.WARNING}", "help - command list", f"{Colors.ENDC}")
35
+ print(f"{Colors.WARNING}", "<command_group> help - help with the command", f"{Colors.ENDC}")
36
+ print("\n")
37
+
38
+ if hasattr(instance, '_children'):
39
+ if isinstance(instance, Group) and instance.command_name != 'cli':
40
+ print(f"{Colors.HEADER}")
41
+ print("{command} - {description}".format(command=instance.command_name.ljust(20),
42
+ description=instance.description))
43
+ print(f"-" * 22)
44
+ print(f"{Colors.ENDC}")
45
+ print(" ") # Переводим каретку, хоть и нет явного, все же перевод будет осуществлен
46
+
47
+ for command in instance._children:
48
+ if isinstance(command, Command):
49
+ if command.description:
50
+ for (i, string) in enumerate(split_str(' '.join(command.description.split()), int(columns) - 23)):
51
+ if i == 0:
52
+ print("{command} - {description}".format(command=command.command_name.ljust(20),
53
+ description=string))
54
+ else:
55
+ print(' ' * 22, string.ljust(int(columns) - 23))
56
+ else:
57
+ print("{command} - {description}".format(command=command.command_name.ljust(20),
58
+ description='<Description not available>'))
59
+
60
+ for i, argument in enumerate(command.arguments):
61
+ arg = "{s1}{s2}{s3}{s4}{s5}".format(
62
+ s1='[' if argument.required else '',
63
+ s2=argument.argument,
64
+ s3=', ' if argument.short else '',
65
+ s4=argument.short if argument.short else '',
66
+ s5=']' if argument.required else ''
67
+ )
68
+ print("%s%s%s" % (
69
+ " ".ljust(1),
70
+ arg.ljust(20),
71
+ argument.description.ljust(int(columns) - 23)
72
+ ))
73
+
74
+ if isinstance(command, Group):
75
+ if command.description:
76
+ for (i, string) in enumerate(split_str(' '.join(command.description.split()), int(columns) - 23)):
77
+ if i == 0:
78
+ print("{command} - {description}".format(command=command.command_name.ljust(20),
79
+ description=string))
80
+ else:
81
+ print(' ' * 22, string.ljust(int(columns) - 23))
82
+ else:
83
+ print("{command} - {description}".format(command=command.command_name.ljust(20),
84
+ description='<Description not available>'))
85
+
86
+ print(" ") # Переводим каретку, хоть и нет явного, все же перевод будет осуществлен
87
+ else:
88
+ if instance.description is not None:
89
+ doc = instance.description
90
+ elif instance.handler.__doc__ is not None:
91
+ doc = instance.handler.__doc__
92
+ else:
93
+ doc = '<Description not available>'
94
+ print("{heads}{command}{heade}\n\n{description}".format(
95
+ heads=Colors.HEADER,
96
+ heade=Colors.ENDC,
97
+ command=instance.command_name.ljust(20),
98
+ description=doc))
99
+ print(f"\n\n- %s\n" % 'Arguments')
100
+ for i, argument in enumerate(instance.arguments):
101
+ arg = "{s1}{s2}{s3}{s4}{s5}".format(
102
+ s1='[' if argument.required else '',
103
+ s2=argument.argument,
104
+ s3=', ' if argument.short else '',
105
+ s4=argument.short if argument.short else '',
106
+ s5=']' if argument.required else ''
107
+ )
108
+ print("%s%s" % (
109
+ arg.ljust(20),
110
+ argument.description.ljust(int(columns) - 23)
111
+ ))
112
+
113
+ print(f"\n")
114
+ return True
115
+
116
+
117
+ class Command(CliCommand):
118
+ """
119
+ Класс для обработки консольных команд
120
+
121
+ """
122
+
123
+ def __init__(self, key: str | list[str] | None,
124
+ function_name: typing.Optional[str] = None,
125
+ handler: Callable[..., Any] | None = None,
126
+ description: str = '',
127
+ command_name: typing.Optional[str] = None):
128
+ """
129
+ Конструктор консольной команды
130
+
131
+ :param key: идентификатор консольной команды
132
+ :param function_name:
133
+ :param handler: Обработчик консольной команды
134
+ :param description: Текстовое описание команды
135
+ :param command_name: название консольной команды
136
+ """
137
+ if not key:
138
+ raise Exception('`key` not specified')
139
+ self._key = key if isinstance(key, list) else [key]
140
+ self._function_name = function_name
141
+ self._handler = handler
142
+ self._description = description
143
+ self._parent = None
144
+ self._command_name = command_name if command_name else '-'.join(self._key)
145
+ self._arguments = []
146
+
147
+ def __repr__(self):
148
+ return "Command(%s)" % ', '.join([
149
+ 'key=%s' % '/'.join(self.key),
150
+ 'function_name=%s' % self.function_name,
151
+ 'handler=%s' % "{}.{}".format(str(self.handler.__module__), str(self.handler.__name__)),
152
+ 'command_name=%s' % self.command_name,
153
+ ])
154
+
155
+ @property
156
+ def function_name(self) -> str:
157
+ return self._function_name or ""
158
+
159
+ @function_name.setter
160
+ def function_name(self, function_name) -> None:
161
+ self._function_name = function_name
162
+
163
+ @property
164
+ def handler(self) -> Callable[..., Any]:
165
+ if self._handler is None:
166
+ raise RuntimeError("Command handler is not configured")
167
+ return self._handler
168
+
169
+ @handler.setter
170
+ def handler(self, handler):
171
+ self._handler = handler
172
+
173
+ @property
174
+ def description(self) -> str:
175
+ return self._description
176
+
177
+ @description.setter
178
+ def description(self, description) -> None:
179
+ self._description = description
180
+
181
+ @property
182
+ def command_name(self) -> str:
183
+ return self._command_name
184
+
185
+ @command_name.setter
186
+ def command_name(self, command_name) -> None:
187
+ self._command_name = command_name
188
+
189
+ @property
190
+ def arguments(self) -> list[Argument]:
191
+ return self._arguments
192
+
193
+ @arguments.setter
194
+ def arguments(self, arguments) -> None:
195
+ self._arguments = arguments
196
+
197
+ def add_argument(self, argument: Argument) -> None:
198
+ """
199
+ Добавляет аргемент к консольной команде
200
+
201
+ :param argument: объект класса Argument
202
+ :return:
203
+ """
204
+ self._arguments.append(argument)
205
+
206
+ def add_arguments(self, arguments: list[Argument]) -> None:
207
+ """
208
+ Добавляет список аргументов к консольной команде
209
+
210
+ :param arguments: список объектов класса Argument
211
+ :return:
212
+ """
213
+ for argument in arguments:
214
+ self._arguments.append(argument)
215
+
216
+ def execute(self, *args, **_kwargs):
217
+ """
218
+ Запускает обработку консольной команды
219
+
220
+ """
221
+ handler = self.handler
222
+ handler_obj = cast(Any, handler)
223
+ if hasattr(handler_obj, 'arguments'):
224
+ arguments = handler_obj.arguments
225
+ else:
226
+ arguments = []
227
+ # args, kwargs = argsparse(arguments, args)
228
+ args, kwargs = parse_arguments(arguments, args)
229
+ kwargs.update(_kwargs)
230
+ params = {}
231
+ if hasattr(handler_obj, 'arguments'):
232
+ for argument in handler_obj.arguments:
233
+ params.update({argument.dest: kwargs.get(argument.dest, argument.default)})
234
+ result = handler(*args, **params)
235
+ return result
236
+
237
+
238
+ class Argument:
239
+ """
240
+ Клас обработки декоратов для установки возможных значений к консольным командам
241
+
242
+ """
243
+
244
+ _dest = None
245
+ _argument = None
246
+ _short = None
247
+ _required = False
248
+ _description = ''
249
+ _default = None
250
+ _multiple = False
251
+ _flag_value = False
252
+ _nargs = 0
253
+ _prompt = None
254
+ _value = None
255
+ _hide = None
256
+
257
+ def __init__(self,
258
+ argument: typing.Optional[str] = None,
259
+ short: typing.Optional[str] = None,
260
+ dest: typing.Optional[str] = None,
261
+ required: bool = False,
262
+ description: str = '',
263
+ default: Any = None,
264
+ multiple: bool = False,
265
+ flag_value: bool = False,
266
+ nargs: int = 0,
267
+ prompt: typing.Optional[str] = None,
268
+ hide: typing.Optional[bool] = None
269
+ ):
270
+ """
271
+ Конструктор объекта аргумента
272
+
273
+ :param argument: строка параметр аргумента для консольной команды
274
+ :param short: краткий параметр аргумента консольной команды
275
+ :param dest: название аргумента, которому будет передо значение аргумента из консольной команды
276
+ :param required: Истина, если аргумент обязательный
277
+ :param description: Описание аргумента
278
+ :param default: Значение по умолчанию
279
+ :param multiple: Если Истина то аргумент можно указать несколько раз в одной консольной команде
280
+ :param flag_value: Если Истина то наличие аргумента устанавливает параметр в Истину, а отсутствие означает Лож
281
+ :param nargs: Количество значений аргумента
282
+ :param prompt: Если указан, то в консоли при выполнении команды будет задан вопрос с текстом из параметра и
283
+ команда примет введенный пользователем аргумент в качестве значения
284
+ :param hide: Установите если значение аргумента должно быть скрыто
285
+ """
286
+ self._dest = dest
287
+ self._argument = argument
288
+ self._short = short
289
+ self._required = required
290
+ self._description = description
291
+ self._default = default
292
+ self._value = default
293
+ self._multiple = multiple
294
+ self._flag_value = flag_value
295
+ self._nargs = nargs
296
+ self._prompt = prompt
297
+ self._hide = hide
298
+
299
+ def __repr__(self):
300
+ return "Argument(%s)" % ', '.join([
301
+ 'argument=%s' % self.argument,
302
+ 'short=%s' % self.short,
303
+ 'dest=%s' % self.dest,
304
+ 'required=%s' % self.required,
305
+ 'default=%s' % self.default,
306
+ 'multiple=%s' % self.multiple,
307
+ 'flag_value=%s' % self.flag_value,
308
+ 'nargs=%s' % self.nargs,
309
+ # 'prompt=%s' % self.prompt,
310
+ 'hide=%s' % self.hide,
311
+ ])
312
+
313
+ @property
314
+ def value(self) -> Any:
315
+ return self._value
316
+
317
+ @value.setter
318
+ def value(self, value) -> None:
319
+ self._value = value
320
+
321
+ @property
322
+ def dest(self) -> str:
323
+ arg = self._argument or self._short or ""
324
+ dest = arg.replace("-", "")
325
+ return self._dest or dest
326
+
327
+ @dest.setter
328
+ def dest(self, dest) -> None:
329
+ if dest:
330
+ self._dest = dest
331
+
332
+ @property
333
+ def argument(self) -> str:
334
+ return self._argument or ""
335
+
336
+ @argument.setter
337
+ def argument(self, argument: str) -> None:
338
+ if not argument:
339
+ return
340
+ if argument[0:2] == '--':
341
+ dest = argument[2:]
342
+ elif argument[0:1] == '-':
343
+ dest = argument[1:]
344
+ else:
345
+ raise Exception("Argument %s must start with -- or -" % argument)
346
+ self.dest = dest
347
+ self._argument = argument
348
+
349
+ @property
350
+ def short(self) -> str:
351
+ return self._short or ""
352
+
353
+ @short.setter
354
+ def short(self, short: str | None) -> None:
355
+ self._short = short
356
+
357
+ @property
358
+ def prompt(self) -> str | None:
359
+ return self._prompt
360
+
361
+ @prompt.setter
362
+ def prompt(self, prompt: str | None) -> None:
363
+ if prompt and self._nargs <= 0:
364
+ self._nargs = 1
365
+ self._prompt = prompt
366
+
367
+ @property
368
+ def required(self) -> bool:
369
+ return self._required
370
+
371
+ @required.setter
372
+ def required(self, required: bool) -> None:
373
+ self._required = required
374
+
375
+ @property
376
+ def description(self) -> str:
377
+ return self._description
378
+
379
+ @description.setter
380
+ def description(self, description) -> None:
381
+ self._description = description
382
+
383
+ @property
384
+ def default(self):
385
+ return self._default
386
+
387
+ @default.setter
388
+ def default(self, default) -> None:
389
+ self._default = default
390
+
391
+ @property
392
+ def multiple(self) -> bool:
393
+ return self._multiple if self._multiple else False
394
+
395
+ @multiple.setter
396
+ def multiple(self, multiple: bool) -> None:
397
+ self._multiple = multiple
398
+
399
+ @property
400
+ def hide(self):
401
+ return self._hide
402
+
403
+ @hide.setter
404
+ def hide(self, hide) -> None:
405
+ if hide:
406
+ self.nargs = 1
407
+ self._hide = hide
408
+
409
+ @property
410
+ def flag_value(self):
411
+ return True if self._flag_value else False
412
+
413
+ @flag_value.setter
414
+ def flag_value(self, flag_value) -> None:
415
+ self._flag_value = flag_value
416
+
417
+ @property
418
+ def nargs(self) -> int:
419
+ return self._nargs
420
+
421
+ @nargs.setter
422
+ def nargs(self, nargs: int) -> None:
423
+ self._nargs = nargs
424
+
425
+
426
+ class Group(CliCommand):
427
+ """
428
+ Класс для работы с группами консольных команд
429
+
430
+ """
431
+
432
+ _commands: Dict[str, Any] = {}
433
+
434
+ def __init__(self,
435
+ key: str | list[str] | None = None,
436
+ function_name: str | None = None,
437
+ handler: Callable[..., Any] | None = None,
438
+ description: str = '',
439
+ command_name: typing.Optional[str] = None
440
+ ):
441
+ """
442
+ Конструктор объекта группы
443
+
444
+ :param key: идентификатор группы
445
+ :param function_name:
446
+ :param handler: обработчик группы
447
+ :param description: описание группы
448
+ :param command_name: название команды группы
449
+ """
450
+ key_parts = key if isinstance(key, list) else ([key] if key else [])
451
+ self._children: list[Command | Group] = []
452
+ self._key = key_parts
453
+ self._function_name = function_name
454
+ self._handler = handler
455
+ self._description = description
456
+ self._parent = None
457
+ self._command_name = command_name if command_name else '-'.join(key_parts)
458
+ self._arguments: list[Argument] = []
459
+ self._children_by_command: dict[str, Command | Group] = {}
460
+
461
+ def __repr__(self):
462
+ return "Group(%s)" % ', '.join([
463
+ 'key=%s' % '/'.join(self.key),
464
+ 'function_name=%s' % self.function_name,
465
+ 'handler=%s' % "{}.{}".format(str(self.handler.__module__), str(self.handler.__name__)),
466
+ 'command_name=%s' % self.command_name,
467
+ 'arguments=%s' % self.arguments,
468
+ 'arguments=%s' % cast(Any, self.handler).arguments if hasattr(self.handler, 'arguments') else '[]',
469
+ ])
470
+
471
+ @property
472
+ def function_name(self) -> str:
473
+ return self._function_name or ""
474
+
475
+ @function_name.setter
476
+ def function_name(self, function_name) -> None:
477
+ self._function_name = function_name
478
+
479
+ @property
480
+ def handler(self) -> Callable[..., Any]:
481
+ if self._handler is None:
482
+ raise RuntimeError("Group handler is not configured")
483
+ return self._handler
484
+
485
+ @handler.setter
486
+ def handler(self, handler):
487
+ self._handler = handler
488
+
489
+ @property
490
+ def arguments(self) -> list[Argument]:
491
+ return self._arguments
492
+
493
+ @arguments.setter
494
+ def arguments(self, arguments) -> None:
495
+ self._arguments = arguments
496
+
497
+ @property
498
+ def description(self) -> str:
499
+ return self._description
500
+
501
+ @description.setter
502
+ def description(self, description) -> None:
503
+ self._description = description
504
+
505
+ @property
506
+ def command_name(self) -> str:
507
+ return self._command_name
508
+
509
+ @command_name.setter
510
+ def command_name(self, command_name) -> None:
511
+ self._command_name = command_name
512
+
513
+ def add(self, command: Command | Group) -> None:
514
+ """
515
+ Добавляет к группе новую команду или другую группу
516
+
517
+ :param command: объект группы или команды
518
+ :return:
519
+ """
520
+ self._children.append(command)
521
+ self._children_by_command[command.command_name] = command
522
+ command.parent = self
523
+
524
+ def remove(self, command: Command | Group) -> None:
525
+ """
526
+ Удаляет из группы команду или другую группу
527
+
528
+ :param command: объект группы или команды
529
+ :return:
530
+ """
531
+ self._children.remove(command)
532
+ self._children_by_command.pop(command.command_name, None)
533
+ command.parent = None
534
+
535
+ def execute(self, *args, **_kwargs):
536
+ """
537
+ Запускает выполнение обработчика группы
538
+
539
+ :param args:
540
+ :param _kwargs:
541
+ :return:
542
+ """
543
+ if hasattr(self.handler, 'arguments'):
544
+ arguments = cast(Any, self.handler).arguments
545
+ else:
546
+ arguments = []
547
+ if isinstance(args, str):
548
+ args = [args]
549
+ # args, kwargs = argsparse(arguments, args)
550
+ args, kwargs = parse_arguments(arguments, args)
551
+ kwargs.update(_kwargs)
552
+ if len(args) >= 1 and isinstance(args[0], str) and args[0].startswith('-'):
553
+ raise ValueError(f"Invalid argument: {args[0]}")
554
+ params = {}
555
+ if hasattr(self.handler, 'arguments'):
556
+ for argument in cast(Any, self.handler).arguments:
557
+ params.update({argument.dest: kwargs.get(argument.dest, argument.default)})
558
+ result = self.handler(*args, **params)
559
+ if len(args) >= 1:
560
+ command = self._children_by_command.get(args[0])
561
+ if command:
562
+ return command.execute(*args[1:], **kwargs)
563
+ print(f"\n")
564
+
565
+ if len(args[0]) > 0:
566
+ raise Exception("Command `%s` not found" % args[0])
567
+ return result
568
+
569
+ def help(self, *args, **kwargs):
570
+ """
571
+ Устанавливает команду вывода помощи для подсказок по группе
572
+
573
+ :param args:
574
+ :param kwargs:
575
+ :return:
576
+ """
577
+ self._help(args[:-1], self)
578
+
579
+ def _help(self, args, command):
580
+ if len(args) > 0:
581
+ args, _command = args[1:] if len(args[1:]) > 0 else [], args[0:1][0] if len(args[0:1]) > 0 else None
582
+ if hasattr(command, '_children_by_command') and _command in command._children_by_command:
583
+ self._help(args, command._children_by_command[_command])
584
+ else:
585
+ return print_help(command)
586
+
587
+ def _default_func_prop(self, func):
588
+ if not hasattr(func, 'arguments'):
589
+ setattr(func, 'arguments', [])
590
+ if not hasattr(func, 'command'):
591
+ setattr(func, 'command', None)
592
+ if not hasattr(func, 'group'):
593
+ setattr(func, 'group', None)
594
+
595
+ def command(self, command_name: typing.Union[str, None] = None, description: typing.Union[str, None] = "-"):
596
+ """
597
+ Декоратор устанавливающий функцию как обработчик команды
598
+
599
+ :param command_name: Название команды
600
+ :param description: Описание
601
+ :return:
602
+ """
603
+
604
+ def decorator(func):
605
+ self._default_func_prop(func)
606
+ func_obj = cast(Any, func)
607
+ key = [func.__name__] + self.key
608
+ _command = Command(key)
609
+ _command.command_name = command_name if command_name else func.__name__
610
+ _command.description = description if description is not None else func.__doc__
611
+ _command.function_name = func.__name__
612
+ _command.handler = func
613
+ _command.add_arguments(func_obj.arguments)
614
+ self.add(_command)
615
+ # _command = commandFactory.update(key, _command)
616
+ setattr(func, 'command', _command)
617
+
618
+ @wraps(func)
619
+ def wrapper(*args, **kwargs):
620
+ return func(*args, **kwargs)
621
+
622
+ wrapper.__name__ = func.__name__
623
+ wrapper.__doc__ = func.__doc__
624
+ return wrapper
625
+
626
+ return decorator
627
+
628
+ def group(self, description=None, command_name=None):
629
+ """
630
+ Декоратор устанавливающий функцию как обработчик группы команд
631
+
632
+ :param description: описание
633
+ :param command_name: название команды
634
+ :return:
635
+ """
636
+
637
+ def decorator(func):
638
+ self._default_func_prop(func)
639
+ func_obj = cast(Any, func)
640
+ key = [func.__name__] + self.key
641
+ _group = Group(key)
642
+ _group.command_name = command_name if command_name else func.__name__
643
+ _group.function_name = func.__name__
644
+ _group.description = description if description is not None else func.__doc__
645
+ _group.handler = func
646
+ setattr(func_obj, 'group', _group)
647
+ self.add(_group)
648
+
649
+ # key = ['help'] + _group.key
650
+ key = _group.key + ['help']
651
+ _command = Command(key)
652
+ _command.function_name = _group.help.__name__
653
+ _command.handler = _group.help
654
+ _command.command_name = 'help'
655
+ _command.description = "Command list for %s" % _group.command_name
656
+
657
+ _group.add(_command)
658
+
659
+ @wraps(func)
660
+ def wrapper(*args, **kwargs):
661
+ return func(*args, **kwargs)
662
+
663
+ wrapper.__name__ = func.__name__
664
+ wrapper.__doc__ = func.__doc__
665
+ return _group
666
+
667
+ return decorator
668
+
669
+ def argument(self, argument, short=None, description='', required=False, default=None,
670
+ multiple=False, flag_value=False, dest=None, nargs=0, prompt=None, hide=False):
671
+ """
672
+ Декоратор устанавливающий к функции определенной декоратором группы или команды новые аргументы
673
+
674
+ :param argument: строка параметр аргумента для консольной команды
675
+ :param short: краткий параметр аргумента консольной команды
676
+ :param dest: название аргумента, которому будет передо значение аргумента из консольной команды
677
+ :param required: Истина, если аргумент обязательный
678
+ :param description: Описание аргумента
679
+ :param default: Значение по умолчанию
680
+ :param multiple: Если Истина то аргумент можно указать несколько раз в одной консольной команде
681
+ :param flag_value: Если Истина то наличие аргумента устанавливает параметр в Истину, а отсутствие означает Лож
682
+ :param nargs: Количество значений аргумента
683
+ :param prompt: Если указан, то в консоли при выполнении команды будет задан вопрос с текстом из параметра и
684
+ команда примет введенный пользователем аргумент в качестве значения
685
+ :param hide: Установите если значение аргумента должно быть скрыто
686
+ :return:
687
+ """
688
+
689
+ def decorator(func):
690
+ self._default_func_prop(func)
691
+ func_obj = cast(Any, func)
692
+ _argument = Argument(
693
+ argument=argument,
694
+ short=short,
695
+ description=description,
696
+ required=required,
697
+ default=False if flag_value is True and default is None else default,
698
+ multiple=multiple,
699
+ dest=dest,
700
+ flag_value=flag_value,
701
+ nargs=nargs,
702
+ prompt=prompt,
703
+ hide=hide
704
+ )
705
+ # _argument.argument = argument
706
+ # _argument.short = short
707
+ # _argument.description = description
708
+ # _argument.required = required
709
+ # _argument.default = default
710
+ # _argument.multiple = multiple
711
+ # _argument.dest = dest
712
+ # _argument.flag_value = flag_value
713
+ # _argument.nargs = nargs
714
+ # _argument.prompt = prompt
715
+ # _argument.hide = hide
716
+
717
+ if _argument.required and _argument.nargs <= 0:
718
+ _argument.nargs = 1
719
+
720
+ func_obj.arguments.append(_argument)
721
+ self.arguments = getattr(func_obj, 'arguments')
722
+
723
+ @wraps(func)
724
+ def wrapper(*args, **kwargs):
725
+ # signature = inspect.signature(func)
726
+ # params = signature.parameters
727
+ # must_have_kwargs = {}
728
+ # for name, param in params.items():
729
+ # must_have_kwargs[name] = param.default
730
+ # if len(must_have_kwargs) != len(kwargs):
731
+ # raise Exception(locale('Количество переданных параметров отличается от количества запрошенных'))
732
+ return func(*args, **kwargs)
733
+
734
+ wrapper.__name__ = func.__name__
735
+ wrapper.__doc__ = func.__doc__
736
+ return wrapper
737
+
738
+ return decorator
739
+
740
+ def flag(self, argument, short=None, description='', dest=None, default=False, flag_value=True):
741
+ """
742
+ Декоратор устанавливающий к функции определенной как декоратором группы или команды новый лаг
743
+
744
+ :param argument: строка параметр аргумента для консольной команды
745
+ :param short: краткий параметр аргумента консольной команды
746
+ :param dest: название аргумента, которому будет передо значение аргумента из консольной команды
747
+ :param description: Описание аргумента
748
+ :param default: Значение по умолчанию
749
+ :param flag_value: Если Истина то наличие аргумента устанавливает параметр в Истину, а отсутствие означает Лож
750
+ :return:
751
+ """
752
+
753
+ def decorator(func):
754
+ self._default_func_prop(func)
755
+ func_obj = cast(Any, func)
756
+ _argument = Argument()
757
+ _argument.argument = argument
758
+ _argument.short = short
759
+ _argument.description = description
760
+ _argument.required = False
761
+ _argument.default = default
762
+ _argument.multiple = False
763
+ _argument.dest = dest
764
+ _argument.flag_value = flag_value
765
+ _argument.nargs = 0
766
+ _argument.prompt = None
767
+ func_obj.arguments.append(_argument)
768
+ self.arguments = func_obj.arguments
769
+
770
+ @wraps(func)
771
+ def wrapper(*args, **kwargs):
772
+ return func(*args, **kwargs)
773
+
774
+ wrapper.__name__ = func.__name__
775
+ wrapper.__doc__ = func.__doc__
776
+ return wrapper
777
+
778
+ return decorator