Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jantic
GitHub Repository: jantic/deoldify
Path: blob/master/fastai/gen_doc/docstrings.py
781 views
1
# https://github.com/openstack/rally/blob/master/rally/common/plugin/info.py
2
# Copyright 2015: Mirantis Inc.
3
# All Rights Reserved.
4
#
5
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6
# not use this file except in compliance with the License. You may obtain
7
# a copy of the License at
8
#
9
# http://www.apache.org/licenses/LICENSE-2.0
10
#
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
# License for the specific language governing permissions and limitations
15
# under the License.
16
17
import re
18
import sys
19
20
__all__ = ['parse_docstring']
21
22
23
FIELDS = 'param|val' # supported fields
24
PARAM_OR_RETURN_REGEX = re.compile(f":(?:{FIELDS}|return)")
25
RETURN_REGEX = re.compile(":return: (?P<doc>.*)", re.S)
26
NEW_REGEX = re.compile(f":(?P<field>{FIELDS}) (?P<name>[\*\w]+): (?P<doc>.*?)"
27
f"(?:(?=:(?:{FIELDS}|return|raises))|\Z)", re.S)
28
29
def trim(docstring):
30
"""trim function from PEP-257"""
31
if not docstring:
32
return ""
33
# Convert tabs to spaces (following the normal Python rules)
34
# and split into a list of lines:
35
lines = docstring.expandtabs().splitlines()
36
# Determine minimum indentation (first line doesn't count):
37
indent = sys.maxsize
38
for line in lines[1:]:
39
stripped = line.lstrip()
40
if stripped:
41
indent = min(indent, len(line) - len(stripped))
42
# Remove indentation (first line is special):
43
trimmed = [lines[0].strip()]
44
if indent < sys.maxsize:
45
for line in lines[1:]:
46
trimmed.append(line[indent:].rstrip())
47
# Strip off trailing and leading blank lines:
48
while trimmed and not trimmed[-1]:
49
trimmed.pop()
50
while trimmed and not trimmed[0]:
51
trimmed.pop(0)
52
53
# Current code/unittests expects a line return at
54
# end of multiline docstrings
55
# workaround expected behavior from unittests
56
if "\n" in docstring:
57
trimmed.append("")
58
59
# Return a single string:
60
return "\n".join(trimmed)
61
62
63
def reindent(string):
64
return "\n".join(l.strip() for l in string.strip().split("\n"))
65
66
67
def parse_docstring(docstring):
68
"""Parse the docstring into its components.
69
70
:return: a dictionary of form
71
{
72
"short_description": ...,
73
"long_description": ...,
74
"params": [{"name": ..., "doc": ...}, ...],
75
"vals": [{"name": ..., "doc": ...}, ...],
76
"return": ...
77
}
78
"""
79
80
short_description = long_description = return_str = ""
81
args = []
82
83
if docstring:
84
docstring = trim(docstring.lstrip("\n"))
85
86
lines = docstring.split("\n", 1)
87
short_description = lines[0]
88
89
if len(lines) > 1:
90
long_description = lines[1].strip()
91
92
params_return_desc = None
93
94
match = PARAM_OR_RETURN_REGEX.search(long_description)
95
if match:
96
long_desc_end = match.start()
97
params_return_desc = long_description[long_desc_end:].strip()
98
long_description = long_description[:long_desc_end].rstrip()
99
100
if params_return_desc:
101
args = [
102
{"name": name, "doc": trim(doc), "field": field}
103
for field, name, doc in NEW_REGEX.findall(params_return_desc)
104
]
105
match = RETURN_REGEX.search(params_return_desc)
106
if match:
107
return_str = reindent(match.group("doc"))
108
comments = {p['name']: p['doc'] for p in args}
109
return {
110
"short_description": short_description,
111
"long_description": long_description,
112
"args": args,
113
"comments": comments,
114
"return": return_str
115
}
116
117
118
class InfoMixin(object):
119
120
@classmethod
121
def _get_doc(cls):
122
"""Return documentary of class
123
124
By default it returns docstring of class, but it can be overridden
125
for example for cases like merging own docstring with parent
126
"""
127
return cls.__doc__
128
129
@classmethod
130
def get_info(cls):
131
doc = parse_docstring(cls._get_doc())
132
133
return {
134
"name": cls.get_name(),
135
"platform": cls.get_platform(),
136
"module": cls.__module__,
137
"title": doc["short_description"],
138
"description": doc["long_description"],
139
"parameters": doc["params"],
140
"schema": getattr(cls, "CONFIG_SCHEMA", None),
141
"return": doc["return"]
142
}
143
144