Skip to content

Commit 7aff219

Browse files
committed
refine_func_args_parse
1 parent 31f275f commit 7aff219

File tree

3 files changed

+104
-68
lines changed

3 files changed

+104
-68
lines changed

ci_scripts/check_api_parameters.py

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ def add_path(path):
2929
this_dir = osp.dirname(__file__)
3030
# Add docs/api to PYTHONPATH
3131
add_path(osp.abspath(osp.join(this_dir, "..", "docs", "api")))
32-
from extract_api_from_docs import extract_params_desc_from_rst_file
32+
from extract_api_from_docs import (
33+
extract_params_desc_from_rst_file,
34+
gen_functions_args_str,
35+
)
3336

3437
arguments = [
3538
# flags, dest, type, default, help
@@ -60,37 +63,11 @@ def _check_params_in_description(rstfilename, paramstr):
6063
params_in_title = []
6164
if paramstr:
6265
fake_func = ast.parse(f"def fake_func({paramstr}): pass")
63-
# Iterate over all in_title parameters
64-
num_defaults = len(fake_func.body[0].args.defaults)
65-
num_args = len(fake_func.body[0].args.args)
66-
# args & defaults
67-
for i, arg in enumerate(fake_func.body[0].args.args):
68-
if i >= num_args - num_defaults:
69-
default_value = fake_func.body[0].args.defaults[
70-
i - (num_args - num_defaults)
71-
]
72-
params_in_title.append(f"{arg.arg}={default_value}")
73-
else:
74-
params_in_title.append(arg.arg)
75-
# posonlyargs
76-
for arg in fake_func.body[0].args.posonlyargs:
77-
params_in_title.append(arg.arg)
78-
# vararg(*args)
79-
if fake_func.body[0].args.vararg:
80-
params_in_title.append(fake_func.body[0].args.vararg.arg)
81-
# kwonlyargs & kw_defaults
82-
for i, arg in enumerate(fake_func.body[0].args.kwonlyargs):
83-
if (
84-
i < len(fake_func.body[0].args.kw_defaults)
85-
and fake_func.body[0].args.kw_defaults[i] is not None
86-
):
87-
default_value = fake_func.body[0].args.kw_defaults[i]
88-
params_in_title.append(f"{arg.arg}={default_value}")
89-
else:
90-
params_in_title.append(arg.arg)
91-
# **kwargs
92-
if fake_func.body[0].args.kwarg:
93-
params_in_title.append(fake_func.body[0].args.kwarg.arg)
66+
func_node = fake_func.body[0]
67+
func_args_str = gen_functions_args_str(func_node)
68+
params_in_title = func_args_str.split(", ")
69+
params_in_title.remove("/")
70+
params_in_title.remove("*")
9471

9572
funcdescnode = extract_params_desc_from_rst_file(rstfilename)
9673
if funcdescnode:
@@ -141,11 +118,35 @@ def _check_params_in_description(rstfilename, paramstr):
141118
def _check_params_in_description_with_fullargspec(rstfilename, funcname):
142119
flag = True
143120
info = ""
144-
funcspec = inspect.getfullargspec(eval(funcname))
121+
try:
122+
func = eval(funcname)
123+
except NameError:
124+
func = eval(funcname)
125+
source = inspect.getsource(func)
126+
127+
class FunctionDefExtractor(ast.NodeTransformer):
128+
target_name = func.__name__
129+
130+
def visit_FunctionDef(self, node):
131+
if node.name == self.target_name:
132+
node.decorator_list = []
133+
node.body = [ast.Pass()]
134+
return node
135+
return None
136+
137+
tree = ast.parse(source)
138+
modified_tree = FunctionDefExtractor().visit(tree)
139+
modified_tree.body = [
140+
node for node in modified_tree.body if node is not None
141+
]
142+
143+
func_node = modified_tree.body[0]
144+
params_inspec = gen_functions_args_str(func_node).split(", ")
145+
params_inspec.remove("/")
146+
params_inspec.remove("*")
145147
funcdescnode = extract_params_desc_from_rst_file(rstfilename)
146148
if funcdescnode:
147149
items = funcdescnode.children[1].children[0].children
148-
params_inspec = funcspec.args
149150
if len(items) != len(params_inspec):
150151
flag = False
151152
info = f"check_with_fullargspec failed (parammeters description): {rstfilename}"
@@ -171,10 +172,10 @@ def _check_params_in_description_with_fullargspec(rstfilename, funcname):
171172
f"check failed (parammeters description): {rstfilename}, param name not found in {i} paragraph."
172173
)
173174
else:
174-
if funcspec.args:
175+
if params_inspec:
175176
info = "params section not found in description, check it please."
176177
print(
177-
f"check failed (parameters description not found): {rstfilename}, {funcspec.args}."
178+
f"check failed (parameters description not found): {rstfilename}, {params_inspec}."
178179
)
179180
flag = False
180181
return flag, info

ci_scripts/ci_start.sh

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,17 @@ if [ "${BUILD_DOC}" = "true" ] && [ -x /usr/local/bin/sphinx-build ] ; then
8383
fi
8484
fi
8585

86+
git merge --no-edit upstream/${BRANCH}
87+
need_check_cn_doc_files=$(find_all_cn_api_files_modified_by_pr)
88+
echo $need_check_cn_doc_files
89+
90+
# Check for existing stock issues.
91+
find_cn_rst_files() {
92+
local search_dir="$SCRIPT_DIR/../docs/api/paddle"
93+
find "$search_dir" -type f -name "*_cn.rst"
94+
}
95+
all_api_cn_files=$(find_cn_rst_files)
96+
8697
check_parameters=ON
8798
if [ "${check_parameters}" = "OFF" ] ; then
8899
#echo "chinese api doc fileslist is empty, skip check."
@@ -91,7 +102,7 @@ else
91102
jsonfn=${OUTPUTDIR}/en/${VERSIONSTR}/gen_doc_output/api_info_all.json
92103
if [ -f $jsonfn ] ; then
93104
echo "$jsonfn exists."
94-
/bin/bash ${DIR_PATH}/check_api_parameters.sh "${need_check_cn_doc_files}" ${jsonfn}
105+
/bin/bash ${DIR_PATH}/check_api_parameters.sh "${all_api_cn_files}" ${jsonfn}
95106
if [ $? -ne 0 ];then
96107
exit 1
97108
fi
@@ -109,9 +120,6 @@ if [ $? -ne 0 ];then
109120
EXIT_CODE=1
110121
fi
111122

112-
git merge --no-edit upstream/${BRANCH}
113-
need_check_cn_doc_files=$(find_all_cn_api_files_modified_by_pr)
114-
echo $need_check_cn_doc_files
115123
# 4 Chinese api docs check
116124
if [ "${need_check_cn_doc_files}" = "" ] ; then
117125
echo "chinese api doc fileslist is empty, skip check."

docs/api/gen_doc.py

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -362,36 +362,63 @@ def parse_module_file(mod):
362362

363363

364364
def gen_functions_args_str(node):
365+
def _process_positional_args(args, params):
366+
positional_args = args.posonlyargs + args.args
367+
num_defaults = len(args.defaults)
368+
369+
total_positional = len(positional_args)
370+
first_default_pos = total_positional - num_defaults
371+
if args.posonlyargs:
372+
for idx, arg in enumerate(args.posonlyargs):
373+
if arg.arg == "self":
374+
continue
375+
param = _format_arg_with_default(
376+
arg, idx, first_default_pos, args.defaults
377+
)
378+
params.append(param)
379+
params.append("/")
380+
381+
for idx, arg in enumerate(args.args):
382+
if arg.arg == "self":
383+
continue
384+
global_idx = idx + len(args.posonlyargs)
385+
param = _format_arg_with_default(
386+
arg, global_idx, first_default_pos, args.defaults
387+
)
388+
params.append(param)
389+
390+
def _format_arg_with_default(arg, index, first_default_pos, defaults):
391+
if first_default_pos is not None and index >= first_default_pos:
392+
default_index = index - first_default_pos
393+
defarg_value = ast.unparse(defaults[default_index]).strip()
394+
return f"{arg.arg}={defarg_value}"
395+
return arg.arg
396+
397+
def _process_var_args(args, params):
398+
if args.vararg:
399+
params.append(f"*{args.vararg.arg}")
400+
elif args.kwonlyargs:
401+
params.append("*")
402+
403+
def _process_kwonly_args(args, params):
404+
for idx, arg in enumerate(args.kwonlyargs):
405+
if default := args.kw_defaults[idx]:
406+
default_str = ast.unparse(default).strip()
407+
params.append(f"{arg.arg}={default_str}")
408+
else:
409+
params.append(arg.arg)
410+
411+
def _process_kwargs(args, params):
412+
if args.kwarg:
413+
params.append(f"**{args.kwarg.arg}")
414+
365415
str_args_list = []
366416
if isinstance(node, ast.FunctionDef):
367-
# 'args', 'defaults', 'kw_defaults', 'kwarg', 'kwonlyargs', 'posonlyargs', 'vararg'
368-
for arg in node.args.args:
369-
if not arg.arg == "self":
370-
str_args_list.append(arg.arg)
371-
372-
defarg_ind_start = len(str_args_list) - len(node.args.defaults)
373-
for defarg_ind in range(len(node.args.defaults)):
374-
if isinstance(node.args.defaults[defarg_ind], ast.Name):
375-
str_args_list[defarg_ind_start + defarg_ind] += "=" + str(
376-
node.args.defaults[defarg_ind].id
377-
)
378-
elif isinstance(node.args.defaults[defarg_ind], ast.Constant):
379-
defarg_val = str(node.args.defaults[defarg_ind].value)
380-
if isinstance(node.args.defaults[defarg_ind].value, str):
381-
defarg_val = f"'{defarg_val}'"
382-
str_args_list[defarg_ind_start + defarg_ind] += "=" + defarg_val
383-
if node.args.vararg is not None:
384-
str_args_list.append("*" + node.args.vararg.arg)
385-
if len(node.args.kwonlyargs) > 0:
386-
if node.args.vararg is None:
387-
str_args_list.append("*")
388-
for kwoarg, d in zip(node.args.kwonlyargs, node.args.kw_defaults):
389-
if isinstance(d, ast.Constant):
390-
str_args_list.append(f"{kwoarg.arg}={d.value}")
391-
elif isinstance(d, ast.Name):
392-
str_args_list.append(f"{kwoarg.arg}={d.id}")
393-
if node.args.kwarg is not None:
394-
str_args_list.append("**" + node.args.kwarg.arg)
417+
func_args = node.args
418+
_process_positional_args(func_args, str_args_list)
419+
_process_var_args(func_args, str_args_list)
420+
_process_kwonly_args(func_args, str_args_list)
421+
_process_kwargs(func_args, str_args_list)
395422

396423
return ", ".join(str_args_list)
397424

0 commit comments

Comments
 (0)