PageRenderTime 23ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/programmes/SPAdes-3.8.2-Linux/share/spades/joblib3/func_inspect.py

https://gitlab.com/sirarredondo/Plasmid_Assembly
Python | 303 lines | 261 code | 10 blank | 32 comment | 8 complexity | e65186ef492174e2c86688edbf3532b1 MD5 | raw file
  1. """
  2. My own variation on function-specific inspect-like features.
  3. """
  4. # Author: Gael Varoquaux <gael dot varoquaux at normalesup dot org>
  5. # Copyright (c) 2009 Gael Varoquaux
  6. # License: BSD Style, 3 clauses.
  7. from itertools import islice
  8. import inspect
  9. import warnings
  10. import re
  11. import os
  12. from ._compat import _basestring
  13. from .logger import pformat
  14. from ._memory_helpers import open_py_source
  15. def get_func_code(func):
  16. """ Attempts to retrieve a reliable function code hash.
  17. The reason we don't use inspect.getsource is that it caches the
  18. source, whereas we want this to be modified on the fly when the
  19. function is modified.
  20. Returns
  21. -------
  22. func_code: string
  23. The function code
  24. source_file: string
  25. The path to the file in which the function is defined.
  26. first_line: int
  27. The first line of the code in the source file.
  28. Notes
  29. ------
  30. This function does a bit more magic than inspect, and is thus
  31. more robust.
  32. """
  33. source_file = None
  34. try:
  35. code = func.__code__
  36. source_file = code.co_filename
  37. if not os.path.exists(source_file):
  38. # Use inspect for lambda functions and functions defined in an
  39. # interactive shell, or in doctests
  40. source_code = ''.join(inspect.getsourcelines(func)[0])
  41. line_no = 1
  42. if source_file.startswith('<doctest '):
  43. source_file, line_no = re.match(
  44. '\<doctest (.*\.rst)\[(.*)\]\>',
  45. source_file).groups()
  46. line_no = int(line_no)
  47. source_file = '<doctest %s>' % source_file
  48. return source_code, source_file, line_no
  49. # Try to retrieve the source code.
  50. with open_py_source(source_file) as source_file_obj:
  51. first_line = code.co_firstlineno
  52. # All the lines after the function definition:
  53. source_lines = list(islice(source_file_obj, first_line - 1, None))
  54. return ''.join(inspect.getblock(source_lines)), source_file, first_line
  55. except:
  56. # If the source code fails, we use the hash. This is fragile and
  57. # might change from one session to another.
  58. if hasattr(func, '__code__'):
  59. # Python 3.X
  60. return str(func.__code__.__hash__()), source_file, -1
  61. else:
  62. # Weird objects like numpy ufunc don't have __code__
  63. # This is fragile, as quite often the id of the object is
  64. # in the repr, so it might not persist across sessions,
  65. # however it will work for ufuncs.
  66. return repr(func), source_file, -1
  67. def _clean_win_chars(string):
  68. """Windows cannot encode some characters in filename."""
  69. import urllib
  70. if hasattr(urllib, 'quote'):
  71. quote = urllib.quote
  72. else:
  73. # In Python 3, quote is elsewhere
  74. import urllib.parse
  75. quote = urllib.parse.quote
  76. for char in ('<', '>', '!', ':', '\\'):
  77. string = string.replace(char, quote(char))
  78. return string
  79. def get_func_name(func, resolv_alias=True, win_characters=True):
  80. """ Return the function import path (as a list of module names), and
  81. a name for the function.
  82. Parameters
  83. ----------
  84. func: callable
  85. The func to inspect
  86. resolv_alias: boolean, optional
  87. If true, possible local aliases are indicated.
  88. win_characters: boolean, optional
  89. If true, substitute special characters using urllib.quote
  90. This is useful in Windows, as it cannot encode some filenames
  91. """
  92. if hasattr(func, '__module__'):
  93. module = func.__module__
  94. else:
  95. try:
  96. module = inspect.getmodule(func)
  97. except TypeError:
  98. if hasattr(func, '__class__'):
  99. module = func.__class__.__module__
  100. else:
  101. module = 'unknown'
  102. if module is None:
  103. # Happens in doctests, eg
  104. module = ''
  105. if module == '__main__':
  106. try:
  107. filename = os.path.abspath(inspect.getsourcefile(func))
  108. except:
  109. filename = None
  110. if filename is not None:
  111. # mangling of full path to filename
  112. parts = filename.split(os.sep)
  113. if parts[-1].startswith('<ipython-input'):
  114. # function is defined in an IPython session. The filename
  115. # will change with every new kernel instance. This hack
  116. # always returns the same filename
  117. parts[-1] = '__ipython-input__'
  118. filename = '-'.join(parts)
  119. if filename.endswith('.py'):
  120. filename = filename[:-3]
  121. module = module + '-' + filename
  122. module = module.split('.')
  123. if hasattr(func, 'func_name'):
  124. name = func.func_name
  125. elif hasattr(func, '__name__'):
  126. name = func.__name__
  127. else:
  128. name = 'unknown'
  129. # Hack to detect functions not defined at the module-level
  130. if resolv_alias:
  131. # TODO: Maybe add a warning here?
  132. if hasattr(func, 'func_globals') and name in func.func_globals:
  133. if not func.func_globals[name] is func:
  134. name = '%s-alias' % name
  135. if inspect.ismethod(func):
  136. # We need to add the name of the class
  137. if hasattr(func, 'im_class'):
  138. klass = func.im_class
  139. module.append(klass.__name__)
  140. if os.name == 'nt' and win_characters:
  141. # Stupid windows can't encode certain characters in filenames
  142. name = _clean_win_chars(name)
  143. module = [_clean_win_chars(s) for s in module]
  144. return module, name
  145. def filter_args(func, ignore_lst, args=(), kwargs=dict()):
  146. """ Filters the given args and kwargs using a list of arguments to
  147. ignore, and a function specification.
  148. Parameters
  149. ----------
  150. func: callable
  151. Function giving the argument specification
  152. ignore_lst: list of strings
  153. List of arguments to ignore (either a name of an argument
  154. in the function spec, or '*', or '**')
  155. *args: list
  156. Positional arguments passed to the function.
  157. **kwargs: dict
  158. Keyword arguments passed to the function
  159. Returns
  160. -------
  161. filtered_args: list
  162. List of filtered positional and keyword arguments.
  163. """
  164. args = list(args)
  165. if isinstance(ignore_lst, _basestring):
  166. # Catch a common mistake
  167. raise ValueError('ignore_lst must be a list of parameters to ignore '
  168. '%s (type %s) was given' % (ignore_lst, type(ignore_lst)))
  169. # Special case for functools.partial objects
  170. if (not inspect.ismethod(func) and not inspect.isfunction(func)):
  171. if ignore_lst:
  172. warnings.warn('Cannot inspect object %s, ignore list will '
  173. 'not work.' % func, stacklevel=2)
  174. return {'*': args, '**': kwargs}
  175. arg_spec = inspect.getargspec(func)
  176. # We need to if/them to account for different versions of Python
  177. if hasattr(arg_spec, 'args'):
  178. arg_names = arg_spec.args
  179. arg_defaults = arg_spec.defaults
  180. arg_keywords = arg_spec.keywords
  181. arg_varargs = arg_spec.varargs
  182. else:
  183. arg_names, arg_varargs, arg_keywords, arg_defaults = arg_spec
  184. arg_defaults = arg_defaults or {}
  185. if inspect.ismethod(func):
  186. # First argument is 'self', it has been removed by Python
  187. # we need to add it back:
  188. args = [func.__self__, ] + args
  189. # XXX: Maybe I need an inspect.isbuiltin to detect C-level methods, such
  190. # as on ndarrays.
  191. _, name = get_func_name(func, resolv_alias=False)
  192. arg_dict = dict()
  193. arg_position = -1
  194. for arg_position, arg_name in enumerate(arg_names):
  195. if arg_position < len(args):
  196. # Positional argument or keyword argument given as positional
  197. arg_dict[arg_name] = args[arg_position]
  198. else:
  199. position = arg_position - len(arg_names)
  200. if arg_name in kwargs:
  201. arg_dict[arg_name] = kwargs.pop(arg_name)
  202. else:
  203. try:
  204. arg_dict[arg_name] = arg_defaults[position]
  205. except (IndexError, KeyError):
  206. # Missing argument
  207. raise ValueError('Wrong number of arguments for %s%s:\n'
  208. ' %s(%s, %s) was called.'
  209. % (name,
  210. inspect.formatargspec(*inspect.getargspec(func)),
  211. name,
  212. repr(args)[1:-1],
  213. ', '.join('%s=%s' % (k, v)
  214. for k, v in kwargs.items())
  215. )
  216. )
  217. varkwargs = dict()
  218. for arg_name, arg_value in sorted(kwargs.items()):
  219. if arg_name in arg_dict:
  220. arg_dict[arg_name] = arg_value
  221. elif arg_keywords is not None:
  222. varkwargs[arg_name] = arg_value
  223. else:
  224. raise TypeError("Ignore list for %s() contains an unexpected "
  225. "keyword argument '%s'" % (name, arg_name))
  226. if arg_keywords is not None:
  227. arg_dict['**'] = varkwargs
  228. if arg_varargs is not None:
  229. varargs = args[arg_position + 1:]
  230. arg_dict['*'] = varargs
  231. # Now remove the arguments to be ignored
  232. for item in ignore_lst:
  233. if item in arg_dict:
  234. arg_dict.pop(item)
  235. else:
  236. raise ValueError("Ignore list: argument '%s' is not defined for "
  237. "function %s%s" %
  238. (item, name,
  239. inspect.formatargspec(arg_names,
  240. arg_varargs,
  241. arg_keywords,
  242. arg_defaults,
  243. )))
  244. # XXX: Return a sorted list of pairs?
  245. return arg_dict
  246. def format_signature(func, *args, **kwargs):
  247. # XXX: Should this use inspect.formatargvalues/formatargspec?
  248. module, name = get_func_name(func)
  249. module = [m for m in module if m]
  250. if module:
  251. module.append(name)
  252. module_path = '.'.join(module)
  253. else:
  254. module_path = name
  255. arg_str = list()
  256. previous_length = 0
  257. for arg in args:
  258. arg = pformat(arg, indent=2)
  259. if len(arg) > 1500:
  260. arg = '%s...' % arg[:700]
  261. if previous_length > 80:
  262. arg = '\n%s' % arg
  263. previous_length = len(arg)
  264. arg_str.append(arg)
  265. arg_str.extend(['%s=%s' % (v, pformat(i)) for v, i in kwargs.items()])
  266. arg_str = ', '.join(arg_str)
  267. signature = '%s(%s)' % (name, arg_str)
  268. return module_path, signature
  269. def format_call(func, args, kwargs, object_name="Memory"):
  270. """ Returns a nicely formatted statement displaying the function
  271. call with the given arguments.
  272. """
  273. path, signature = format_signature(func, *args, **kwargs)
  274. msg = '%s\n[%s] Calling %s...\n%s' % (80 * '_', object_name,
  275. path, signature)
  276. return msg
  277. # XXX: Not using logging framework
  278. #self.debug(msg)