84 lines
2.5 KiB
Python
84 lines
2.5 KiB
Python
|
#!/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
|
||
|
|
||
|
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:
|
||
|
print('Unknown arguments found:')
|
||
|
for k, v in unknown_args.items():
|
||
|
print(f' {k}: {repr(v)}')
|
||
|
print()
|
||
|
print(f'Usage help for: {func.__module__}.{func.__name__}')
|
||
|
tbl = list()
|
||
|
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(table_fmt(
|
||
|
'name,type,default'.split(','),
|
||
|
tbl,
|
||
|
alignment='^'*3,
|
||
|
))
|
||
|
return None
|
||
|
kwargs = dict()
|
||
|
for key in str_args:
|
||
|
kwargs[key] = convert_type(
|
||
|
func_annotations.get(key, str),
|
||
|
str_args[key]
|
||
|
)
|
||
|
print(f'Calling {func.__module__}.{func.__name__} with arguments:')
|
||
|
if len(kwargs) <= 0:
|
||
|
print(' --- no arguments given ---')
|
||
|
else:
|
||
|
for k, v in kwargs.items():
|
||
|
print(f' {k}: {repr(v)}')
|
||
|
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)
|