| 
									
										
										
										
											2017-12-15 07:04:38 +02:00
										 |  |  | import functools | 
					
						
							|  |  |  | import inspect | 
					
						
							|  |  |  | import reprlib | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											2017-12-15 07:04:38 +02:00
										 |  |  | import traceback | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from . import constants | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _get_function_source(func): | 
					
						
							|  |  |  |     func = inspect.unwrap(func) | 
					
						
							|  |  |  |     if inspect.isfunction(func): | 
					
						
							|  |  |  |         code = func.__code__ | 
					
						
							|  |  |  |         return (code.co_filename, code.co_firstlineno) | 
					
						
							|  |  |  |     if isinstance(func, functools.partial): | 
					
						
							|  |  |  |         return _get_function_source(func.func) | 
					
						
							|  |  |  |     if isinstance(func, functools.partialmethod): | 
					
						
							|  |  |  |         return _get_function_source(func.func) | 
					
						
							|  |  |  |     return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _format_callback_source(func, args): | 
					
						
							|  |  |  |     func_repr = _format_callback(func, args, None) | 
					
						
							|  |  |  |     source = _get_function_source(func) | 
					
						
							|  |  |  |     if source: | 
					
						
							|  |  |  |         func_repr += f' at {source[0]}:{source[1]}' | 
					
						
							|  |  |  |     return func_repr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _format_args_and_kwargs(args, kwargs): | 
					
						
							|  |  |  |     """Format function arguments and keyword arguments.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Special case for a single parameter: ('hello',) is formatted as ('hello'). | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     # use reprlib to limit the length of the output | 
					
						
							|  |  |  |     items = [] | 
					
						
							|  |  |  |     if args: | 
					
						
							|  |  |  |         items.extend(reprlib.repr(arg) for arg in args) | 
					
						
							|  |  |  |     if kwargs: | 
					
						
							|  |  |  |         items.extend(f'{k}={reprlib.repr(v)}' for k, v in kwargs.items()) | 
					
						
							|  |  |  |     return '({})'.format(', '.join(items)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _format_callback(func, args, kwargs, suffix=''): | 
					
						
							|  |  |  |     if isinstance(func, functools.partial): | 
					
						
							|  |  |  |         suffix = _format_args_and_kwargs(args, kwargs) + suffix | 
					
						
							|  |  |  |         return _format_callback(func.func, func.args, func.keywords, suffix) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-28 16:27:34 -04:00
										 |  |  |     if hasattr(func, '__qualname__') and func.__qualname__: | 
					
						
							|  |  |  |         func_repr = func.__qualname__ | 
					
						
							|  |  |  |     elif hasattr(func, '__name__') and func.__name__: | 
					
						
							|  |  |  |         func_repr = func.__name__ | 
					
						
							| 
									
										
										
										
											2017-12-15 07:04:38 +02:00
										 |  |  |     else: | 
					
						
							|  |  |  |         func_repr = repr(func) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     func_repr += _format_args_and_kwargs(args, kwargs) | 
					
						
							|  |  |  |     if suffix: | 
					
						
							|  |  |  |         func_repr += suffix | 
					
						
							|  |  |  |     return func_repr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def extract_stack(f=None, limit=None): | 
					
						
							|  |  |  |     """Replacement for traceback.extract_stack() that only does the
 | 
					
						
							|  |  |  |     necessary work for asyncio debug mode. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if f is None: | 
					
						
							|  |  |  |         f = sys._getframe().f_back | 
					
						
							|  |  |  |     if limit is None: | 
					
						
							|  |  |  |         # Limit the amount of work to a reasonable amount, as extract_stack() | 
					
						
							|  |  |  |         # can be called for each coroutine and future in debug mode. | 
					
						
							|  |  |  |         limit = constants.DEBUG_STACK_DEPTH | 
					
						
							|  |  |  |     stack = traceback.StackSummary.extract(traceback.walk_stack(f), | 
					
						
							|  |  |  |                                            limit=limit, | 
					
						
							|  |  |  |                                            lookup_lines=False) | 
					
						
							|  |  |  |     stack.reverse() | 
					
						
							|  |  |  |     return stack |