From 9dbef4ff3df43d5fc13242b5c727cb06ed9e80fd Mon Sep 17 00:00:00 2001 From: Steven Myint Date: Thu, 4 Jan 2018 11:22:40 -0800 Subject: [PATCH] Ignore additional complex duplicate-key cases --- Makefile | 4 ++-- autoflake.py | 29 ++++++++++++++++++++++++++--- test_autoflake.py | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 2a71cf8..5a2b0f7 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ check: - pyflakes ./*.py + pyflakes autoflake.py setup.py test_autoflake.py pylint \ --reports=no \ --rcfile=/dev/null \ --errors-only \ autoflake.py setup.py - pycodestyle ./*.py + pycodestyle autoflake.py setup.py test_autoflake.py pydocstyle autoflake.py setup.py check-manifest python setup.py --long-description | rstcheck - diff --git a/autoflake.py b/autoflake.py index 8530a22..ccb6f09 100755 --- a/autoflake.py +++ b/autoflake.py @@ -344,6 +344,11 @@ def filter_code(source, additional_imports=None, if remove_duplicate_keys: marked_key_line_numbers = frozenset( duplicate_key_line_numbers(messages)) + if ( + marked_key_line_numbers and + any_complex_duplicate_key_cases(marked_key_line_numbers, source) + ): + marked_key_line_numbers = frozenset() else: marked_key_line_numbers = frozenset() @@ -375,6 +380,22 @@ def filter_code(source, additional_imports=None, previous_line = line +def any_complex_duplicate_key_cases(marked_line_numbers, source): + """Return True if duplicate key lines contain complex code. + + We don't want to bother trying to parse this stuff and get it right. + """ + lines = source.split('\n') + for line_number in marked_line_numbers: + line = lines[line_number - 1] + + if line.rstrip().endswith((':', '\\')): + return True + + if ':' not in line or '#' in line: + return True + + def get_messages_by_line(messages): """Return dictionary that maps line number to message.""" line_messages = {} @@ -467,9 +488,9 @@ def is_last_in_object(line, line_number, key, marked_line_numbers, source): source ) - if len(obj_lines) <= 1: - # This means it is too complex for us to parse. Keep the item by - # assuming it is the last item. + if obj_lines is None or len(obj_lines) <= 1: + # We failed to parse something. Don't touch. Keep the item by assuming + # it is the last item. return True if line_number == obj_lines[-1]: @@ -481,6 +502,8 @@ def is_last_in_object(line, line_number, key, marked_line_numbers, source): def dict_entry_has_key(line, key): """Return True if `line` is a dict entry that uses `key`.""" result = re.match(r'\s*(.*)\s*:.*,?\s*$', line) + if not result: + return False try: candidate_key = ast.literal_eval(result.group(1)) diff --git a/test_autoflake.py b/test_autoflake.py index 8269ad9..f287a29 100755 --- a/test_autoflake.py +++ b/test_autoflake.py @@ -457,6 +457,41 @@ def test_filter_code_should_ignore_complex_case_of_duplicate_key(self): (0,1): 3, } print(a) +""" + + self.assertEqual( + code, + ''.join(autoflake.filter_code(code, + remove_duplicate_keys=True))) + + def test_filter_code_should_ignore_more_cases_of_duplicate_key(self): + """We only handle simple cases.""" + code = """\ +a = { + (0,1): + 1, + (0, 1): 'two', + (0,1): 3, +} +print(a) +""" + + self.assertEqual( + code, + ''.join(autoflake.filter_code(code, + remove_duplicate_keys=True))) + + def test_filter_code_should_ignore_duplicate_key_with_comments(self): + """We only handle simple cases.""" + code = """\ +a = { + (0,1) # : f + : + 1, + (0, 1): 'two', + (0,1): 3, +} +print(a) """ self.assertEqual(