reddit-image-wall-getter/reddit_imgs/system/cmdline_parser.py

84 lines
2.5 KiB
Python
Raw Normal View History

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
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)