2020-07-20 01:54:26 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
# -*- encoding: utf-8 -*-
|
|
|
|
|
|
|
|
import re
|
|
|
|
from inspect import _empty, getfullargspec, signature
|
|
|
|
from typing import Callable, Dict, List, Optional, Set, Type, TypeVar
|
2020-11-06 00:08:05 +00:00
|
|
|
import colored as clrlib
|
2020-07-20 01:54:26 +00:00
|
|
|
|
|
|
|
from .table_fmt import table_fmt
|
|
|
|
|
|
|
|
SPLITTER_RGX = re.compile(r'(?<!\~):')
|
|
|
|
|
|
|
|
|
|
|
|
def unescape_after_splitter(txt: str) -> str:
|
|
|
|
return txt.replace('~:', ':')
|
|
|
|
|
|
|
|
|
|
|
|
T = TypeVar('T')
|
|
|
|
|
|
|
|
|
|
|
|
def parse_cmdline(func: Callable[..., T], encoded_args: str) -> Optional[T]:
|
|
|
|
'''
|
|
|
|
Transforms a colon-separated key-pairs into callable arguments
|
|
|
|
|
|
|
|
Type-annotated fields will be converted.
|
|
|
|
'''
|
|
|
|
split_args = SPLITTER_RGX.split(encoded_args)
|
|
|
|
split_args = list(map(unescape_after_splitter, split_args))
|
|
|
|
brute_dict = dict(zip(split_args[0::2], split_args[1::2]))
|
|
|
|
full_arg_spec = getfullargspec(func)
|
|
|
|
sig = signature(func)
|
|
|
|
func_args = full_arg_spec.args
|
|
|
|
func_annotations = full_arg_spec.annotations
|
|
|
|
str_args = {k: v
|
|
|
|
for k, v in
|
|
|
|
brute_dict.items()
|
|
|
|
if k in func_args}
|
|
|
|
unknown_args = {k: v
|
|
|
|
for k, v in
|
|
|
|
brute_dict.items()
|
|
|
|
if k not in func_args}
|
|
|
|
if encoded_args == 'help' or len(unknown_args) > 0:
|
|
|
|
if len(unknown_args) > 0:
|
2020-11-06 00:08:05 +00:00
|
|
|
print(clrlib.stylize('Unknown arguments found:', [
|
|
|
|
clrlib.fg('light_red'),
|
|
|
|
clrlib.attr('bold'),
|
|
|
|
]))
|
2020-07-20 01:54:26 +00:00
|
|
|
for k, v in unknown_args.items():
|
2020-11-06 00:08:05 +00:00
|
|
|
print(clrlib.stylize(f' {k}: {repr(v)}', [
|
|
|
|
clrlib.fg('light_red'),
|
|
|
|
]))
|
2020-07-20 01:54:26 +00:00
|
|
|
print()
|
2020-11-06 00:08:05 +00:00
|
|
|
print(clrlib.stylize(f'Usage help for: {func.__module__}.{func.__name__}', [
|
|
|
|
clrlib.fg('light_cyan'),
|
|
|
|
clrlib.attr('bold'),
|
|
|
|
]))
|
2020-07-20 01:54:26 +00:00
|
|
|
tbl = list()
|
2020-11-06 00:08:05 +00:00
|
|
|
if len(sig.parameters) <= 0:
|
|
|
|
print(clrlib.stylize(' ' * 4 + 'No arguments accepted', [
|
|
|
|
clrlib.fg('light_cyan'),
|
|
|
|
]))
|
|
|
|
else:
|
|
|
|
for name, parameter in sig.parameters.items():
|
|
|
|
annotation = parameter.annotation if parameter.annotation != _empty else str
|
|
|
|
tbl.append((
|
|
|
|
str(name),
|
|
|
|
repr(annotation),
|
|
|
|
repr(parameter.default) if parameter.default != _empty else '-unset-',
|
|
|
|
))
|
|
|
|
print(clrlib.stylize(space_left_pad_text(4, table_fmt(
|
|
|
|
'name,type,default'.split(','),
|
|
|
|
tbl,
|
|
|
|
alignment='^'*3,
|
|
|
|
)), [
|
|
|
|
clrlib.fg('light_cyan'),
|
|
|
|
]))
|
2020-07-20 01:54:26 +00:00
|
|
|
return None
|
|
|
|
kwargs = dict()
|
|
|
|
for key in str_args:
|
|
|
|
kwargs[key] = convert_type(
|
|
|
|
func_annotations.get(key, str),
|
|
|
|
str_args[key]
|
|
|
|
)
|
2020-11-06 00:08:05 +00:00
|
|
|
print(clrlib.stylize(f'Calling {func.__module__}.{func.__name__} with arguments:', [
|
|
|
|
clrlib.fg('light_gray'),
|
|
|
|
clrlib.attr('dim'),
|
|
|
|
]))
|
2020-07-20 01:54:26 +00:00
|
|
|
if len(kwargs) <= 0:
|
2020-11-06 00:08:05 +00:00
|
|
|
print(clrlib.stylize(' --- no arguments given ---', [
|
|
|
|
clrlib.fg('light_gray'),
|
|
|
|
clrlib.attr('dim'),
|
|
|
|
]))
|
2020-07-20 01:54:26 +00:00
|
|
|
else:
|
|
|
|
for k, v in kwargs.items():
|
2020-11-06 00:08:05 +00:00
|
|
|
print(clrlib.stylize(f' {k}: {repr(v)}', [
|
|
|
|
clrlib.fg('light_gray'),
|
|
|
|
clrlib.attr('dim'),
|
|
|
|
]))
|
2020-07-20 01:54:26 +00:00
|
|
|
return func(**kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
K = TypeVar('K')
|
|
|
|
|
|
|
|
|
|
|
|
def convert_type(cls: Type[K], data: str) -> K:
|
|
|
|
if cls not in (str, int, float):
|
|
|
|
cls = eval
|
|
|
|
return cls(data)
|
2020-11-06 00:08:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
def space_left_pad_text(qty: int, multiline_text: str) -> str:
|
|
|
|
return '\n'.join([' ' * qty + line for line in multiline_text.splitlines()])
|