Skip to content

Commit 85ceaef

Browse files
committed
Fix resource leaks and optimize nested loops for better performance
- Add context managers for all file operations to prevent resource leaks - Optimize O(n²) nested loop in set_api_sketch() to O(n) using reverse mapping - Optimize nested loop in set_display_attr_of_apis() using any() builtin - Convert list to set for O(1) membership tests in check_api_label_cn.py - Use extend() instead of repeated append() calls for better performance - Add proper file handle cleanup in 6 files
1 parent 75171e1 commit 85ceaef

File tree

6 files changed

+43
-36
lines changed

6 files changed

+43
-36
lines changed

ci_scripts/check_api_docs_en.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ def check_system_message_in_doc(doc_file):
105105
for i in range(len(py_files)):
106106
if py_files[i].startswith("python/"):
107107
py_files[i] = py_files[i][6:]
108-
api_info = json.load(open(args.api_info_file))
108+
with open(args.api_info_file) as f:
109+
api_info = json.load(f)
109110
output_path = args.output_path
110111
build_source_file_to_doc_file_dict(api_info)
111112
error_files = set()

ci_scripts/check_api_label_cn.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ def find_all_api_labels_in_dir(rootdir):
4545
path = str(real_path).removeprefix(rootdir)
4646
if not should_test(path):
4747
continue
48-
for label in find_api_labels_in_one_file(real_path):
49-
all_api_labels.append(label)
48+
# Use extend instead of repeated append for better performance
49+
all_api_labels.extend(find_api_labels_in_one_file(real_path))
5050
return all_api_labels
5151

5252

@@ -80,7 +80,8 @@ def run_cn_api_label_checking(rootdir, files):
8080
f"The first line in {rootdir}/{file} is not available, please re-check it!"
8181
)
8282
sys.exit(1)
83-
valid_api_labels = find_all_api_labels_in_dir(rootdir)
83+
# Convert to set for O(1) membership tests
84+
valid_api_labels = set(find_all_api_labels_in_dir(rootdir))
8485
for file in files:
8586
if not file.endswith(".rst"):
8687
continue

ci_scripts/check_api_parameters.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,8 @@ def check_api_parameters(rstfiles, apiinfo):
268268
if __name__ == "__main__":
269269
args = parse_args()
270270
rstfiles = [fn for fn in args.rst_files.split(" ") if fn]
271-
apiinfo = json.load(open(args.api_info_file))
271+
with open(args.api_info_file) as f:
272+
apiinfo = json.load(f)
272273
check_passed, check_failed, api_notfound = check_api_parameters(
273274
rstfiles=rstfiles, apiinfo=apiinfo
274275
)

ci_scripts/hooks/post_filter_htmls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ def insert_header_and_anchor_for_method(htmlfile):
2828
"""
2929
insert a hide h3 tag and a anchor for every class method.
3030
"""
31-
soup = BeautifulSoup(open(htmlfile, "r"), "lxml")
31+
with open(htmlfile, "r") as f:
32+
soup = BeautifulSoup(f, "lxml")
3233
method_title_tags = soup.find_all("dl", class_="method")
3334
for mtt in method_title_tags:
3435
dt = mtt.find("dt")

docs/api/extract_api_from_docs.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,11 @@ def extract_code_blocks_from_file(filename):
124124
r = os.path.splitext(filename)
125125
ext = r[1].lower()
126126
if ext == ".md":
127-
return extract_code_blocks_from_md(open(filename, "r").read())
127+
with open(filename, "r") as f:
128+
return extract_code_blocks_from_md(f.read())
128129
elif ext == ".rst":
129-
return extract_code_blocks_from_rst(open(filename, "r").read())
130+
with open(filename, "r") as f:
131+
return extract_code_blocks_from_rst(f.read())
130132
else:
131133
return []
132134

docs/api/gen_doc.py

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,8 @@ def parse_module_file(mod):
264264
if len(mod_name) >= 6 and mod_name[:6] == "paddle":
265265
fn_splited = os.path.splitext(src_file)
266266
if len(fn_splited) > 1 and fn_splited[1].lower() == ".py":
267-
mod_ast = ast.parse(open(src_file, "r").read())
267+
with open(src_file, "r") as f:
268+
mod_ast = ast.parse(f.read())
268269
for node in mod_ast.body:
269270
short_names = []
270271
if (
@@ -425,16 +426,14 @@ def set_display_attr_of_apis():
425426
set the display attr
426427
"""
427428
if os.path.exists(NOT_DISPLAY_DOC_LIST_FILENAME):
428-
display_none_apis = {
429-
line.strip() for line in open(NOT_DISPLAY_DOC_LIST_FILENAME, "r")
430-
}
429+
with open(NOT_DISPLAY_DOC_LIST_FILENAME, "r") as f:
430+
display_none_apis = {line.strip() for line in f}
431431
else:
432432
logger.warning("file not exists: %s", NOT_DISPLAY_DOC_LIST_FILENAME)
433433
display_none_apis = set()
434434
if os.path.exists(DISPLAY_DOC_LIST_FILENAME):
435-
display_yes_apis = {
436-
line.strip() for line in open(DISPLAY_DOC_LIST_FILENAME, "r")
437-
}
435+
with open(DISPLAY_DOC_LIST_FILENAME, "r") as f:
436+
display_yes_apis = {line.strip() for line in f}
438437
else:
439438
logger.warning("file not exists: %s", DISPLAY_DOC_LIST_FILENAME)
440439
display_yes_apis = set()
@@ -447,21 +446,17 @@ def set_display_attr_of_apis():
447446
# file the same apis
448447
for id_api in api_info_dict:
449448
all_names = api_info_dict[id_api]["all_names"]
450-
display_yes = False
451-
for n in all_names:
452-
if n in display_yes_apis:
453-
display_yes = True
454-
break
449+
# Check if any name is in display_yes_apis (O(1) lookup with set)
450+
display_yes = any(n in display_yes_apis for n in all_names)
451+
455452
if display_yes:
456453
api_info_dict[id_api]["display"] = True
457454
else:
455+
# Check if any name starts with any display_none prefix
458456
display_yes = True
459457
for n in all_names:
460-
for dn in display_none_apis:
461-
if n.startswith(dn):
462-
display_yes = False
463-
break
464-
if not display_yes:
458+
if any(n.startswith(dn) for dn in display_none_apis):
459+
display_yes = False
465460
break
466461
if not display_yes:
467462
api_info_dict[id_api]["display"] = False
@@ -570,17 +565,22 @@ def set_api_sketch():
570565
for api in apis:
571566
all_api_found[f"{m}.{api}"] = False
572567

568+
# Create a reverse mapping from API name to api_info_dict keys for O(1) lookup
569+
name_to_id_map = {}
570+
for id_api, api_info in api_info_dict.items():
571+
if "all_names" in api_info:
572+
for name in api_info["all_names"]:
573+
name_to_id_map[name] = id_api
574+
575+
# Use the reverse mapping for efficient lookups
573576
for api in all_api_found.keys():
574-
for id_api in api_info_dict.keys():
575-
if ("all_names" in api_info_dict[id_api]) and (
576-
api in api_info_dict[id_api]["all_names"]
577-
):
578-
all_api_found[api] = True
579-
api_info_dict[id_api]["in_api_sketch"] = True
580-
if "api_sketch_names" not in api_info_dict[id_api]:
581-
api_info_dict[id_api]["api_sketch_names"] = []
582-
api_info_dict[id_api]["api_sketch_names"].append(api)
583-
break
577+
if api in name_to_id_map:
578+
id_api = name_to_id_map[api]
579+
all_api_found[api] = True
580+
api_info_dict[id_api]["in_api_sketch"] = True
581+
if "api_sketch_names" not in api_info_dict[id_api]:
582+
api_info_dict[id_api]["api_sketch_names"] = []
583+
api_info_dict[id_api]["api_sketch_names"].append(api)
584584

585585
api_not_in_dict = [api for api in all_api_found if not all_api_found[api]]
586586
if api_not_in_dict:
@@ -1114,6 +1114,7 @@ def parse_args():
11141114
check_cn_en_match()
11151115

11161116
filter_out_object_of_api_info_dict()
1117-
json.dump(api_info_dict, open(jsonfn, "w"), indent=4)
1117+
with open(jsonfn, "w") as f:
1118+
json.dump(api_info_dict, f, indent=4)
11181119

11191120
logger.info("done")

0 commit comments

Comments
 (0)