Skip to content

Commit

Permalink
Handle complex duplicate key cases found by fuzzer
Browse files Browse the repository at this point in the history
  • Loading branch information
myint committed Jan 4, 2018
1 parent f74645b commit b5f223e
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 15 deletions.
33 changes: 18 additions & 15 deletions autoflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,15 +457,6 @@ def filter_duplicate_key(line, message, line_number, marked_line_numbers,
return ''


def stringify_key(key):
"""Return `key` with special characters escaped."""
return str(key)\
.replace('(', '\(').replace(')', '\)')\
.replace('{', '\{').replace('}', '\}')\
.replace('[', '\[').replace(']', '\]')\
.replace(' ', '\s?')


def is_last_in_object(line, line_number, key, marked_line_numbers, source):
"""Return True if this line represents the last item in the dict."""
obj_lines = get_occurrence_in_object(
Expand All @@ -477,17 +468,31 @@ def is_last_in_object(line, line_number, key, marked_line_numbers, source):
)

if len(obj_lines) <= 1:
return False
# This means it is too complex for us to parse. Keep the item by
# assuming it is the last item.
return True

if line_number == obj_lines[-1]:
return True
else:
return False


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)

try:
candidate_key = ast.literal_eval(result.group(1))
except (SyntaxError, ValueError):
return False

return candidate_key == key


def get_occurrence_in_object(line, line_number, key, marked_line_numbers,
source):
"""Return lines relevant to object."""
"""Return line numbers relevant to object."""
lines = source.split('\n')
opening_object_lines = [
i for i, s in enumerate(lines, start=1) if '{' in s]
Expand All @@ -502,10 +507,8 @@ def get_occurrence_in_object(line, line_number, key, marked_line_numbers,
for ln in marked_line_numbers:
if (
opening_object_lines[obj] <= ln and
closing_object_lines[obj] >= ln
and re.search(
r'(?:\'|")?%s(?:\'|")?: [^,]+' % stringify_key(key),
lines[ln - 1])
closing_object_lines[obj] >= ln and
dict_entry_has_key(lines[ln - 1], key)
):
obj_lines.append(ln)

Expand Down
16 changes: 16 additions & 0 deletions test_autoflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,22 @@ def test_filter_code_with_duplicate_key(self):
(0,1): 3,
}
print(a)
""", remove_duplicate_keys=True)))

def test_filter_code_with_special_re_symbols_in_key(self):
self.assertEqual(
"""\
a = {
'????': 2,
}
print(a)
""",
''.join(autoflake.filter_code("""\
a = {
'????': 3,
'????': 2,
}
print(a)
""", remove_duplicate_keys=True)))

def test_filter_code_should_ignore_complex_case_of_duplicate_key(self):
Expand Down

0 comments on commit b5f223e

Please sign in to comment.