Skip to content

Commit 641b495

Browse files
committed
📝 Add support for positional-only parameters
See https://www.python.org/dev/peps/pep-0570/
1 parent 27e3b21 commit 641b495

4 files changed

Lines changed: 46 additions & 3 deletions

File tree

src/python_minifier/expression_printer.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,8 +586,10 @@ def visit_Lambda(self, node):
586586
def visit_arguments(self, node):
587587
first = True
588588

589-
count_no_defaults = len(node.args) - len(node.defaults)
590-
for i, arg in enumerate(node.args):
589+
args = getattr(node, 'posonlyargs', []) + node.args
590+
591+
count_no_defaults = len(args) - len(node.defaults)
592+
for i, arg in enumerate(args):
591593
if not first:
592594
self.code += ','
593595
else:
@@ -600,6 +602,9 @@ def visit_arguments(self, node):
600602
self.code += '='
601603
self._expression(node.defaults[i - count_no_defaults])
602604

605+
if hasattr(node, 'posonlyargs') and node.posonlyargs and i + 1 == len(node.posonlyargs):
606+
self.code += ',/'
607+
603608
if node.vararg:
604609
if not first:
605610
self.code += ','

src/python_minifier/rename/mapper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def add_parent_to_arguments(arguments, func):
1111
arguments.parent = func
1212
arguments.namespace = func
1313

14-
for arg in arguments.args:
14+
for arg in getattr(arguments, 'posonlyargs', []) + arguments.args:
1515
add_parent(arg, arguments, func)
1616
if hasattr(arg, 'annotation') and arg.annotation is not None:
1717
add_parent(arg.annotation, arguments, func.namespace)

src/python_minifier/rename/util.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ def arg_rename_in_place(node):
5353
can be safely renamed. Comprehension arguments are not accessible from outside, so
5454
can be renamed.
5555
56+
If the argument is positional-only, it can be safely renamed
57+
5658
Other arguments may be referenced by the caller as keyword arguments, so should not be
5759
renamed in place. The name assigner may still decide to bind the argument to a new name
5860
inside the function namespace.
@@ -85,6 +87,9 @@ def arg_rename_in_place(node):
8587
# starargs
8688
return True
8789

90+
if hasattr(func.args, 'posonlyargs') and node in func.args.posonlyargs:
91+
return True
92+
8893
return False
8994

9095

test/test_posargs.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import ast
2+
import sys
3+
import pytest
4+
from python_minifier import unparse
5+
from python_minifier.ast_compare import compare_ast
6+
7+
def test_pep():
8+
if sys.version_info < (3, 8):
9+
pytest.skip('No Assignment expressions in python < 3.8')
10+
11+
source = '''
12+
def name(p1, p2, /, p_or_kw, *, kw): pass
13+
def name(p1, p2=None, /, p_or_kw=None, *, kw): pass
14+
def name(p1, p2=None, /, *, kw): pass
15+
def name(p1, p2=None, /): pass
16+
def name(p1, p2, /, p_or_kw): pass
17+
def name(p1, p2, /): pass
18+
def name(p_or_kw, *, kw): pass
19+
def name(*, kw): pass
20+
21+
def standard_arg(arg):
22+
print(arg)
23+
def pos_only_arg(arg, /):
24+
print(arg)
25+
def kwd_only_arg(*, arg):
26+
print(arg)
27+
def combined_example(pos_only, /, standard, *, kwd_only):
28+
print(pos_only, standard, kwd_only)
29+
'''
30+
31+
expected_ast = ast.parse(source)
32+
actual_ast = unparse(expected_ast)
33+
compare_ast(expected_ast, ast.parse(actual_ast))

0 commit comments

Comments
 (0)