Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 367
Expand file tree
/
Copy pathdocstring.py
More file actions
Latest commit
executable file
·101 lines (85 loc) · 3.61 KB
/
Copy pathdocstring.py
File metadata and controls
executable file
·101 lines (85 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#!/usr/bin/env python
importast
importpathlib
importre
defget_docstring_args(fd, file_name, func_name, class_name=None):
"""
Extract docstring parameters from function definition
"""
docstring=ast.get_docstring(fd)
ifdocstringisNoneorlen(re.findall(r"Parameters", docstring)) !=1:
msg="Missing required 'Parameters' section in docstring in \n"
msg+=f"file: {file_name}\n"
ifclass_nameisnotNone:
msg+=f"class: {class_name}\n"
msg+=f"function/method: {func_name}\n"
raiseRuntimeError(msg)
iflen(re.findall(r"Returns", docstring)) !=1:
msg="Missing required 'Returns' section in docstring in \n"
msg+=f"file: {file_name}\n"
ifclass_nameisnotNone:
msg+=f"class: {class_name}\n"
msg+=f"function/method: {func_name}\n"
raiseRuntimeError(msg)
params_section=re.findall(
r"(?<=Parameters)(.*)(?=Returns)", docstring, re.DOTALL
)[0]
args=re.findall(r"(\w+)\s+\:", params_section)
args=set([aforainargsifa!="i"]) # `i` should never be a parameter
returnargs
defget_signature_args(fd):
"""
Extract signature arguments from function definition
"""
returnset([a.argforainfd.args.argsifa.arg!="self"])
defcheck_args(doc_args, sig_args, file_name, func_name, class_name=None):
"""
Compare docstring arguments and signature argments
"""
diff_args=sig_args.difference(doc_args)
iflen(diff_args) >0:
msg="Found one or more arguments/parameters with missing docstring in \n"
msg+=f"file: {file_name}\n"
ifclass_nameisnotNone:
msg+=f"class: {class_name}\n"
msg+=f"function/method: {func_name}\n"
msg+=f"parameter(s): {diff_args}\n"
raiseRuntimeError(msg)
diff_args=doc_args.difference(sig_args)
iflen(diff_args) >0:
msg="Found one or more unsupported arguments/parameters with docstring in \n"
msg+=f"file: {file_name}\n"
ifclass_nameisnotNone:
msg+=f"class: {class_name}\n"
msg+=f"function/method: {func_name}\n"
msg+=f"parameter(s): {diff_args}\n"
raiseRuntimeError(msg)
ignore= ["__init__.py", "__pycache__"]
stumpy_path=pathlib.Path(__file__).parent/"stumpy"
filepaths=sorted(fforfinpathlib.Path(stumpy_path).iterdir() iff.is_file())
forfilepathinfilepaths:
iffilepath.namenotinignoreandstr(filepath).endswith(".py"):
file_contents=""
withopen(filepath, encoding="utf8") asf:
file_contents=f.read()
module=ast.parse(file_contents)
# Check Functions
function_definitions= [
nodefornodeinmodule.bodyifisinstance(node, ast.FunctionDef)
]
forfdinfunction_definitions:
docstring_args=get_docstring_args(fd, filepath.name, fd.name)
signature_args=get_signature_args(fd)
check_args(docstring_args, signature_args, filepath.name, fd.name)
# Check Class Methods
class_definitions= [
nodefornodeinmodule.bodyifisinstance(node, ast.ClassDef)
]
forcdinclass_definitions:
methods= [nodefornodeincd.bodyifisinstance(node, ast.FunctionDef)]
forfdinmethods:
docstring_args=get_docstring_args(fd, filepath.name, fd.name, cd.name)
signature_args=get_signature_args(fd)
check_args(
docstring_args, signature_args, filepath.name, fd.name, cd.name
)