py2docfx 0.1.1rc1538122__py3-none-any.whl → 0.1.1rc1634530__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,24 +26,161 @@ scientific_notation_regex = re.compile(r'^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)$
26
26
  def string_representer(dumper, data):
27
27
  return dumper.represent_scalar(u"tag:yaml.org,2002:str", data,
28
28
  style="'" if (scientific_notation_regex.match(data)) else None)
29
+
29
30
  yml.add_representer(str, string_representer)
30
31
 
32
+ def merge_params(arg_params, doc_params):
33
+ merged_params = deepcopy(doc_params)
34
+ # merge arg_params into merged_params
35
+ for arg_param in arg_params:
36
+ for merged_param in merged_params:
37
+ if arg_param['id'] == merged_param['id']:
38
+ if "defaultValue" in arg_param.keys():
39
+ merged_param["defaultValue"] = arg_param["defaultValue"]
40
+ if "type" in arg_param.keys():
41
+ merged_param["type"] = arg_param["type"]
42
+ if "isRequired" in arg_param.keys():
43
+ if arg_param["isRequired"] == False:
44
+ merged_param["isRequired"] = arg_param["isRequired"]
45
+ break
46
+ else:
47
+ merged_params.append(arg_param)
48
+ return merged_params
49
+
50
+ def remove_params_without_id(params):
51
+ new_params = []
52
+ for param in params:
53
+ if 'id' in param:
54
+ new_params.append(param)
55
+ return new_params
56
+
57
+ def add_isrequired_if_needed(obj, key: str):
58
+ if key in obj['syntax'] and obj['type'] in ['class', 'function', 'method']:
59
+ for args in obj['syntax'][key]:
60
+ if 'isRequired' not in args and 'defaultValue' not in args:
61
+ args['isRequired'] = True
62
+
63
+ def get_merged_params(obj, info_field_data, key: str):
64
+ merged_params = []
65
+ arg_params = obj.get('syntax', {}).get(key, [])
66
+ if key in info_field_data[obj['uid']]:
67
+ doc_params = info_field_data[obj['uid']].get(
68
+ key, [])
69
+ if arg_params and doc_params:
70
+ if len(arg_params) - len(doc_params) > 0:
71
+ print("Documented params don't match size of params:"" {}".format(obj['uid'])) # lgtm [py/clear-text-logging-sensitive-data]
72
+ doc_params = remove_params_without_id(doc_params)
73
+ merged_params = merge_params(arg_params, doc_params)
74
+ else:
75
+ merged_params = arg_params
76
+
77
+ return merged_params
78
+
79
+ def raise_up_fields(obj):
80
+ # Raise up summary
81
+ if 'summary' in obj['syntax'] and obj['syntax']['summary']:
82
+ obj['summary'] = obj['syntax'].pop(
83
+ 'summary').strip(" \n\r\r")
84
+
85
+ # Raise up remarks
86
+ if 'remarks' in obj['syntax'] and obj['syntax']['remarks']:
87
+ obj['remarks'] = obj['syntax'].pop('remarks')
88
+
89
+ # Raise up seealso
90
+ if 'seealso' in obj['syntax'] and obj['syntax']['seealso']:
91
+ obj['seealsoContent'] = obj['syntax'].pop('seealso')
92
+
93
+ # Raise up example
94
+ if 'example' in obj['syntax'] and obj['syntax']['example']:
95
+ obj.setdefault('example', []).append(
96
+ obj['syntax'].pop('example'))
97
+
98
+ # Raise up exceptions
99
+ if 'exceptions' in obj['syntax'] and obj['syntax']['exceptions']:
100
+ obj['exceptions'] = obj['syntax'].pop('exceptions')
101
+
102
+ # Raise up references
103
+ if 'references' in obj['syntax'] and obj['syntax']['references']:
104
+ obj.setdefault('references', []).extend(
105
+ obj['syntax'].pop('references'))
106
+
107
+ def merge_data(obj, info_field_data, yaml_data):
108
+ # Avoid entities with same uid and diff type.
109
+ # Delete `type` temporarily
110
+ del(info_field_data[obj['uid']]['type'])
111
+ if 'syntax' not in obj:
112
+ obj['syntax'] = {}
113
+ merged_params = get_merged_params(obj, info_field_data, 'parameters')
114
+ merged_kwargs = get_merged_params(obj, info_field_data, 'keywordOnlyParameters')
115
+
116
+ obj['syntax'].update(info_field_data[obj['uid']])
117
+
118
+ # Merging parameters and keywordOnlyParameters is required,
119
+ # becasue parameters and keywordOnlyParameters can be in both signature and docstring
120
+ # For positionalOnlyParameters, it's not required, because it's only in signature so far
121
+ if merged_params:
122
+ obj['syntax']['parameters'] = merged_params
123
+ if merged_kwargs:
124
+ obj['syntax']['keywordOnlyParameters'] = merged_kwargs
125
+
126
+ add_isrequired_if_needed(obj, 'parameters')
127
+ add_isrequired_if_needed(obj, 'keywordOnlyParameters')
128
+ add_isrequired_if_needed(obj, 'positionalOnlyParameters')
129
+
130
+ raise_up_fields(obj)
131
+
132
+ # add content of temp list 'added_attribute' to children and yaml_data
133
+ if 'added_attribute' in obj['syntax'] and obj['syntax']['added_attribute']:
134
+ added_attribute = obj['syntax'].pop('added_attribute')
135
+ # TODO: yaml_data is updated wihle iterated.
136
+ # `added_attribute` items are copied from class api's `obj` to `yaml_data`
137
+ # Then iterate again
138
+ # Should iterate uid and merge yaml_data, added_attribute
139
+ for attrData in added_attribute:
140
+ existed_Data = next(
141
+ (n for n in yaml_data if n['uid'] == attrData['uid']), None)
142
+ if existed_Data:
143
+ # Update data for already existed one which has attribute comment in source file
144
+ existed_Data.update(attrData)
145
+ else:
146
+ obj.get('children', []).append(attrData['uid'])
147
+ yaml_data.append(attrData)
148
+ # Revert `type` for other objects to use
149
+ info_field_data[obj['uid']]['type'] = obj['type']
150
+
151
+ def find_node_in_toc_tree(toc_yaml, to_add_node):
152
+ for module in toc_yaml:
153
+ if module['name'] == to_add_node:
154
+ return module
155
+
156
+ if 'items' in module:
157
+ items = module['items']
158
+ found_module = find_node_in_toc_tree(items, to_add_node)
159
+ if found_module != None:
160
+ return found_module
161
+
162
+ return None
163
+
164
+ def build_nested_toc(toc_yaml, uid):
165
+ # Build nested TOC
166
+ if uid.count('.') >= 1:
167
+ parent_level = '.'.join(uid.split('.')[:-1])
168
+ found_node = find_node_in_toc_tree(toc_yaml, parent_level)
169
+
170
+ if found_node:
171
+ found_node.pop('uid', 'No uid found')
172
+ found_node.setdefault('items', [{'name': 'Overview', 'uid': parent_level}]).append(
173
+ {'name': uid, 'uid': uid})
174
+ else:
175
+ toc_yaml.append({'name': uid, 'uid': uid})
176
+
177
+ else:
178
+ toc_yaml.append({'name': uid, 'uid': uid})
179
+
31
180
  def build_finished(app, exception):
32
181
  """
33
182
  Output YAML on the file system.
34
183
  """
35
- def find_node_in_toc_tree(toc_yaml, to_add_node):
36
- for module in toc_yaml:
37
- if module['name'] == to_add_node:
38
- return module
39
-
40
- if 'items' in module:
41
- items = module['items']
42
- found_module = find_node_in_toc_tree(items, to_add_node)
43
- if found_module != None:
44
- return found_module
45
-
46
- return None
47
184
 
48
185
  def convert_class_to_enum_if_needed(obj):
49
186
  if (obj.get('inheritance'), None):
@@ -64,37 +201,23 @@ def build_finished(app, exception):
64
201
  app.env.docfx_info_uid_types[obj['uid']] = 'enum'
65
202
  return
66
203
 
67
- def merge_params(arg_params, doc_params):
68
- merged_params = deepcopy(doc_params)
69
- # merge arg_params into merged_params
70
- for arg_param in arg_params:
71
- for merged_param in merged_params:
72
- if arg_param['id'] == merged_param['id']:
73
- if "defaultValue" in arg_param.keys():
74
- merged_param["defaultValue"] = arg_param["defaultValue"]
75
- if "type" in arg_param.keys():
76
- merged_param["type"] = arg_param["type"]
77
- if "isRequired" in arg_param.keys():
78
- if arg_param["isRequired"] == False:
79
- merged_param["isRequired"] = arg_param["isRequired"]
80
- break
81
- else:
82
- merged_params.append(arg_param)
83
- return merged_params
84
-
85
- def remove_params_without_id(params):
86
- new_params = []
87
- for param in params:
88
- if 'id' in param:
89
- new_params.append(param)
90
- return new_params
91
-
92
204
  normalized_outdir = os.path.normpath(os.path.join(
93
205
  app.builder.outdir, # Output Directory for Builder
94
206
  API_ROOT
95
207
  ))
208
+
96
209
  ensuredir(normalized_outdir)
97
210
 
211
+ def filter_out_self_from_args(obj):
212
+ arg_params = obj.get('syntax', {}).get('parameters', [])
213
+ if(len(arg_params) > 0 and 'id' in arg_params[0]):
214
+ if (arg_params[0]['id'] == 'self') or (obj['type'] in ['class', 'method'] and arg_params[0]['id'] == 'cls'):
215
+ # Support having `self` as an arg param, but not documented
216
+ # Not document 'cls' of constuctors and class methods too
217
+ arg_params = arg_params[1:]
218
+ obj['syntax']['parameters'] = arg_params
219
+ return obj
220
+
98
221
  toc_yaml = []
99
222
  # Used to record filenames dumped to avoid confliction
100
223
  # caused by Windows case insensitive file system
@@ -103,8 +226,8 @@ def build_finished(app, exception):
103
226
  # Order matters here, we need modules before lower level classes,
104
227
  # so that we can make sure to inject the TOC properly
105
228
  # put app.env.docfx_yaml_packages after app.env.docfx_yaml_modules to keep same TOC items order
106
- for data_set in (app.env.docfx_yaml_modules,
107
- app.env.docfx_yaml_packages,
229
+ for data_set in (app.env.docfx_yaml_packages,
230
+ app.env.docfx_yaml_modules,
108
231
  app.env.docfx_yaml_classes,
109
232
  app.env.docfx_yaml_functions): # noqa
110
233
 
@@ -116,86 +239,11 @@ def build_finished(app, exception):
116
239
  references = []
117
240
  # Merge module data with class data
118
241
  for obj in yaml_data:
119
- arg_params = obj.get('syntax', {}).get('parameters', [])
120
- if(len(arg_params) > 0 and 'id' in arg_params[0]):
121
- if (arg_params[0]['id'] == 'self') or (obj['type'] in ['class', 'method'] and arg_params[0]['id'] == 'cls'):
122
- # Support having `self` as an arg param, but not documented
123
- # Not document 'cls' of constuctors and class methods too
124
- arg_params = arg_params[1:]
125
- obj['syntax']['parameters'] = arg_params
242
+ obj = filter_out_self_from_args(obj)
243
+
126
244
  if obj['uid'] in app.env.docfx_info_field_data and \
127
245
  obj['type'] == app.env.docfx_info_field_data[obj['uid']]['type']:
128
- # Avoid entities with same uid and diff type.
129
- # Delete `type` temporarily
130
- del(app.env.docfx_info_field_data[obj['uid']]['type'])
131
- if 'syntax' not in obj:
132
- obj['syntax'] = {}
133
- merged_params = []
134
- if 'parameters' in app.env.docfx_info_field_data[obj['uid']]:
135
- doc_params = app.env.docfx_info_field_data[obj['uid']].get(
136
- 'parameters', [])
137
- if arg_params and doc_params:
138
- if len(arg_params) - len(doc_params) > 0:
139
- print("Documented params don't match size of params:"" {}".format(obj['uid'])) # lgtm [py/clear-text-logging-sensitive-data]
140
- doc_params = remove_params_without_id(doc_params)
141
- merged_params = merge_params(arg_params, doc_params)
142
-
143
- obj['syntax'].update(
144
- app.env.docfx_info_field_data[obj['uid']])
145
- if merged_params:
146
- obj['syntax']['parameters'] = merged_params
147
-
148
- if 'parameters' in obj['syntax'] and obj['type'] == 'method':
149
- for args in obj['syntax']['parameters']:
150
- if 'isRequired' not in args and 'defaultValue' not in args:
151
- args['isRequired'] = True
152
-
153
- # Raise up summary
154
- if 'summary' in obj['syntax'] and obj['syntax']['summary']:
155
- obj['summary'] = obj['syntax'].pop(
156
- 'summary').strip(" \n\r\r")
157
-
158
- # Raise up remarks
159
- if 'remarks' in obj['syntax'] and obj['syntax']['remarks']:
160
- obj['remarks'] = obj['syntax'].pop('remarks')
161
-
162
- # Raise up seealso
163
- if 'seealso' in obj['syntax'] and obj['syntax']['seealso']:
164
- obj['seealsoContent'] = obj['syntax'].pop('seealso')
165
-
166
- # Raise up example
167
- if 'example' in obj['syntax'] and obj['syntax']['example']:
168
- obj.setdefault('example', []).append(
169
- obj['syntax'].pop('example'))
170
-
171
- # Raise up exceptions
172
- if 'exceptions' in obj['syntax'] and obj['syntax']['exceptions']:
173
- obj['exceptions'] = obj['syntax'].pop('exceptions')
174
-
175
- # Raise up references
176
- if 'references' in obj['syntax'] and obj['syntax']['references']:
177
- obj.setdefault('references', []).extend(
178
- obj['syntax'].pop('references'))
179
-
180
- # add content of temp list 'added_attribute' to children and yaml_data
181
- if 'added_attribute' in obj['syntax'] and obj['syntax']['added_attribute']:
182
- added_attribute = obj['syntax'].pop('added_attribute')
183
- # TODO: yaml_data is updated wihle iterated.
184
- # `added_attribute` items are copied from class api's `obj` to `yaml_data`
185
- # Then iterate again
186
- # Should iterate uid and merge yaml_data, added_attribute
187
- for attrData in added_attribute:
188
- existed_Data = next(
189
- (n for n in yaml_data if n['uid'] == attrData['uid']), None)
190
- if existed_Data:
191
- # Update data for already existed one which has attribute comment in source file
192
- existed_Data.update(attrData)
193
- else:
194
- obj.get('children', []).append(attrData['uid'])
195
- yaml_data.append(attrData)
196
- # Revert `type` for other objects to use
197
- app.env.docfx_info_field_data[obj['uid']
198
- ]['type'] = obj['type']
246
+ merge_data(obj, app.env.docfx_info_field_data, yaml_data)
199
247
 
200
248
  if 'references' in obj:
201
249
  # Ensure that references have no duplicate ref
@@ -212,20 +260,20 @@ def build_finished(app, exception):
212
260
  if (obj['type'] == 'class' and obj['inheritance']):
213
261
  convert_class_to_enum_if_needed(obj)
214
262
 
215
- # Build nested TOC
216
- if uid.count('.') >= 1:
217
- parent_level = '.'.join(uid.split('.')[:-1])
218
- found_node = find_node_in_toc_tree(toc_yaml, parent_level)
263
+ build_nested_toc(toc_yaml, uid)
219
264
 
220
- if found_node:
221
- found_node.pop('uid', 'No uid found')
222
- found_node.setdefault('items', [{'name': 'Overview', 'uid': parent_level}]).append(
223
- {'name': uid, 'uid': uid})
224
- else:
225
- toc_yaml.append({'name': uid, 'uid': uid})
265
+ index_children = []
266
+ index_references = []
226
267
 
227
- else:
228
- toc_yaml.append({'name': uid, 'uid': uid})
268
+ def form_index_references_and_children(yaml_data, index_children, index_references):
269
+ if yaml_data[0].get('type', None) in ['package', 'module']:
270
+ index_children.append(yaml_data[0].get('fullName', ''))
271
+ index_references.append({
272
+ 'uid': yaml_data[0].get('fullName', ''),
273
+ 'name': yaml_data[0].get('fullName', ''),
274
+ 'fullname': yaml_data[0].get('fullName', ''),
275
+ 'isExternal': False
276
+ })
229
277
 
230
278
  for data_set in (app.env.docfx_yaml_packages,
231
279
  app.env.docfx_yaml_modules,
@@ -233,6 +281,9 @@ def build_finished(app, exception):
233
281
  app.env.docfx_yaml_functions): # noqa
234
282
 
235
283
  for uid, yaml_data in iter(sorted(data_set.items())):
284
+
285
+ form_index_references_and_children(yaml_data, index_children, index_references)
286
+
236
287
  # Output file
237
288
  if uid.lower() in file_name_set:
238
289
  filename = uid + "(%s)" % app.env.docfx_info_uid_types[uid]
@@ -281,16 +332,6 @@ def build_finished(app, exception):
281
332
  )
282
333
 
283
334
  index_file = os.path.join(normalized_outdir, 'index.yml')
284
- index_children = []
285
- index_references = []
286
- for item in toc_yaml:
287
- index_children.append(item.get('name', ''))
288
- index_references.append({
289
- 'uid': item.get('name', ''),
290
- 'name': item.get('name', ''),
291
- 'fullname': item.get('name', ''),
292
- 'isExternal': False
293
- })
294
335
 
295
336
  index_obj = [{
296
337
  'uid': 'project-' + app.config.project,
@@ -97,7 +97,9 @@ def convert_member(obj, reference_mapping):
97
97
  'name': obj.get('fullName', '').split('.')[-1],
98
98
  'summary': obj.get('summary', None),
99
99
  'signature': obj.get('syntax', {}).get('content', None),
100
+ 'positionalOnlyParameters': list(map(convert_parameter_partial, obj.get('syntax', {}).get('positionalOnlyParameters', []))),
100
101
  'parameters': list(map(convert_parameter_partial, obj.get('syntax', {}).get('parameters', []))),
102
+ 'keywordOnlyParameters': list(map(convert_parameter_partial, obj.get('syntax', {}).get('keywordOnlyParameters', []))),
101
103
  'return': convert_return(obj.get('syntax', {}).get('return', {}), reference_mapping),
102
104
  'exceptions': obj.get('exceptions', None),
103
105
  'examples': obj.get('example', None),
@@ -167,7 +169,9 @@ def get_constructor_and_variables(syntax_object, reference_mapping):
167
169
  if syntax_object:
168
170
  constructor_object = {
169
171
  'syntax': syntax_object.get('content', None),
170
- 'parameters': list(map(convert_parameter_partial, syntax_object.get('parameters', [])))
172
+ 'positionalOnlyParameters': list(map(convert_parameter_partial, syntax_object.get('positionalOnlyParameters', []))),
173
+ 'parameters': list(map(convert_parameter_partial, syntax_object.get('parameters', []))),
174
+ 'keywordOnlyParameters': list(map(convert_parameter_partial, syntax_object.get('keywordOnlyParameters', []))),
171
175
  }
172
176
 
173
177
  return remove_empty_values(constructor_object), list(map(convert_variable_partial, syntax_object.get('variables', [])))
@@ -214,7 +214,7 @@ def extract_description(ret_data, app):
214
214
  nodes = ret_data.children
215
215
  description_index = None
216
216
  for node in nodes:
217
- if node.tagname == "#text" and node.astext().strip() in ['–', '––']:
217
+ if node.tagname == "#text" and node.astext().strip() in ['–', '––', '--']:
218
218
  description_index = nodes.index(node) + 1
219
219
  break
220
220
 
@@ -110,6 +110,72 @@ def _resolve_reference_in_module_summary(lines):
110
110
  new_lines.append(new_line)
111
111
  return new_lines
112
112
 
113
+ def getParameterArgs(argspec):
114
+ args = []
115
+ for arg in argspec.args:
116
+ args.append({'id': arg})
117
+ if argspec.defaults:
118
+ for count, default in enumerate(argspec.defaults):
119
+ cut_count = len(argspec.defaults)
120
+ # Only add defaultValue when str(default) doesn't contain object address string
121
+ # (object at 0x)(lambda at 0x)(function *** at 0x)
122
+ # inspect.getargspec method will return wrong defaults which contain object address for some default values, like sys.stdout
123
+ # Match the defaults with the count
124
+ if ' at 0x' not in str(default):
125
+ args[len(args) - cut_count +
126
+ count]['defaultValue'] = str(default)
127
+ else:
128
+ args[len(args) - cut_count +
129
+ count]['isRequired'] = False
130
+ return args
131
+
132
+ def getKeywordOnlyParameters(argspec):
133
+ keyword_only_args = []
134
+ # check if there is keyword only args
135
+ if argspec.kwonlyargs:
136
+ count = 0
137
+ for arg in argspec.kwonlyargs:
138
+ keyword_only_args.append({'id': arg})
139
+ # try get the default value for keyword only args
140
+ if argspec.kwonlydefaults:
141
+ kwarg_default = argspec.kwonlydefaults.get(arg, None)
142
+ if kwarg_default:
143
+ keyword_only_args[count]['defaultValue'] = str(kwarg_default)
144
+ count += 1
145
+ return keyword_only_args
146
+
147
+ def getpositionalOnlyParameters(signature):
148
+ positional_only_param = []
149
+ # check if there is positional only params
150
+ positional_only_param_list = [param
151
+ for param in signature.parameters.values()
152
+ if param.kind == param.POSITIONAL_ONLY]
153
+ if positional_only_param_list:
154
+ count = 0
155
+ for po_param in positional_only_param_list:
156
+ if po_param.name != 'self':
157
+ positional_only_param.append({'id': po_param.name})
158
+
159
+ try:
160
+ default_value = str(po_param.default)
161
+ except KeyError:
162
+ # if the default value is not available, set it to inspect._empty
163
+ default_value = "<class 'inspect._empty'>"
164
+
165
+ if default_value != "<class 'inspect._empty'>":
166
+ positional_only_param[count]['defaultValue'] = default_value
167
+
168
+ count += 1
169
+ return positional_only_param
170
+
171
+ def removePositonalOnlyFromArgs(args, positional_only_params):
172
+ # Create a set of ids from positional_only_params for efficient lookup
173
+ positional_only_params_ids = set(obj['id'] for obj in positional_only_params)
174
+
175
+ # Filter out objects from args array whose id is in the set of positional_only_params_ids
176
+ filtered_a = [obj for obj in args if obj['id'] not in positional_only_params_ids]
177
+
178
+ return filtered_a
113
179
 
114
180
  def _create_datam(app, cls, module, name, _type, obj, lines=None):
115
181
  """
@@ -120,26 +186,23 @@ def _create_datam(app, cls, module, name, _type, obj, lines=None):
120
186
  lines = []
121
187
  short_name = name.split('.')[-1]
122
188
  args = []
123
-
189
+ keyword_only_args = []
190
+ positional_only_params = []
124
191
  try:
125
192
  if _type in [CLASS, METHOD, FUNCTION]:
126
- if not (_type == CLASS and isinstance(type(obj).__call__, type(EnumMeta.__call__))):
127
- argspec = inspect.getfullargspec(obj) # noqa
128
- for arg in argspec.args:
129
- args.append({'id': arg})
130
- if argspec.defaults:
131
- for count, default in enumerate(argspec.defaults):
132
- cut_count = len(argspec.defaults)
133
- # Only add defaultValue when str(default) doesn't contain object address string
134
- # (object at 0x)(lambda at 0x)(function *** at 0x)
135
- # inspect.getargspec method will return wrong defaults which contain object address for some default values, like sys.stdout
136
- # Match the defaults with the count
137
- if ' at 0x' not in str(default):
138
- args[len(args) - cut_count +
139
- count]['defaultValue'] = str(default)
140
- else:
141
- args[len(args) - cut_count +
142
- count]['isRequired'] = False
193
+ if not (_type == CLASS and isinstance(type(obj).__call__, type(EnumMeta.__call__))):
194
+ signature = inspect.signature(obj)
195
+ argspec = inspect.getfullargspec(obj)
196
+
197
+ args = getParameterArgs(argspec)
198
+ keyword_only_args = getKeywordOnlyParameters(argspec)
199
+ positional_only_params = getpositionalOnlyParameters(signature)
200
+
201
+ # The args will contian both regular args and positional only params
202
+ # so we need to remove the positional only args from params
203
+ if positional_only_params:
204
+ args = removePositonalOnlyFromArgs(args, positional_only_params)
205
+
143
206
  except Exception as e:
144
207
  print("Can't get argspec for {}: {}. Exception: {}".format(type(obj), name, e))
145
208
 
@@ -160,9 +223,14 @@ def _create_datam(app, cls, module, name, _type, obj, lines=None):
160
223
  if summary:
161
224
  datam['summary'] = summary.strip(" \n\r\r")
162
225
 
163
- if args:
226
+ if args or keyword_only_args or positional_only_params:
164
227
  datam['syntax'] = {}
165
- datam['syntax']['parameters'] = args
228
+ if args:
229
+ datam['syntax']['parameters'] = args
230
+ if keyword_only_args:
231
+ datam['syntax']['keywordOnlyParameters'] = keyword_only_args
232
+ if positional_only_params:
233
+ datam['syntax']['positionalOnlyParameters'] = positional_only_params
166
234
  if cls:
167
235
  datam[CLASS] = cls
168
236
  if _type in [CLASS, MODULE, PACKAGE]:
@@ -0,0 +1,16 @@
1
+ class TestClass:
2
+ def test_method(self,
3
+ positional_only_param,
4
+ /,
5
+ parameter,
6
+ *,
7
+ keyword_only_arg,
8
+ **kwargs):
9
+ """
10
+ This is a test method
11
+
12
+ :param str parameter: This is a parameter
13
+ :keyword bool keyword_only_arg: This is a keyword only argument
14
+ """
15
+ pass
16
+
@@ -0,0 +1,24 @@
1
+ import os
2
+ import sys
3
+
4
+ sys.path.insert(0, os.path.abspath('.'))
5
+
6
+ extensions = ["sphinx.ext.autodoc","sphinx.ext.napoleon", "yaml_builder"]
7
+
8
+ class includeTest:
9
+ pass
10
+
11
+ # The suffix of source filenames.
12
+ source_suffix = '.rst'
13
+
14
+ autodoc_mock_imports = [
15
+ 'dummy'
16
+ ]
17
+
18
+ pygments_style = 'sphinx'
19
+
20
+ napoleon_use_admonition_for_examples = True
21
+
22
+ nitpicky = True
23
+
24
+ napoleon_preprocess_types=True
@@ -0,0 +1,10 @@
1
+ class TestClass:
2
+ def test_method(self,
3
+ positional_only_param = 10,
4
+ /,
5
+ parameter_with_default_value=True,
6
+ *,
7
+ keyword_only_arg = "keyword_only_arg_default_value",
8
+ **kwargs):
9
+ pass
10
+
@@ -0,0 +1,24 @@
1
+ import os
2
+ import sys
3
+
4
+ sys.path.insert(0, os.path.abspath('.'))
5
+
6
+ extensions = ["sphinx.ext.autodoc","sphinx.ext.napoleon", "yaml_builder"]
7
+
8
+ class includeTest:
9
+ pass
10
+
11
+ # The suffix of source filenames.
12
+ source_suffix = '.rst'
13
+
14
+ autodoc_mock_imports = [
15
+ 'dummy'
16
+ ]
17
+
18
+ pygments_style = 'sphinx'
19
+
20
+ napoleon_use_admonition_for_examples = True
21
+
22
+ nitpicky = True
23
+
24
+ napoleon_preprocess_types=True
@@ -0,0 +1,133 @@
1
+ import pytest
2
+
3
+ from translator import translator
4
+ from build_finished import build_finished, merge_data
5
+
6
+ from .utils.test_utils import prepare_app_envs,load_rst_transform_to_doctree
7
+
8
+ @pytest.mark.sphinx('yaml', testroot='build-finished')
9
+ def test_build_finished(app):
10
+ # Test data definition
11
+ objectToGenXml = 'code_with_signature_and_docstring.TestClass'
12
+ objectToGenXmlType = 'class'
13
+
14
+ # Arrange
15
+ prepare_app_envs(app, objectToGenXml)
16
+ doctree = load_rst_transform_to_doctree(app, objectToGenXmlType, objectToGenXml)
17
+
18
+ translator(app, '', doctree)
19
+
20
+ # Assert before build_finished
21
+ target_node = app.env.docfx_yaml_classes[objectToGenXml][1]['syntax']
22
+ parameter_node = target_node['parameters'][0]
23
+ keyword_only_arg_node = target_node['keywordOnlyParameters'][0]
24
+ positional_only_param_node = target_node['positionalOnlyParameters'][0]
25
+
26
+ assert (parameter_node['id'] == 'self')
27
+ parameter_node = target_node['parameters'][1]
28
+ assert (parameter_node['id'] == 'parameter')
29
+ assert ('type' not in parameter_node.keys())
30
+ assert (keyword_only_arg_node['id'] == 'keyword_only_arg')
31
+ assert ('type' not in keyword_only_arg_node.keys())
32
+ assert (positional_only_param_node['id'] == 'positional_only_param')
33
+ assert ('isRequired' not in positional_only_param_node.keys())
34
+ # Act
35
+ build_finished(app, None)
36
+
37
+ # Assert after build_finished
38
+ target_node = app.env.docfx_yaml_classes[objectToGenXml][1]['syntax']
39
+ parameter_node = target_node['parameters'][0]
40
+ keyword_only_arg_node = target_node['keywordOnlyParameters'][0]
41
+ positional_only_param_node = target_node['positionalOnlyParameters'][0]
42
+
43
+ assert (parameter_node['id'] == 'parameter')
44
+ assert (parameter_node['type'] == ['<xref:str>'])
45
+ assert (keyword_only_arg_node['id'] == 'keyword_only_arg')
46
+ assert (keyword_only_arg_node['type'] == ['<xref:bool>'])
47
+ assert (positional_only_param_node['id'] == 'positional_only_param')
48
+ assert (positional_only_param_node['isRequired'] == True)
49
+
50
+ def test_merge_data():
51
+ # Test data definition
52
+ obj = {
53
+ 'uid': 'test_uid',
54
+ 'type': 'test_type',
55
+ 'syntax': {
56
+ 'parameters': [{'id': 'param1'}],
57
+ 'keywordOnlyParameters': [{'id': 'kwarg1'}]
58
+ }
59
+ }
60
+ info_field_data = {
61
+ 'test_uid': {
62
+ 'type': 'test_type',
63
+ 'parameters': [{'id': 'param2'}],
64
+ 'keywordOnlyParameters': [{'id': 'kwarg2'}]
65
+ }
66
+ }
67
+ yaml_data = []
68
+
69
+ # Call the function to test
70
+ merge_data(obj, info_field_data, yaml_data)
71
+
72
+ # Assert the results
73
+ assert 'type' in info_field_data['test_uid']
74
+ assert info_field_data['test_uid']['type'] == 'test_type'
75
+ assert len(obj['syntax']['parameters']) == 2
76
+ assert len(obj['syntax']['keywordOnlyParameters']) == 2
77
+ assert obj['syntax']['parameters'][0]['id'] == 'param2'
78
+ assert obj['syntax']['parameters'][1]['id'] == 'param1'
79
+ assert obj['syntax']['keywordOnlyParameters'][0]['id'] == 'kwarg2'
80
+ assert obj['syntax']['keywordOnlyParameters'][1]['id'] == 'kwarg1'
81
+
82
+ def test_merge_data_no_syntax():
83
+ # Test data definition
84
+ obj = {
85
+ 'uid': 'test_uid',
86
+ 'type': 'test_type'
87
+ }
88
+ info_field_data = {
89
+ 'test_uid': {
90
+ 'type': 'test_type',
91
+ 'parameters': [{'id': 'param1'}],
92
+ 'keywordOnlyParameters': [{'id': 'kwarg1'}]
93
+ }
94
+ }
95
+ yaml_data = []
96
+
97
+ # Call the function to test
98
+ merge_data(obj, info_field_data, yaml_data)
99
+
100
+ # Assert the results
101
+ assert 'syntax' in obj
102
+ assert len(obj['syntax']['parameters']) == 1
103
+ assert len(obj['syntax']['keywordOnlyParameters']) == 1
104
+ assert obj['syntax']['parameters'][0]['id'] == 'param1'
105
+ assert obj['syntax']['keywordOnlyParameters'][0]['id'] == 'kwarg1'
106
+
107
+ def test_merge_data_added_attribute():
108
+ # Test data definition
109
+ obj = {
110
+ 'uid': 'test_uid',
111
+ 'type': 'test_type',
112
+ 'syntax': {
113
+ 'parameters': [{'id': 'param1'}],
114
+ 'keywordOnlyParameters': [{'id': 'kwarg1'}],
115
+ 'added_attribute': [{'uid': 'attr1'}]
116
+ }
117
+ }
118
+ info_field_data = {
119
+ 'test_uid': {
120
+ 'type': 'test_type',
121
+ 'parameters': [{'id': 'param2'}],
122
+ 'keywordOnlyParameters': [{'id': 'kwarg2'}]
123
+ }
124
+ }
125
+ yaml_data = []
126
+
127
+ # Call the function to test
128
+ merge_data(obj, info_field_data, yaml_data)
129
+
130
+ # Assert the results
131
+ assert 'added_attribute' not in obj['syntax']
132
+ assert len(yaml_data) == 1
133
+ assert yaml_data[0]['uid'] == 'attr1'
@@ -0,0 +1,35 @@
1
+ import pytest
2
+
3
+ from sphinx.testing import restructuredtext
4
+ from sphinx.io import SphinxStandaloneReader
5
+ from sphinx import addnodes
6
+ from translator import translator
7
+
8
+ from .utils.test_utils import prepare_app_envs,prepare_refered_objects,load_rst_transform_to_doctree, do_autodoc
9
+ @pytest.mark.sphinx('dummy', testroot='method-arguments')
10
+ def test_method_with_three_type_of_arguments(app):
11
+ # Test data definition
12
+ objectToGenXml = 'code_with_all_arg_types.TestClass'
13
+ objectToGenXmlType = 'class'
14
+
15
+ # Arrange
16
+ prepare_app_envs(app, objectToGenXml)
17
+ doctree = load_rst_transform_to_doctree(app, objectToGenXmlType, objectToGenXml)
18
+
19
+ # Act
20
+ translator(app, '', doctree)
21
+
22
+ # Assert
23
+ argumentsDetail = app.env.docfx_yaml_classes[objectToGenXml][1]['syntax']
24
+ parameters = argumentsDetail.get('parameters', None)
25
+ keywordOnlyParameters = argumentsDetail.get('keywordOnlyParameters', None)
26
+ positionalOnlyParameters = argumentsDetail.get('positionalOnlyParameters', None)
27
+ assert (parameters != None)
28
+ assert (keywordOnlyParameters != None)
29
+ assert (positionalOnlyParameters != None)
30
+ assert (parameters[1]['id'] == 'parameter_with_default_value')
31
+ assert (parameters[1]['defaultValue'] == 'True')
32
+ assert (keywordOnlyParameters[0]['id'] == 'keyword_only_arg')
33
+ assert (keywordOnlyParameters[0]['defaultValue'] == 'keyword_only_arg_default_value')
34
+ assert (positionalOnlyParameters[0]['id'] == 'positional_only_param')
35
+ assert (positionalOnlyParameters[0]['defaultValue'] == '10')
@@ -123,6 +123,7 @@ def translator(app, docname, doctree):
123
123
  def _get_full_data(node, module_name):
124
124
  data = {
125
125
  'parameters': [],
126
+ 'keywordOnlyParameters': [],
126
127
  'variables': [],
127
128
  'exceptions': [],
128
129
  'return': {},
@@ -165,16 +166,20 @@ def translator(app, docname, doctree):
165
166
  if _is_single_paragraph(fieldbody):
166
167
  #_data = parse_parameter(ret_data, fieldtype)
167
168
  _data = parameter_utils.parse_parameter(content[0], fieldtype, app)
168
- if fieldtype in ['Parameters', 'Keyword']:
169
+ if fieldtype == 'Parameters':
169
170
  data['parameters'].append(_data)
171
+ elif fieldtype == 'Keyword':
172
+ data['keywordOnlyParameters'].append(_data)
170
173
  else:
171
174
  _data['id'] = _parse_variable_id(content[0].astext())
172
175
  data['variables'].append(_data)
173
176
  else:
174
177
  for child in content[0]:
175
178
  _data = parameter_utils.parse_parameter(child[0], fieldtype, app)
176
- if fieldtype in ['Parameters', 'Keyword']:
179
+ if fieldtype in ['Parameters']:
177
180
  data['parameters'].append(_data)
181
+ elif fieldtype == 'Keyword':
182
+ data['keywordOnlyParameters'].append(_data)
178
183
  else:
179
184
  _data['id'] = _parse_variable_id(child.astext())
180
185
  data['variables'].append(_data)
@@ -371,6 +376,9 @@ def translator(app, docname, doctree):
371
376
  if 'parameters' in current_data and 'parameters' in field_list_data:
372
377
  current_data['parameters'].extend(field_list_data['parameters'])
373
378
  field_list_data.pop('parameters')
379
+ if 'keywordOnlyParameters' in current_data and 'keywordOnlyParameters' in field_list_data:
380
+ current_data['keywordOnlyParameters'].extend(field_list_data['keywordOnlyParameters'])
381
+ field_list_data.pop('keywordOnlyParameters')
374
382
  if 'variables' in current_data and 'variables' in field_list_data:
375
383
  current_data['variables'].extend(field_list_data['variables'])
376
384
  field_list_data.pop('variables')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py2docfx
3
- Version: 0.1.1rc1538122
3
+ Version: 0.1.1rc1634530
4
4
  Summary: A package built based on Sphinx which download source code package and generate yaml files supported by docfx.
5
5
  Author: Microsoft Corporation
6
6
  License: MIT License
@@ -52,9 +52,9 @@ py2docfx/convert_prepare/tests/data/subpackage/azure-mgmt-containerservice/azure
52
52
  py2docfx/convert_prepare/tests/data/subpackage/azure-mgmt-containerservice/azure/mgmt/containerservice/v2018_03_31/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
53
  py2docfx/convert_prepare/tests/data/subpackage/azure-mgmt-containerservice/azure/mgmt/containerservice/v2018_03_31/models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  py2docfx/docfx_yaml/__init__.py,sha256=KCEizAXv-SXtrYhvFfLHdBWDhz51AA9uagaeTL-Itpo,100
55
- py2docfx/docfx_yaml/build_finished.py,sha256=jf8--IvekegnTs6Qx9H31TlDNZA6E5yPWaInmHH9QbA,13996
55
+ py2docfx/docfx_yaml/build_finished.py,sha256=kJemkgnh9NIzn4E8jcAIaP7vb7wcHzdLl7yWUjoZbi8,14218
56
56
  py2docfx/docfx_yaml/build_init.py,sha256=lAw-fnBVQbySfZ7Sut_NpFQUjnqLOmnGQrTBBH2RXcg,1860
57
- py2docfx/docfx_yaml/common.py,sha256=Tl6OPSIcvPjFw1AvWt5Mun8pQr9NtUGQnk4zh474Py0,6316
57
+ py2docfx/docfx_yaml/common.py,sha256=UN1MUmjUoN1QSFDR1Cm_bfRuHr6FQiOe5VQV6s8xzjc,6841
58
58
  py2docfx/docfx_yaml/convert_class.py,sha256=boKDaxnXbnLxja62UFXi3eChGDB_WBW6ouUUJgOhdpE,2098
59
59
  py2docfx/docfx_yaml/convert_enum.py,sha256=Kyx48WRl-48O7uv4s-Np1oD9uAd3AXL5uHb7jUsnfFg,2022
60
60
  py2docfx/docfx_yaml/convert_module.py,sha256=8UVjPn4krVfu7CgETAEBesYZyLdPthVXg7MXknni6aQ,2088
@@ -62,16 +62,18 @@ py2docfx/docfx_yaml/convert_package.py,sha256=R8dTHQXjoztHQ3bkBBchPx0k179IVr_e71
62
62
  py2docfx/docfx_yaml/directives.py,sha256=zVVuNM_6AU9G6sbqL1UAyHHgPe7bkBWbthXI-PO5ez0,879
63
63
  py2docfx/docfx_yaml/miss_reference.py,sha256=Btoj9wAvA4u_wU7JHH0Cei3910N8a7MS34OUqJvXAd4,2443
64
64
  py2docfx/docfx_yaml/nodes.py,sha256=tBDi35jLJArlobl07DKOkmH2qz7dudXLp_kTUfR_r2w,412
65
- py2docfx/docfx_yaml/parameter_utils.py,sha256=vCol5q2SJd1ymuyJdE_-62Tau9RP7PewQdKSimcfQuo,8700
66
- py2docfx/docfx_yaml/process_doctree.py,sha256=iKs1fsyo-1_P3RzpZBzD8G9hcOTGO78esWNZLXvSx2g,14866
65
+ py2docfx/docfx_yaml/parameter_utils.py,sha256=zGSIQrUfbXf9PUK-W_1K83Uo5Zk797Zlze6aMurbHIA,8706
66
+ py2docfx/docfx_yaml/process_doctree.py,sha256=Ve5kYoxmsJ-lq_UvfB5fldN87Nrtlm0APF0IGHWCrYg,17663
67
67
  py2docfx/docfx_yaml/return_type_utils.py,sha256=nmdCUOvwdYk2jF6RqmOvU6gjXmXUTPUeCqyHPdKZNUQ,7483
68
68
  py2docfx/docfx_yaml/settings.py,sha256=JQZNwFebczl-zn8Yk2taAGANRi-Hw8hywtDWxqXXFyQ,373
69
- py2docfx/docfx_yaml/translator.py,sha256=kJwGiXkiJgK3HPcVNX4qmt2Xwd77_DXS9Vd7LyGCFZo,25366
69
+ py2docfx/docfx_yaml/translator.py,sha256=li20Sdu-j1V7oK1iaxWw9mo0KSJOlh4FLSnwmu6UxBQ,25912
70
70
  py2docfx/docfx_yaml/utils.py,sha256=m5jC_qP2NKqzUx_z0zgZ-HAmxQdNTpJYKkL_F9vGeII,1555
71
71
  py2docfx/docfx_yaml/writer.py,sha256=0ZqyVGDHa4Cr3NsuOPRf4pGUStl6g6IBxpSgIZeDT9I,34683
72
72
  py2docfx/docfx_yaml/yaml_builder.py,sha256=qSxXVS4iFCc1ZdL5QzLrv8hy3LHIQCrhO4WcTp01vag,2575
73
73
  py2docfx/docfx_yaml/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
74
  py2docfx/docfx_yaml/tests/conftest.py,sha256=CykkZxaDZ-3a1EIQdGBieSmHL9FdyTE2xTJZe9QgKcg,1214
75
+ py2docfx/docfx_yaml/tests/test_build_finished.py,sha256=ShCRhIHGu2IUaM6iWsC0w9i_qmdc_kadPE3oPRBBZbQ,4720
76
+ py2docfx/docfx_yaml/tests/test_method_arguments.py,sha256=Cvj9aoADtacKciVN8nempXW-KQL8nujSa9GNVuk6l_8,1578
75
77
  py2docfx/docfx_yaml/tests/test_numpy_syntax.py,sha256=ssb3J_-Jzjybhh4eycCA_LkXbGflyZyIUAiTjlEYLiw,863
76
78
  py2docfx/docfx_yaml/tests/test_translator_attributes.py,sha256=qZCsQGffq31k3UzpXkJpycplOXIq9gi2SxY6vu0DTfw,5224
77
79
  py2docfx/docfx_yaml/tests/test_translator_contents.py,sha256=lVCWbBIQk2oPFqsKK9gIb-b5DixutMabWjP7x03oj4s,1746
@@ -83,6 +85,10 @@ py2docfx/docfx_yaml/tests/test_translator_rst_returns.py,sha256=BL3nOMMTPzNPJk-P
83
85
  py2docfx/docfx_yaml/tests/test_translator_signatures.py,sha256=DM51EOb4UXLkrO1-4cQQQvvX210goAsnxKJH-4A2U2Q,1537
84
86
  py2docfx/docfx_yaml/tests/test_writer_table.py,sha256=UnGYXQ-QVxin_e-HGZAHdg1LSFV0qc480ZNsqPN9OYc,1444
85
87
  py2docfx/docfx_yaml/tests/test_writer_uri.py,sha256=L9eFHZndD6H7nkznJ9Bw0v8xh9IegDlhhGFHBz9EHmM,1745
88
+ py2docfx/docfx_yaml/tests/roots/test-build-finished/code_with_signature_and_docstring.py,sha256=qvcKWL68C2aDTP8JT022nMV4EdZ50vhxVshMrHVO2sY,449
89
+ py2docfx/docfx_yaml/tests/roots/test-build-finished/conf.py,sha256=L8vIFmO546PCQks50Gif_uTBwC3cppohXrQaogfyRF8,410
90
+ py2docfx/docfx_yaml/tests/roots/test-method-arguments/code_with_all_arg_types.py,sha256=jK4M4ejeVWedhHJ_s9L9wEEqJmk0wOF8-yuoIaA6fZU,322
91
+ py2docfx/docfx_yaml/tests/roots/test-method-arguments/conf.py,sha256=L8vIFmO546PCQks50Gif_uTBwC3cppohXrQaogfyRF8,410
86
92
  py2docfx/docfx_yaml/tests/roots/test-numpy-syntax/code_with_numpy.py,sha256=-7ZN5VPVQfj0-jwPZW_jkIe78B17j5cbXA4f2ZgQIFc,219
87
93
  py2docfx/docfx_yaml/tests/roots/test-numpy-syntax/conf.py,sha256=SczEhbCZ_zuTYW1ZyrB2VJ4FRh6B-q58SN7ZZ5INCeM,394
88
94
  py2docfx/docfx_yaml/tests/roots/test-translator-attributes/code_with_docstring.py,sha256=5JDlpC9Pm-8Bob2Qvqq58Nudk4n26nhHdOiNULrSXeY,326
@@ -112,7 +118,7 @@ py2docfx/docfx_yaml/tests/roots/test-writer-table/conf.py,sha256=avcbnIOV2mlGQwh
112
118
  py2docfx/docfx_yaml/tests/roots/test-writer-uri/code_with_uri.py,sha256=bzWTZpY2yf_By2bOSl1GFaY3BsZpkAvwQuGztlcHKkQ,537
113
119
  py2docfx/docfx_yaml/tests/roots/test-writer-uri/conf.py,sha256=avcbnIOV2mlGQwhMQJZC4W6UGRBRhnq1QBxjPWlySxQ,260
114
120
  py2docfx/docfx_yaml/tests/utils/test_utils.py,sha256=d0OYSUQ6NyoZx5mlLdNGGNhiNmmQhjVT4hQ6jY3VE_M,3383
115
- py2docfx-0.1.1rc1538122.dist-info/METADATA,sha256=AgLm_FNB3wg6R1EQyC9LHpJIq8q49FqvoJeJ2TYcfLM,599
116
- py2docfx-0.1.1rc1538122.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
117
- py2docfx-0.1.1rc1538122.dist-info/top_level.txt,sha256=5dH2uP81dczt_qQJ38wiZ-gzoVWasfiJALWRSjdbnYU,9
118
- py2docfx-0.1.1rc1538122.dist-info/RECORD,,
121
+ py2docfx-0.1.1rc1634530.dist-info/METADATA,sha256=wJWdP3fNN10kOVuRl7qfKg1-rdZXDreGXUcPVrkyI7s,599
122
+ py2docfx-0.1.1rc1634530.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
123
+ py2docfx-0.1.1rc1634530.dist-info/top_level.txt,sha256=5dH2uP81dczt_qQJ38wiZ-gzoVWasfiJALWRSjdbnYU,9
124
+ py2docfx-0.1.1rc1634530.dist-info/RECORD,,