Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import types 

2import inspect 

3from collections.abc import Iterable 

4from typer.models import OptionInfo 

5from typer.main import get_params_convertors_ctx_param_name_from_function 

6from rich.console import Console 

7 

8console = Console() 

9 

10 

11def copy_func(f, name=None): 

12 """ 

13 Returns a deep copy of a function. 

14 

15 The new function has the same code, globals, defaults, closure, annotations, and name 

16 (unless a new name is provided) 

17 

18 Derived from https://stackoverflow.com/a/30714299 

19 """ 

20 fn = types.FunctionType(f.__code__, f.__globals__, name or f.__name__, f.__defaults__, f.__closure__) 

21 # in case f was given attrs (note this dict is a shallow copy): 

22 fn.__dict__.update(f.__dict__) 

23 fn.__annotations__.update(f.__annotations__) 

24 return fn 

25 

26 

27def call_func(func, *args, **kwargs): 

28 """ 

29 Calls a function while filtering the kwargs for only ones in the signature. 

30 

31 Args: 

32 func (Callable): The function to call 

33 

34 Returns: 

35 The result of the function call. 

36 """ 

37 allowed_params, _, _ = get_params_convertors_ctx_param_name_from_function(func) 

38 allowed_param_names = [p.name for p in allowed_params] 

39 kwargs = {key: value for key, value in kwargs.items() if key in allowed_param_names} 

40 return func(*args, **kwargs) 

41 

42 

43def change_typer_to_defaults(func): 

44 func = getattr(func, "__func__", func) 

45 signature = inspect.signature(func) 

46 

47 # Create a dictionary with both the existing parameters for the function and the new ones 

48 parameters = dict(signature.parameters) 

49 

50 for key, value in parameters.items(): 

51 if isinstance(value.default, OptionInfo): 

52 parameters[key] = value.replace(default=value.default.default) 

53 

54 func.__signature__ = signature.replace(parameters=parameters.values()) 

55 

56 # Change defaults directly 

57 if func.__defaults__ is not None: 

58 func.__defaults__ = tuple( 

59 [value.default if isinstance(value, OptionInfo) else value for value in func.__defaults__] 

60 ) 

61 

62 

63def add_kwargs(to_func, from_funcs): 

64 """Adds all the keyword arguments from one function to the signature of another function. 

65 

66 Args: 

67 from_funcs (callable or iterable): The function with new parameters to add. 

68 to_func (callable): The function which will receive the new parameters in its signature. 

69 """ 

70 

71 if not isinstance(from_funcs, Iterable): 

72 from_funcs = [from_funcs] 

73 

74 for from_func in from_funcs: 

75 # Get the existing parameters 

76 to_func = getattr(to_func, "__func__", to_func) 

77 from_func = getattr(from_func, "__func__", from_func) 

78 from_func_signature = inspect.signature(from_func) 

79 to_func_signature = inspect.signature(to_func) 

80 

81 # Create a dictionary with both the existing parameters for the function and the new ones 

82 to_func_parameters = dict(to_func_signature.parameters) 

83 

84 if "kwargs" in to_func_parameters: 

85 kwargs_parameter = to_func_parameters.pop("kwargs") 

86 

87 from_func_kwargs = { 

88 k: v 

89 for k, v in from_func_signature.parameters.items() 

90 if v.default != inspect.Parameter.empty and k not in to_func_parameters 

91 } 

92 # to_func_parameters['kwargs'] = kwargs_parameter 

93 

94 to_func_parameters.update(from_func_kwargs) 

95 

96 # Modify function signature with the parameters in this dictionary 

97 # print('to_func', hex(id(to_func))) 

98 to_func.__signature__ = to_func_signature.replace(parameters=to_func_parameters.values()) 

99 for key, value in from_func.__annotations__.items(): 

100 if key not in to_func.__annotations__: 

101 to_func.__annotations__[key] = value