1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3""" 4Various utilities functions 5""" 6 7import sys 8 9from inspect import isclass 10try: 11 from inspect import getfullargspec as getargspec 12 13 _fullargspec_supported = True 14except ImportError: 15 _fullargspec_supported = False 16 from inspect import getargspec 17 18from .utils import is_iterable 19 20if sys.version_info < (3, 4, 0): # pragma: no cover 21 def _constructor(class_): 22 """ 23 Retrieves constructor from given class 24 25 :param class_: 26 :type class_: class 27 :return: constructor from given class 28 :rtype: callable 29 """ 30 return class_.__init__ 31else: # pragma: no cover 32 def _constructor(class_): 33 """ 34 Retrieves constructor from given class 35 36 :param class_: 37 :type class_: class 38 :return: constructor from given class 39 :rtype: callable 40 """ 41 return class_ 42 43 44def call(function, *args, **kwargs): 45 """ 46 Call a function or constructor with given args and kwargs after removing args and kwargs that doesn't match 47 function or constructor signature 48 49 :param function: Function or constructor to call 50 :type function: callable 51 :param args: 52 :type args: 53 :param kwargs: 54 :type kwargs: 55 :return: sale vakye as default function call 56 :rtype: object 57 """ 58 func = constructor_args if isclass(function) else function_args 59 call_args, call_kwargs = func(function, *args, ignore_unused=True, **kwargs) # @see #20 60 return function(*call_args, **call_kwargs) 61 62 63def function_args(callable_, *args, **kwargs): 64 """ 65 Return (args, kwargs) matching the function signature 66 67 :param callable: callable to inspect 68 :type callable: callable 69 :param args: 70 :type args: 71 :param kwargs: 72 :type kwargs: 73 :return: (args, kwargs) matching the function signature 74 :rtype: tuple 75 """ 76 argspec = getargspec(callable_) # pylint:disable=deprecated-method 77 return argspec_args(argspec, False, *args, **kwargs) 78 79 80def constructor_args(class_, *args, **kwargs): 81 """ 82 Return (args, kwargs) matching the function signature 83 84 :param callable: callable to inspect 85 :type callable: Callable 86 :param args: 87 :type args: 88 :param kwargs: 89 :type kwargs: 90 :return: (args, kwargs) matching the function signature 91 :rtype: tuple 92 """ 93 argspec = getargspec(_constructor(class_)) # pylint:disable=deprecated-method 94 return argspec_args(argspec, True, *args, **kwargs) 95 96 97def argspec_args(argspec, constructor, *args, **kwargs): 98 """ 99 Return (args, kwargs) matching the argspec object 100 101 :param argspec: argspec to use 102 :type argspec: argspec 103 :param constructor: is it a constructor ? 104 :type constructor: bool 105 :param args: 106 :type args: 107 :param kwargs: 108 :type kwargs: 109 :return: (args, kwargs) matching the function signature 110 :rtype: tuple 111 """ 112 if argspec.varkw: 113 call_kwarg = kwargs 114 else: 115 call_kwarg = dict((k, kwargs[k]) for k in kwargs if k in argspec.args) # Python 2.6 dict comprehension 116 if argspec.varargs: 117 call_args = args 118 else: 119 call_args = args[:len(argspec.args) - (1 if constructor else 0)] 120 return call_args, call_kwarg 121 122 123if not _fullargspec_supported: 124 def argspec_args_legacy(argspec, constructor, *args, **kwargs): 125 """ 126 Return (args, kwargs) matching the argspec object 127 128 :param argspec: argspec to use 129 :type argspec: argspec 130 :param constructor: is it a constructor ? 131 :type constructor: bool 132 :param args: 133 :type args: 134 :param kwargs: 135 :type kwargs: 136 :return: (args, kwargs) matching the function signature 137 :rtype: tuple 138 """ 139 if argspec.keywords: 140 call_kwarg = kwargs 141 else: 142 call_kwarg = dict((k, kwargs[k]) for k in kwargs if k in argspec.args) # Python 2.6 dict comprehension 143 if argspec.varargs: 144 call_args = args 145 else: 146 call_args = args[:len(argspec.args) - (1 if constructor else 0)] 147 return call_args, call_kwarg 148 149 150 argspec_args = argspec_args_legacy 151 152 153def ensure_list(param): 154 """ 155 Retrieves a list from given parameter. 156 157 :param param: 158 :type param: 159 :return: 160 :rtype: 161 """ 162 if not param: 163 param = [] 164 elif not is_iterable(param): 165 param = [param] 166 return param 167 168 169def ensure_dict(param, default_value, default_key=None): 170 """ 171 Retrieves a dict and a default value from given parameter. 172 173 if parameter is not a dict, it will be promoted as the default value. 174 175 :param param: 176 :type param: 177 :param default_value: 178 :type default_value: 179 :param default_key: 180 :type default_key: 181 :return: 182 :rtype: 183 """ 184 if not param: 185 param = default_value 186 if not isinstance(param, dict): 187 if param: 188 default_value = param 189 return {default_key: param}, default_value 190 return param, default_value 191 192 193def filter_index(collection, predicate=None, index=None): 194 """ 195 Filter collection with predicate function and index. 196 197 If index is not found, returns None. 198 :param collection: 199 :type collection: collection supporting iteration and slicing 200 :param predicate: function to filter the collection with 201 :type predicate: function 202 :param index: position of a single element to retrieve 203 :type index: int 204 :return: filtered list, or single element of filtered list if index is defined 205 :rtype: list or object 206 """ 207 if index is None and isinstance(predicate, int): 208 index = predicate 209 predicate = None 210 if predicate: 211 collection = collection.__class__(filter(predicate, collection)) 212 if index is not None: 213 try: 214 collection = collection[index] 215 except IndexError: 216 collection = None 217 return collection 218 219 220def set_defaults(defaults, kwargs, override=False): 221 """ 222 Set defaults from defaults dict to kwargs dict 223 224 :param override: 225 :type override: 226 :param defaults: 227 :type defaults: 228 :param kwargs: 229 :type kwargs: 230 :return: 231 :rtype: 232 """ 233 if 'clear' in defaults.keys() and defaults.pop('clear'): 234 kwargs.clear() 235 for key, value in defaults.items(): 236 if key in kwargs: 237 if isinstance(value, list) and isinstance(kwargs[key], list): 238 kwargs[key] = list(value) + kwargs[key] 239 elif isinstance(value, dict) and isinstance(kwargs[key], dict): 240 set_defaults(value, kwargs[key]) 241 if key not in kwargs or override: 242 kwargs[key] = value 243