From 115572434694ff0ceeb2454d3e79f3cd1ed5487f Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 14 Feb 2018 00:28:54 +0000 Subject: [PATCH] Fix lint issues. --- debugger_protocol/messages/__init__.py | 2 +- ptvsd/safe_repr.py | 216 ++++++++++++++----------- ptvsd/wrapper.py | 93 +++++++---- 3 files changed, 190 insertions(+), 121 deletions(-) diff --git a/debugger_protocol/messages/__init__.py b/debugger_protocol/messages/__init__.py index ccc56c04..6a171a16 100644 --- a/debugger_protocol/messages/__init__.py +++ b/debugger_protocol/messages/__init__.py @@ -71,6 +71,6 @@ class Message(object): # Force registration. -from .message import ProtocolMessage, Request, Response, Event +from .message import ProtocolMessage, Request, Response, Event # noqa from .requests import * # noqa from .events import * # noqa diff --git a/ptvsd/safe_repr.py b/ptvsd/safe_repr.py index cf3456f7..9f8b583a 100644 --- a/ptvsd/safe_repr.py +++ b/ptvsd/safe_repr.py @@ -10,12 +10,12 @@ import sys # Py3 compat - alias unicode to str, and xrange to range try: - unicode -except: + unicode # noqa +except NameError: unicode = str try: - xrange -except: + xrange # noqa +except NameError: xrange = range @@ -50,29 +50,30 @@ class SafeRepr(object): try: from collections import deque collection_types.append((deque, 'deque([', '])', False)) - except: + except Exception: pass - # type, prefix string, suffix string, item prefix string, item key/value separator, item suffix string + # type, prefix string, suffix string, item prefix string, + # item key/value separator, item suffix string dict_types = [(dict, '{', '}', '', ': ', '')] try: from collections import OrderedDict dict_types.append((OrderedDict, 'OrderedDict([', '])', '(', ', ', ')')) - except: + except Exception: pass # All other types are treated identically to strings, but using # different limits. maxother_outer = 2 ** 16 maxother_inner = 30 - + def __call__(self, obj): try: return ''.join(self._repr(obj, 0)) - except: + except Exception: try: return 'An exception was raised: %r' % sys.exc_info()[1] - except: + except Exception: return 'An exception was raised' def _repr(self, obj, level): @@ -80,23 +81,24 @@ class SafeRepr(object): try: obj_repr = type(obj).__repr__ - except: + except Exception: obj_repr = None def has_obj_repr(t): r = t.__repr__ try: return obj_repr == r - except: + except Exception: return obj_repr is r for t, prefix, suffix, comma in self.collection_types: if isinstance(obj, t) and has_obj_repr(t): return self._repr_iter(obj, level, prefix, suffix, comma) - - for t, prefix, suffix, item_prefix, item_sep, item_suffix in self.dict_types: + + for t, prefix, suffix, item_prefix, item_sep, item_suffix in self.dict_types: # noqa if isinstance(obj, t) and has_obj_repr(t): - return self._repr_dict(obj, level, prefix, suffix, item_prefix, item_sep, item_suffix) + return self._repr_dict(obj, level, prefix, suffix, + item_prefix, item_sep, item_suffix) for t in self.string_types: if isinstance(obj, t) and has_obj_repr(t): @@ -104,14 +106,16 @@ class SafeRepr(object): if self._is_long_iter(obj): return self._repr_long_iter(obj) - + return self._repr_other(obj, level) - # Determines whether an iterable exceeds the limits set in maxlimits, and is therefore unsafe to repr(). - def _is_long_iter(self, obj, level = 0): + # Determines whether an iterable exceeds the limits set in + # maxlimits, and is therefore unsafe to repr(). + def _is_long_iter(self, obj, level=0): try: - # Strings have their own limits (and do not nest). Because they don't have __iter__ in 2.x, this - # check goes before the next one. + # Strings have their own limits (and do not nest). Because + # they don't have __iter__ in 2.x, this check goes before + # the next one. if isinstance(obj, self.string_types): return len(obj) > self.maxstring_inner @@ -119,9 +123,10 @@ class SafeRepr(object): if not hasattr(obj, '__iter__'): return False - # Iterable is its own iterator - this is a one-off iterable like generator or enumerate(). We can't - # really count that, but repr() for these should not include any elements anyway, so we can treat it - # the same as non-iterables. + # Iterable is its own iterator - this is a one-off iterable + # like generator or enumerate(). We can't really count that, + # but repr() for these should not include any elements anyway, + # so we can treat it the same as non-iterables. if obj is iter(obj): return False @@ -129,36 +134,39 @@ class SafeRepr(object): if isinstance(obj, xrange): return False - # numpy and scipy collections (ndarray etc) have self-truncating repr, so they're always safe. + # numpy and scipy collections (ndarray etc) have + # self-truncating repr, so they're always safe. try: module = type(obj).__module__.partition('.')[0] if module in ('numpy', 'scipy'): return False - except: + except Exception: pass # Iterables that nest too deep are considered long. if level >= len(self.maxcollection): return True - # It is too long if the length exceeds the limit, or any of its elements are long iterables. + # It is too long if the length exceeds the limit, or any + # of its elements are long iterables. if hasattr(obj, '__len__'): try: - l = len(obj) - except: - l = None - if l is not None and l > self.maxcollection[level]: + size = len(obj) + except Exception: + size = None + if size is not None and size > self.maxcollection[level]: return True - return any((self._is_long_iter(item, level + 1) for item in obj)) - return any(i > self.maxcollection[level] or self._is_long_iter(item, level + 1) for i, item in enumerate(obj)) + return any((self._is_long_iter(item, level + 1) for item in obj)) # noqa + return any(i > self.maxcollection[level] or self._is_long_iter(item, level + 1) for i, item in enumerate(obj)) # noqa - except: + except Exception: # If anything breaks, assume the worst case. return True - - def _repr_iter(self, obj, level, prefix, suffix, comma_after_single_element = False): + + def _repr_iter(self, obj, level, prefix, suffix, + comma_after_single_element=False): yield prefix - + if level >= len(self.maxcollection): yield '...' else: @@ -168,7 +176,7 @@ class SafeRepr(object): if yield_comma: yield ', ' yield_comma = True - + count -= 1 if count <= 0: yield '...' @@ -177,48 +185,50 @@ class SafeRepr(object): for p in self._repr(item, 100 if item is obj else level + 1): yield p else: - if comma_after_single_element and count == self.maxcollection[level] - 1: - yield ',' + if comma_after_single_element: + if count == self.maxcollection[level] - 1: + yield ',' yield suffix def _repr_long_iter(self, obj): try: obj_repr = '<%s, len() = %s>' % (type(obj).__name__, len(obj)) - except: + except Exception: try: obj_repr = '<' + type(obj).__name__ + '>' - except: + except Exception: obj_repr = '' yield obj_repr - - def _repr_dict(self, obj, level, prefix, suffix, item_prefix, item_sep, item_suffix): + + def _repr_dict(self, obj, level, prefix, suffix, + item_prefix, item_sep, item_suffix): if not obj: yield prefix + suffix return if level >= len(self.maxcollection): yield prefix + '...' + suffix return - + yield prefix - + count = self.maxcollection[level] yield_comma = False - + try: sorted_keys = sorted(obj) except Exception: sorted_keys = list(obj) - + for key in sorted_keys: if yield_comma: yield ', ' yield_comma = True - + count -= 1 if count <= 0: yield '...' break - + yield item_prefix for p in self._repr(key, level + 1): yield p @@ -233,56 +243,57 @@ class SafeRepr(object): for p in self._repr(item, 100 if item is obj else level + 1): yield p yield item_suffix - + yield suffix def _repr_str(self, obj, level): - return self._repr_obj(obj, level, self.maxstring_inner, self.maxstring_outer) + return self._repr_obj(obj, level, + self.maxstring_inner, self.maxstring_outer) def _repr_other(self, obj, level): - return self._repr_obj(obj, level, self.maxother_inner, self.maxother_outer) - + return self._repr_obj(obj, level, + self.maxother_inner, self.maxother_outer) + def _repr_obj(self, obj, level, limit_inner, limit_outer): try: obj_repr = repr(obj) - except: + except Exception: try: obj_repr = object.__repr__(obj) - except: + except Exception: try: - obj_repr = '' - except: + obj_repr = '' # noqa + except Exception: obj_repr = '' - + limit = limit_inner if level > 0 else limit_outer - + if limit >= len(obj_repr): yield obj_repr return - + # Slightly imprecise calculations - we may end up with a string that is # up to 3 characters longer than limit. If you need precise formatting, # you are using the wrong class. - left_count, right_count = max(1, int(2 * limit / 3)), max(1, int(limit / 3)) - + left_count, right_count = max(1, int(2 * limit / 3)), max(1, int(limit / 3)) # noqa + yield obj_repr[:left_count] yield '...' yield obj_repr[-right_count:] - - + def _selftest(self): # Test the string limiting somewhat automatically tests = [] tests.append((7, 9, 'A' * (5))) - tests.append((self.maxstring_outer + 3, self.maxstring_inner + 3 + 2, 'A' * (self.maxstring_outer + 10))) + tests.append((self.maxstring_outer + 3, self.maxstring_inner + 3 + 2, 'A' * (self.maxstring_outer + 10))) # noqa if sys.version_info >= (3, 0): - tests.append((self.maxstring_outer + 4, self.maxstring_inner + 4 + 2, bytes('A', 'ascii') * (self.maxstring_outer + 10))) + tests.append((self.maxstring_outer + 4, self.maxstring_inner + 4 + 2, bytes('A', 'ascii') * (self.maxstring_outer + 10))) # noqa else: - tests.append((self.maxstring_outer + 4, self.maxstring_inner + 4 + 2, unicode('A') * (self.maxstring_outer + 10))) - + tests.append((self.maxstring_outer + 4, self.maxstring_inner + 4 + 2, unicode('A') * (self.maxstring_outer + 10))) # noqa + for limit1, limit2, value in tests: - assert len(self(value)) <= limit1 <= len(repr(value)), (len(self(value)), limit1, len(repr(value)), value) - assert len(self([value])) <= limit2 <= len(repr([value])), (len(self([value])), limit2, len(repr([value])), self([value])) + assert len(self(value)) <= limit1 <= len(repr(value)), (len(self(value)), limit1, len(repr(value)), value) # noqa + assert len(self([value])) <= limit2 <= len(repr([value])), (len(self([value])), limit2, len(repr([value])), self([value])) # noqa def test(source, expected): actual = self(source) @@ -292,7 +303,7 @@ class SafeRepr(object): print("Actual " + actual) print("") assert False - + def re_test(source, pattern): import re actual = self(source) @@ -302,7 +313,7 @@ class SafeRepr(object): print("Actual " + actual) print("") assert False - + for ctype, _prefix, _suffix, comma in self.collection_types: for i in range(len(self.maxcollection)): prefix = _prefix * (i + 1) @@ -310,7 +321,8 @@ class SafeRepr(object): suffix = _suffix + ("," + _suffix) * i else: suffix = _suffix * (i + 1) - #print("ctype = " + ctype.__name__ + ", maxcollection[" + str(i) + "] == " + str(self.maxcollection[i])) + #print("ctype = " + ctype.__name__ + ", maxcollection[" + + # str(i) + "] == " + str(self.maxcollection[i])) c1 = ctype(range(self.maxcollection[i] - 1)) inner_repr = prefix + ', '.join(str(j) for j in c1) c2 = ctype(range(self.maxcollection[i])) @@ -329,10 +341,10 @@ class SafeRepr(object): # test with lists. c1 = list(range(self.maxcollection[0] * 2)) c2 = [c1 for _ in range(self.maxcollection[0] * 2)] - c1_expect = '[' + ', '.join(str(j) for j in range(self.maxcollection[0] - 1)) + ', ...]' + c1_expect = '[' + ', '.join(str(j) for j in range(self.maxcollection[0] - 1)) + ', ...]' # noqa test(c1, c1_expect) - c1_expect2 = '[' + ', '.join(str(j) for j in range(self.maxcollection[1] - 1)) + ', ...]' - c2_expect = '[' + ', '.join(c1_expect2 for _ in range(self.maxcollection[0] - 1)) + ', ...]' + c1_expect2 = '[' + ', '.join(str(j) for j in range(self.maxcollection[1] - 1)) + ', ...]' # noqa + c2_expect = '[' + ', '.join(c1_expect2 for _ in range(self.maxcollection[0] - 1)) + ', ...]' # noqa test(c2, c2_expect) # Ensure dict keys and values are limited correctly @@ -340,13 +352,13 @@ class SafeRepr(object): d1_key = 'a' * self.maxstring_inner * 2 d1[d1_key] = d1_key re_test(d1, "{'a+\.\.\.a+': 'a+\.\.\.a+'}") - d2 = {d1_key : d1} + d2 = {d1_key: d1} re_test(d2, "{'a+\.\.\.a+': {'a+\.\.\.a+': 'a+\.\.\.a+'}}") - d3 = {d1_key : d2} + d3 = {d1_key: d2} if len(self.maxcollection) == 2: re_test(d3, "{'a+\.\.\.a+': {'a+\.\.\.a+': {\.\.\.}}}") else: - re_test(d3, "{'a+\.\.\.a+': {'a+\.\.\.a+': {'a+\.\.\.a+': 'a+\.\.\.a+'}}}") + re_test(d3, "{'a+\.\.\.a+': {'a+\.\.\.a+': {'a+\.\.\.a+': 'a+\.\.\.a+'}}}") # noqa # Ensure empty dicts work test({}, '{}') @@ -384,23 +396,32 @@ class SafeRepr(object): # Test with objects with long repr implementations class TestClass(object): repr_str = '<' + 'A' * self.maxother_outer * 2 + '>' + def __repr__(self): return self.repr_str re_test(TestClass(), r'\') # Test collections that don't override repr - class TestClass(dict): pass + class TestClass(dict): + pass test(TestClass(), '{}') - class TestClass(list): pass + + class TestClass(list): + pass test(TestClass(), '[]') # Test collections that override repr class TestClass(dict): - def __repr__(self): return 'MyRepr' + def __repr__(self): + return 'MyRepr' test(TestClass(), 'MyRepr') + class TestClass(list): - def __init__(self, iter = ()): list.__init__(self, iter) - def __repr__(self): return 'MyRepr' + def __init__(self, iter=()): + list.__init__(self, iter) + + def __repr__(self): + return 'MyRepr' test(TestClass(), 'MyRepr') # Test collections and iterables with long repr @@ -410,15 +431,18 @@ class SafeRepr(object): test(TestClass([TestClass(xrange(0, 11))]), '') # Test strings inside long iterables - test(TestClass(['a' * (self.maxcollection[1] + 1)]), 'MyRepr') - test(TestClass(['a' * (self.maxstring_inner + 1)]), '') + test(TestClass(['a' * (self.maxcollection[1] + 1)]), + 'MyRepr') + test(TestClass(['a' * (self.maxstring_inner + 1)]), + '') # Test range if sys.version[0] == '2': range_name = 'xrange' else: range_name = 'range' - test(xrange(1, self.maxcollection[0] + 1), '%s(1, %s)' % (range_name, self.maxcollection[0] + 1)) + test(xrange(1, self.maxcollection[0] + 1), + '%s(1, %s)' % (range_name, self.maxcollection[0] + 1)) # Test directly recursive collections c1 = [1, 2] @@ -442,15 +466,21 @@ class SafeRepr(object): #except MemoryError: # print('Memory error raised while creating repr of test data') # text_repr = '' - #print('len(SafeRepr()(dcoll)) = ' + str(len(text)) + ', len(repr(coll)) = ' + str(len(text_repr))) + #print('len(SafeRepr()(dcoll)) = ' + str(len(text)) + + # ', len(repr(coll)) = ' + str(len(text_repr))) assert len(text) < 8192 - # Test numpy types - they should all use their native reprs, even arrays exceeding limits + # Test numpy types - they should all use their native reprs, + # even arrays exceeding limits try: import numpy as np except ImportError: - print('WARNING! could not import numpy - skipping all numpy tests.') + msg = 'WARNING! could not import numpy - skipping all numpy tests.' + print(msg) else: - test(np.int32(123), repr(np.int32(123))) - test(np.float64(123.456), repr(np.float64(123.456))) - test(np.zeros(self.maxcollection[0] + 1), repr(np.zeros(self.maxcollection[0] + 1))); + test(np.int32(123), + repr(np.int32(123))) + test(np.float64(123.456), + repr(np.float64(123.456))) + test(np.zeros(self.maxcollection[0] + 1), + repr(np.zeros(self.maxcollection[0] + 1))) diff --git a/ptvsd/wrapper.py b/ptvsd/wrapper.py index 3760cf32..d346fcba 100644 --- a/ptvsd/wrapper.py +++ b/ptvsd/wrapper.py @@ -6,14 +6,13 @@ from __future__ import print_function, with_statement, absolute_import import atexit -import itertools import os import socket import sys import threading import traceback import untangle -import platform +import platform try: import urllib @@ -234,6 +233,7 @@ class PydevdSocket(object): os.write(self.pipe_w, s.encode('utf8')) return fut + class ExceptionsManager(object): def __init__(self, proc): self.proc = proc @@ -244,14 +244,14 @@ class ExceptionsManager(object): with self.lock: for exception in self.exceptions: self.proc.pydevd_notify(pydevd_comm.CMD_REMOVE_EXCEPTION_BREAK, - 'python-{}'.format(exception)) + 'python-{}'.format(exception)) self.exceptions = [] def add_exception_break(self, exception, break_raised, break_uncaught): - + # notify_always options: # 1 is deprecated, you will see a warning message - # 2 notify on first raise only + # 2 notify on first raise only # 3 or greater, notify always notify_always = 3 if break_raised else 0 @@ -261,38 +261,66 @@ class ExceptionsManager(object): notify_on_terminate = 1 if break_uncaught else 0 # ignore_libraries options: - # Less than or equal to 0 DO NOT ignore libraries (required for notify_always) + # Less than or equal to 0 DO NOT ignore libraries (required + # for notify_always) # Greater than 0 ignore libraries ignore_libraries = 0 - cmdargs = (exception, notify_always, notify_on_terminate, ignore_libraries) + cmdargs = ( + exception, + notify_always, + notify_on_terminate, + ignore_libraries, + ) msg = 'python-{}\t{}\t{}\t{}'.format(*cmdargs) with self.lock: - self.proc.pydevd_notify(pydevd_comm.CMD_ADD_EXCEPTION_BREAK, msg) + self.proc.pydevd_notify( + pydevd_comm.CMD_ADD_EXCEPTION_BREAK, msg) self.exceptions.append(exception) - + def apply_exception_options(self, exception_options): - """Applies exception options after removing any existing exception breaks. + """ + Applies exception options after removing any existing exception + breaks. """ self.remove_all_exception_breaks() - pyex_options = (o for o in exception_options if self.__is_python_exception_category(o)) + pyex_options = (opt + for opt in exception_options + if self.__is_python_exception_category(opt)) for option in pyex_options: exception_paths = option['path'] + if not exception_paths: + continue + mode = option['breakMode'] - break_raised = True if mode == 'always' else False - break_uncaught = True if mode in ['unhandled', 'userUnhandled'] else False + break_raised = (mode == 'always') + break_uncaught = (mode in ['unhandled', 'userUnhandled']) # Special case for the entire python exceptions category - if len(exception_paths) == 1 and exception_paths[0]['names'][0] == 'Python Exceptions': - self.add_exception_break('BaseException', break_raised, break_uncaught) + is_category = False + if len(exception_paths) == 1: + # TODO: isn't the first one always the category? + if exception_paths[0]['names'][0] == 'Python Exceptions': + is_category = True + if is_category: + self.add_exception_break( + 'BaseException', break_raised, break_uncaught) else: - # Skip the first one. It will always be the category "Python Exceptions" - path_iterator = itertools.islice(exception_paths, 1, None) - exception_names = (ex_name for path in path_iterator for ex_name in path['names']) + path_iterator = iter(exception_paths) + # Skip the first one. It will always be the category + # "Python Exceptions" + next(path_iterator) + exception_names = [] + for path in path_iterator: + for ex_name in path['names']: + exception_names.append(ex_name) for exception_name in exception_names: - self.add_exception_break(exception_name, break_raised, break_uncaught) - + self.add_exception_break( + exception_name, break_raised, break_uncaught) + def __is_python_exception_category(self, option): - """Check if the option has entires and that the first entry is 'Python Exceptions' + """ + Check if the option has entires and that the first entry + is 'Python Exceptions'. """ exception_paths = option['path'] if not exception_paths: @@ -301,7 +329,7 @@ class ExceptionsManager(object): category = exception_paths[0]['names'] if category is None or len(category) != 1: return False - + return category[0] == 'Python Exceptions' @@ -456,7 +484,12 @@ class VSCodeMessageProcessor(ipcjson.SocketIO, ipcjson.IpcChannel): self.send_event('process', **evt) def is_debugger_internal_thread(self, thread_name): - return thread_name and (thread_name.startswith('pydevd.') or thread_name.startswith('ptvsd.')) + if thread_name: + if thread_name.startswith('pydevd.'): + return True + elif thread_name.startswith('ptvsd.'): + return True + return False @async_handler def on_threads(self, request, args): @@ -704,7 +737,8 @@ class VSCodeMessageProcessor(ipcjson.SocketIO, ipcjson.IpcChannel): break_raised = 'raised' in filters break_uncaught = 'uncaught' in filters if break_raised or break_uncaught: - self.exceptions_mgr.add_exception_break('BaseException', break_raised, break_uncaught) + self.exceptions_mgr.add_exception_break( + 'BaseException', break_raised, break_uncaught) self.send_response(request) @async_handler @@ -866,7 +900,10 @@ pydevd_comm.start_client = start_client class SafeReprPresentationProvider(pydevd_extapi.StrPresentationProvider): - """Computes string representation of Python values by delegating them to SafeRepr.""" + """ + Computes string representation of Python values by delegating them + to SafeRepr. + """ def __init__(self): from ptvsd.safe_repr import SafeRepr @@ -878,6 +915,8 @@ class SafeReprPresentationProvider(pydevd_extapi.StrPresentationProvider): def get_str(self, val): return self.safe_repr(val) -# Register our presentation provider as the first item on the list, so that we're in full control of presentation. -str_handlers = pydevd_extutil.EXTENSION_MANAGER_INSTANCE.type_to_instance.setdefault(pydevd_extapi.StrPresentationProvider, []) + +# Register our presentation provider as the first item on the list, +# so that we're in full control of presentation. +str_handlers = pydevd_extutil.EXTENSION_MANAGER_INSTANCE.type_to_instance.setdefault(pydevd_extapi.StrPresentationProvider, []) # noqa str_handlers.insert(0, SafeReprPresentationProvider())