Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,6 @@ Tim Gates (@timgates42) <tim.gates@iress.com>
Batuhan Taskaya (@isidentical) <isidentical@gmail.com>
Jocelyn Boullier (@Kazy) <jocelyn@boullier.bzh>

Rudy Celekli (@rudycelekli)

Note: (@user) means a github user name.
15 changes: 9 additions & 6 deletions parso/python/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import sys
import warnings
import re
import unicodedata
from contextlib import contextmanager

from parso.normalizer import Normalizer, NormalizerConfig, Issue, Rule
Expand Down Expand Up @@ -942,14 +943,15 @@ def is_issue(self, node):
else: # Is a keyword argument.
kw_only = True
if first.type == 'name':
if first.value in arg_set:
name = unicodedata.normalize('NFKC', first.value)
if name in arg_set:
# f(x=1, x=2)
message = "keyword argument repeated"
if self._normalizer.version >= (3, 9):
message += ": {}".format(first.value)
message += ": {}".format(name)
self.add_issue(first, message=message)
else:
arg_set.add(first.value)
arg_set.add(name)
else:
if kw_unpacking_only:
# f(**x, y)
Expand Down Expand Up @@ -978,13 +980,14 @@ def is_issue(self, node):
default_only = False
continue

if p.name.value in param_names:
name = unicodedata.normalize('NFKC', p.name.value)
if name in param_names:
if sys.version_info[:2] < (3, 15):
message = "duplicate argument '%s' in function definition"
else:
message = "duplicate parameter '%s' in function definition"
self.add_issue(p.name, message=message % p.name.value)
param_names.add(p.name.value)
self.add_issue(p.name, message=message % name)
param_names.add(name)

if not star_seen:
if p.default is None and not p.star_count:
Expand Down
32 changes: 32 additions & 0 deletions test/test_python_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,38 @@ def test_forbidden_name(template, target):
assert _get_error_list(template.format(target=target), version="3")


@pytest.mark.parametrize('code', [
'def f(K, K): pass',
'def f(K, K): pass',
'def f(a, a): pass',
'def f(K, *, K): pass',
'lambda K, K: None',
'lambda a, a: None',
'f(K=1, K=2)',
'f(K=1, K=2)',
'f(a=1, a=2)',
])
def test_nfkc_duplicate_arguments(code):
wanted, line_nr = _get_actual_exception(code)
errors = _get_error_list(code)

error, = errors
assert error.message in wanted
assert error.start_pos[0] == line_nr
assert parso.parse(code).get_code() == code


@pytest.mark.parametrize('code', [
'def f(K, k): pass',
'def f(K, K2): pass',
'lambda K, k: None',
'f(K=1, k=2)',
])
def test_distinct_unicode_arguments(code):
compile(code, '<test>', 'exec')
assert not _get_error_list(code)


def test_repeated_kwarg():
# python 3.9+ shows which argument is repeated
assert (
Expand Down
Loading