Skip to content

Commit 5d6af26

Browse files
authored
Update: Support position only arguments in methods (#374)
1 parent a3f9a75 commit 5d6af26

File tree

5 files changed

+272
-222
lines changed

5 files changed

+272
-222
lines changed

src/fake_bpy_module/analyzer/directives.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,14 @@ def parse_function_def(content: str) -> str:
5151
content.strip()
5252

5353
m = _ARG_LIST_FROM_FUNC_DEF_REGEX.search(content)
54+
assert m
5455
name = m.group(1)
5556
params = split_string_by_comma(m.group(2))
5657

5758
# (test=DirectivesTest.test_invalid_function_arg_order)
5859
# Handle case:
5960
# function_1(arg_1, arg_2, arg_3='NONE', arg_4=True, arg_5): pass
60-
fixed_params = []
61+
fixed_params: list[str] = []
6162
required_named_argument = False
6263
for param in params:
6364
p = param.strip()
@@ -66,10 +67,13 @@ def parse_function_def(content: str) -> str:
6667
if len(sp) == 1:
6768
if required_named_argument:
6869
if p == "*":
70+
# Argument without default values are allowed after *.
6971
required_named_argument = False
70-
if p.startswith("*"):
72+
if p.startswith("*") or p == "/":
73+
# *args, **kwargs, /
7174
fixed_params.append(p)
7275
else:
76+
# Have to add default value to keep signature valid.
7377
fixed_params.append(f"{p}=None")
7478
else:
7579
fixed_params.append(p)
@@ -198,16 +202,23 @@ def build_function_node_from_def(fdef: str) -> FunctionNode:
198202

199203
# Get function signature.
200204
arg_list_node = func_node.element(ArgumentListNode)
201-
for i, arg in enumerate(func_def.args.args):
205+
arguments = func_def.args
206+
207+
# Positional args.
208+
pos_args = arguments.posonlyargs + arguments.args
209+
pos_args_types = ("posonlyarg",) * len(arguments.posonlyargs)
210+
pos_args_types += ("arg",) * len(arguments.args)
211+
default_start = len(pos_args) - len(arguments.defaults)
212+
args_iterator = enumerate(zip(pos_args_types, pos_args, strict=True))
213+
for i, (arg_type, arg) in args_iterator:
202214
# Remove self argument which will be added later.
203215
if i == 0 and arg.arg == "self":
204216
continue
205-
arg_node = ArgumentNode.create_template(argument_type="arg")
217+
arg_node = ArgumentNode.create_template(argument_type=arg_type)
206218
arg_node.element(NameNode).add_text(arg.arg)
207-
default_start = \
208-
len(func_def.args.args) - len(func_def.args.defaults)
209219
if i >= default_start:
210-
default = func_def.args.defaults[i - default_start]
220+
default = arguments.defaults[i - default_start]
221+
211222
default_value = parse_func_arg_default_value(default)
212223
if default_value is not None:
213224
arg_node.element(DefaultValueNode).add_text(default_value)
@@ -514,7 +525,7 @@ def run(self) -> list[FunctionNode]:
514525
deprecated_str = func_name[index:]
515526
func_name = func_name[0:index]
516527

517-
func_defs = []
528+
func_defs: list[str] = []
518529
fdef_str: str = ""
519530
for fdef in func_name.split("\n"):
520531
if fdef[-1] == "\\":

src/fake_bpy_module/analyzer/nodes.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import abc
2-
from typing import Self, TypeVar
2+
from typing import Literal, Self, TypeVar
33

44
from docutils import nodes
55

@@ -20,7 +20,7 @@ def append_child(self, item: nodes.Node) -> None:
2020
class UniqueElementNode(NodeBase):
2121
# pylint: disable=W1113
2222
def __init__(self, rawsource: str = "", *children: nodes.Node,
23-
**attributes: dict) -> None:
23+
**attributes: str) -> None:
2424
super().__init__(rawsource, *children, **attributes)
2525

2626
self.elements = {}
@@ -127,7 +127,7 @@ class DataNode(UniqueElementNode, nodes.Part):
127127
@classmethod
128128
def create_template(
129129
cls, rawsource: str = "",
130-
*children: nodes.Node, **attributes: dict) -> Self:
130+
*children: nodes.Node, **attributes: str) -> Self:
131131
node = cls(rawsource, *children, **attributes)
132132

133133
node.append_child(NameNode())
@@ -145,7 +145,7 @@ class AttributeNode(DataNode):
145145
@classmethod
146146
def create_template(
147147
cls, rawsource: str = "",
148-
*children: nodes.Node, **attributes: dict) -> Self:
148+
*children: nodes.Node, **attributes: str) -> Self:
149149
node = cls(rawsource, *children, **attributes)
150150

151151
node.append_child(NameNode())
@@ -171,12 +171,13 @@ class ArgumentListNode(ListNode):
171171
class ArgumentNode(UniqueElementNode, nodes.Part):
172172
tagname = "argument"
173173
child_text_separator = ""
174+
ArgumentType = Literal["posonlyarg", "arg", "vararg", "kwonlyarg", "kwarg"]
174175

175176
# pylint: disable=W1113
176177
@classmethod
177178
def create_template(
178179
cls, rawsource: str = "",
179-
*children: nodes.Node, **attributes: dict) -> Self:
180+
*children: nodes.Node, **attributes: str) -> Self:
180181
node = cls(rawsource, *children, **attributes)
181182

182183
node.append_child(NameNode())
@@ -195,7 +196,7 @@ class FunctionReturnNode(UniqueElementNode, nodes.Part):
195196
@classmethod
196197
def create_template(
197198
cls, rawsource: str = "",
198-
*children: nodes.Node, **attributes: dict) -> Self:
199+
*children: nodes.Node, **attributes: str) -> Self:
199200
node = cls(rawsource, *children, **attributes)
200201

201202
node.append_child(DescriptionNode())
@@ -215,7 +216,7 @@ class FunctionNode(UniqueElementNode, nodes.Part):
215216
@classmethod
216217
def create_template(
217218
cls, rawsource: str = "",
218-
*children: nodes.Node, **attributes: dict) -> Self:
219+
*children: nodes.Node, **attributes: str) -> Self:
219220
node = cls(rawsource, *children, **attributes)
220221

221222
node.append_child(NameNode())
@@ -239,7 +240,7 @@ class BaseClassNode(UniqueElementNode, nodes.Part):
239240
@classmethod
240241
def create_template(
241242
cls, rawsource: str = "",
242-
*children: nodes.Node, **attributes: dict) -> Self:
243+
*children: nodes.Node, **attributes: str) -> Self:
243244
node = cls(rawsource, *children, **attributes)
244245

245246
node.append_child(DataTypeListNode())
@@ -255,7 +256,7 @@ class ClassNode(UniqueElementNode, nodes.Part):
255256
@classmethod
256257
def create_template(
257258
cls, rawsource: str = "",
258-
*children: nodes.Node, **attributes: dict) -> Self:
259+
*children: nodes.Node, **attributes: str) -> Self:
259260
node = cls(rawsource, *children, **attributes)
260261

261262
node.append_child(NameNode())
@@ -275,7 +276,7 @@ class ModuleNode(UniqueElementNode, nodes.Part):
275276
@classmethod
276277
def create_template(
277278
cls, rawsource: str = "",
278-
*children: nodes.Node, **attributes: dict) -> Self:
279+
*children: nodes.Node, **attributes: str) -> Self:
279280
node = cls(rawsource, *children, **attributes)
280281

281282
node.append_child(NameNode())
@@ -297,7 +298,7 @@ class EnumItemNode(UniqueElementNode, nodes.Part):
297298
@classmethod
298299
def create_template(
299300
cls, rawsource: str = "",
300-
*children: nodes.Node, **attributes: dict) -> Self:
301+
*children: nodes.Node, **attributes: str) -> Self:
301302
node = cls(rawsource, *children, **attributes)
302303

303304
node.append_child(NameNode())
@@ -319,7 +320,7 @@ class EnumNode(UniqueElementNode, nodes.Part):
319320
@classmethod
320321
def create_template(
321322
cls, rawsource: str = "",
322-
*children: nodes.Node, **attributes: dict) -> Self:
323+
*children: nodes.Node, **attributes: str) -> Self:
323324
node = cls(rawsource, *children, **attributes)
324325

325326
node.append_child(NameNode())

0 commit comments

Comments
 (0)