mkdocstrings-matlab 0.1.6__tar.gz → 0.2.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/PKG-INFO +1 -1
  2. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/pyproject.toml +1 -1
  3. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/handler.py +121 -35
  4. mkdocstrings_matlab-0.2.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+case/builtin.m +27 -0
  5. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+metadata/class.m +7 -2
  6. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/resolve.m +1 -1
  7. mkdocstrings_matlab-0.1.6/src/mkdocstrings_handlers/matlab/matlab/+docstring/+case/builtin.m +0 -8
  8. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/.gitignore +0 -0
  9. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/LICENSE +0 -0
  10. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/README.md +0 -0
  11. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/docs/index.md +0 -0
  12. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/mkdocs.yml +0 -0
  13. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/__init__.py +0 -0
  14. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/collections.py +0 -0
  15. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+case/class.m +0 -0
  16. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+case/func.m +0 -0
  17. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+case/method.m +0 -0
  18. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+case/namespace.m +0 -0
  19. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+metadata/argument.m +0 -0
  20. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+metadata/func.m +0 -0
  21. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+metadata/namespace.m +0 -0
  22. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+metadata/property.m +0 -0
  23. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+metadata/script.m +0 -0
  24. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+utils/dedent.m +0 -0
  25. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+utils/get_namespace_path.m +0 -0
  26. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/+utils/parse_doc.m +0 -0
  27. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/+docstring/exception.m +0 -0
  28. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/matlab/matlab_startup.m +0 -0
  29. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/models.py +0 -0
  30. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/parser.py +0 -0
  31. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/py.typed +0 -0
  32. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/src/mkdocstrings_handlers/matlab/resources/grammar.yml +0 -0
  33. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2023a/.gitignore +0 -0
  34. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2023a/LICENSE +0 -0
  35. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2023a/README.md +0 -0
  36. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2023a/pyproject.toml +0 -0
  37. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2023a/src/mkdocstrings_handlers/matlab_engine/__init__.py +0 -0
  38. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2023b/.gitignore +0 -0
  39. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2023b/LICENSE +0 -0
  40. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2023b/README.md +0 -0
  41. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2023b/pyproject.toml +0 -0
  42. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2023b/src/mkdocstrings_handlers/matlab_engine/__init__.py +0 -0
  43. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2024a/.gitignore +0 -0
  44. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2024a/LICENSE +0 -0
  45. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2024a/README.md +0 -0
  46. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2024a/pyproject.toml +0 -0
  47. {mkdocstrings_matlab-0.1.6 → mkdocstrings_matlab-0.2.0}/submodules/mkdocstrings-matlab-r2024a/src/mkdocstrings_handlers/matlab_engine/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mkdocstrings-matlab
3
- Version: 0.1.6
3
+ Version: 0.2.0
4
4
  Summary: Add your description here
5
5
  Author-email: Mark Hu <watermarkhu@gmail.com>
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mkdocstrings-matlab"
3
- version = "0.1.6"
3
+ version = "0.2.0"
4
4
  description = "Add your description here"
5
5
  authors = [
6
6
  { name = "Mark Hu", email = "watermarkhu@gmail.com" }
@@ -10,6 +10,7 @@ from pprint import pprint
10
10
 
11
11
  import charset_normalizer
12
12
  import json
13
+ import requests
13
14
 
14
15
 
15
16
  from mkdocstrings_handlers.matlab.collections import LinesCollection, ModelsCollection
@@ -60,7 +61,8 @@ class MatlabHandler(BaseHandler):
60
61
  # "find_stubs_package": False,
61
62
  # "allow_inspection": True,
62
63
  "show_bases": True,
63
- "show_inheritance_diagram": False, # Insider feature
64
+ "show_inheritance_diagram": True,
65
+ "inheritance_diagram_show_builtin": False,
64
66
  "show_source": True,
65
67
  # "preload_modules": None,
66
68
  # Heading options
@@ -125,7 +127,7 @@ class MatlabHandler(BaseHandler):
125
127
  super().__init__(*args, **kwargs)
126
128
 
127
129
  if paths is None:
128
- paths = ""
130
+ full_paths = ""
129
131
  else:
130
132
  config_path = Path(config_file_path).parent
131
133
  full_paths = [str((config_path / path).resolve()) for path in paths]
@@ -143,6 +145,46 @@ class MatlabHandler(BaseHandler):
143
145
  # (it assumes the python handler is installed)
144
146
  return super().get_templates_dir("python")
145
147
 
148
+ def get_ast(self, identifier:str, config: Mapping[str, Any]) -> dict:
149
+ """Retrieve the Abstract Syntax Tree (AST) for a given MATLAB identifier.
150
+
151
+ This method resolves the docstring for the specified identifier and parses it into an AST.
152
+ If the identifier corresponds to a class, it processes its superclasses and optionally
153
+ includes an inheritance diagram based on the provided configuration.
154
+ Args:
155
+ identifier (str): The MATLAB identifier to resolve.
156
+ config (Mapping[str, Any]): Configuration options for processing the AST.
157
+ Returns:
158
+ dict: The parsed AST for the given identifier.
159
+ Raises:
160
+ MatlabExecutionError: If there is an error resolving the superclass AST.
161
+ """
162
+
163
+ ast_json = self.engine.docstring.resolve(identifier)
164
+ ast = json.loads(ast_json)
165
+
166
+ if ast['type'] == 'class':
167
+
168
+ if isinstance(ast["superclasses"], str):
169
+ ast["superclasses"] = [ast["superclasses"]]
170
+
171
+ if config["show_inheritance_diagram"]:
172
+ # Check if class is builtin and skip superclasses if option is not set
173
+ builtin = ast.get('builtin', False) or ast["name"].startswith("matlab.")
174
+ resursive = not builtin or config["inheritance_diagram_show_builtin"]
175
+ if not resursive:
176
+ ast["superclasses"] = []
177
+
178
+ # Get superclasses AST
179
+ for index, base in enumerate(ast["superclasses"]):
180
+ try:
181
+ ast["superclasses"][index] = self.get_ast(base, config)
182
+ ast["superclasses"][index]["name"] = base
183
+ except MatlabExecutionError:
184
+ ast["superclasses"][index] = {"name": base}
185
+ return ast
186
+
187
+
146
188
  def collect(self, identifier: str, config: Mapping[str, Any]) -> CollectorItem:
147
189
  """Collect data given an identifier and user configuration.
148
190
 
@@ -156,26 +198,28 @@ class MatlabHandler(BaseHandler):
156
198
  Returns:
157
199
  CollectorItem
158
200
  """
201
+ if identifier == "":
202
+ raise CollectionError("Empty identifier")
203
+
159
204
  final_config = ChainMap(config, self.default_config) # type: ignore[arg-type]
160
205
  if identifier in self.models:
161
206
  return self.models[identifier]
162
207
 
163
208
  try:
164
- ast_json = self.engine.docstring.resolve(identifier)
209
+ ast = self.get_ast(identifier, final_config)
165
210
  except MatlabExecutionError as error:
166
211
  raise CollectionError(error.args[0].strip()) from error
167
- ast_dict = json.loads(ast_json)
168
212
 
169
- filepath = Path(ast_dict["path"])
213
+ filepath = Path(ast["path"])
170
214
  if filepath not in self.lines:
171
215
  lines = str(charset_normalizer.from_path(filepath).best()).splitlines()
172
216
  self.lines[filepath] = lines
173
217
 
174
- match ast_dict["type"]:
218
+ match ast["type"]:
175
219
  case "function" | "method":
176
- return self.collect_function(ast_dict, final_config)
220
+ return self.collect_function(ast, final_config)
177
221
  case "class":
178
- return self.collect_class(ast_dict, final_config)
222
+ return self.collect_class(ast, final_config)
179
223
  case _:
180
224
  return None
181
225
 
@@ -247,15 +291,11 @@ class MatlabHandler(BaseHandler):
247
291
  lambda template_name: template_name in self.env.list_templates()
248
292
  )
249
293
 
250
- def collect_class(self, ast_dict: dict, config: Mapping) -> Class:
251
- docstring = (
252
- Docstring(ast_dict["docstring"], parser=config["docstring_style"])
253
- if ast_dict["docstring"]
254
- else None
255
- )
294
+ def collect_class(self, ast: dict, config: Mapping) -> Class:
256
295
 
257
- filepath = Path(ast_dict["path"])
296
+ filepath = Path(ast["path"])
258
297
 
298
+ # Parse textmate object
259
299
  if config["show_source"]:
260
300
  tmObject = self.parser.parse_file(filepath)
261
301
  tmClass = next(
@@ -266,18 +306,24 @@ class MatlabHandler(BaseHandler):
266
306
  else:
267
307
  tmClass = None
268
308
 
269
- bases = ast_dict["superclasses"] if isinstance(ast_dict["superclasses"], list) else [ast_dict["superclasses"]]
270
- bases = [base for base in bases if base != "handle"]
271
-
309
+ # Get bases
310
+ if config["show_bases"]:
311
+ if config["show_inheritance_diagram"]:
312
+ bases = [base["name"] for base in ast["superclasses"]]
313
+ else:
314
+ bases = ast["superclasses"] if isinstance(ast["superclasses"], list) else [ast["superclasses"]]
315
+ else:
316
+ bases = []
317
+
318
+ # Load model
272
319
  model = Class(
273
- ast_dict["name"],
274
- docstring=docstring,
320
+ ast["name"],
275
321
  parent=self.get_parent(filepath.parent),
276
- hidden=ast_dict["hidden"],
277
- sealed=ast_dict["sealed"],
278
- abstract=ast_dict["abstract"],
279
- enumeration=ast_dict["enumeration"],
280
- handle=ast_dict["handle"],
322
+ hidden=ast["hidden"],
323
+ sealed=ast["sealed"],
324
+ abstract=ast["abstract"],
325
+ enumeration=ast["enumeration"],
326
+ handle=ast["handle"],
281
327
  bases=bases,
282
328
  filepath=filepath,
283
329
  modules_collection=self.models,
@@ -286,8 +332,21 @@ class MatlabHandler(BaseHandler):
286
332
  endlineno=len(self.lines[filepath]),
287
333
  textmate=tmClass,
288
334
  )
335
+ ast["name"] = model.canonical_path
336
+
337
+ # Format mermaid inheritance diagram
338
+ if config["show_inheritance_diagram"] and ast["superclasses"]:
339
+ section = get_inheritance_diagram(ast)
340
+ docstring = Docstring(ast["docstring"] + section, parser=config["docstring_style"])
341
+ elif ast["docstring"]:
342
+ docstring = Docstring(ast["docstring"], parser=config["docstring_style"])
343
+ else:
344
+ docstring
345
+
346
+ model.docstring = docstring
289
347
 
290
- for property_dict in ast_dict["properties"]:
348
+ # Load properties
349
+ for property_dict in ast["properties"]:
291
350
  name = property_dict.pop("name")
292
351
  defining_class = property_dict.pop("class")
293
352
  property_doc = property_dict.pop("docstring")
@@ -306,7 +365,8 @@ class MatlabHandler(BaseHandler):
306
365
  model.members[name] = prop
307
366
  self.models[prop.canonical_path] = prop
308
367
 
309
- for method_dict in ast_dict["methods"]:
368
+ # Load methods
369
+ for method_dict in ast["methods"]:
310
370
  name = method_dict.pop("name")
311
371
  defining_class = method_dict.pop("class")
312
372
  if (
@@ -337,13 +397,13 @@ class MatlabHandler(BaseHandler):
337
397
 
338
398
  return model
339
399
 
340
- def collect_function(self, ast_dict: dict, config: Mapping) -> Function:
400
+ def collect_function(self, ast: dict, config: Mapping) -> Function:
341
401
  parameters = []
342
402
 
343
403
  inputs = (
344
- ast_dict["inputs"]
345
- if isinstance(ast_dict["inputs"], list)
346
- else [ast_dict["inputs"]]
404
+ ast["inputs"]
405
+ if isinstance(ast["inputs"], list)
406
+ else [ast["inputs"]]
347
407
  )
348
408
  for input_dict in inputs:
349
409
  if input_dict["name"] == "varargin":
@@ -362,16 +422,16 @@ class MatlabHandler(BaseHandler):
362
422
  )
363
423
  )
364
424
 
365
- filepath = Path(ast_dict["path"])
425
+ filepath = Path(ast["path"])
366
426
  model = Function(
367
- ast_dict["name"],
427
+ ast["name"],
368
428
  parameters=Parameters(*parameters),
369
429
  docstring=Docstring(
370
- ast_dict["docstring"],
430
+ ast["docstring"],
371
431
  parser=config["docstring_style"],
372
432
  parser_options=config["docstring_options"],
373
433
  )
374
- if ast_dict["docstring"]
434
+ if ast["docstring"]
375
435
  else None,
376
436
  parent=self.get_parent(filepath.parent),
377
437
  filepath=filepath,
@@ -409,6 +469,32 @@ class MatlabHandler(BaseHandler):
409
469
  parent = ROOT
410
470
  return parent
411
471
 
472
+ def get_inheritance_diagram(ast: dict) -> str:
473
+ def get_id(str: str) -> str:
474
+ return str.replace('.', '_')
475
+ def get_nodes(ast: dict, nodes: set[str] = set(), clicks: set[str] = set()) -> str:
476
+ id = get_id(ast['name'])
477
+ nodes.add(f" {id}[{ast['name']}]")
478
+ if "help" in ast:
479
+ clicks.add(f" click {id} \"{ast['help']}\"")
480
+ if "superclasses" in ast:
481
+ for superclass in ast["superclasses"]:
482
+ get_nodes(superclass, nodes)
483
+ return (nodes, clicks)
484
+ def get_links(ast: dict, links: set[str] = set()) -> str:
485
+ if "superclasses" in ast:
486
+ for superclass in ast["superclasses"]:
487
+ links.add(f" {get_id(ast['name'])} --> {get_id(superclass['name'])}")
488
+ get_links(superclass, links)
489
+ return links
490
+
491
+ (nodes, clicks) = get_nodes(ast)
492
+ nodes_str = '\n'.join(list(nodes))
493
+ clicks_str = '\n'.join(list(clicks))
494
+ links_str = '\n'.join(list(get_links(ast)))
495
+ section = f"\n\n## Inheritance diagram\n\n```mermaid\nflowchart BT\n{nodes_str}\n{clicks_str}\n{links_str}\n```"
496
+ return section
497
+
412
498
 
413
499
  def get_handler(
414
500
  *,
@@ -0,0 +1,27 @@
1
+ function data = builtin(identifier)
2
+ if isMATLABReleaseOlderThan('R2024a')
3
+ metaclass = @meta.class.fromName;
4
+ else
5
+ metaclass = @matlab.metadata.Class.fromName;
6
+ end
7
+
8
+ object = metaclass(identifier);
9
+
10
+ if isempty(object)
11
+ data.name = identifier;
12
+ data.type = 'function';
13
+ data.doc = help(identifier);
14
+ data.location = string(which(identifier));
15
+ data.inputs = struct.empty();
16
+ data.outputs = struct.empty();
17
+ if ~contains(identifier, '.internal.')
18
+ data.help = sprintf('https://mathworks.com/help/matlab/ref/%s.html', lower(identifier));
19
+ end
20
+ else
21
+ data = docstring.metadata.class(object, 'builtin', true);
22
+ if ~contains(identifier, '.internal.')
23
+ data.help = sprintf('https://mathworks.com/help/matlab/ref/%s-class.html', lower(identifier));
24
+ end
25
+ end
26
+ data.builtin = true;
27
+ end
@@ -1,6 +1,7 @@
1
- function data = class(object)
1
+ function data = class(object, opts)
2
2
  arguments
3
3
  object (1,1) % meta.class matlab.metadata.Class
4
+ opts.builtin (1,1) logical = false
4
5
  end
5
6
  data.type = 'class';
6
7
 
@@ -8,7 +9,6 @@ function data = class(object)
8
9
  data.name = namespaces{end};
9
10
 
10
11
  data.docstring = docstring.utils.parse_doc(object);
11
- data.path = matlab.internal.metafunction(object.Name).Location;
12
12
  data.hidden = object.Hidden;
13
13
  data.sealed = object.Sealed;
14
14
  data.abstract = object.Abstract;
@@ -16,6 +16,11 @@ function data = class(object)
16
16
  data.superclasses = arrayfun(@(o) string(o.Name), object.SuperclassList);
17
17
  data.handle = object.HandleCompatible;
18
18
  data.aliases = object.Aliases;
19
+ if opts.builtin
20
+ data.path = '';
21
+ else
22
+ data.path = matlab.internal.metafunction(object.Name).Location;
23
+ end
19
24
 
20
25
  data.methods = [];
21
26
  for methodObject = object.MethodList'
@@ -46,7 +46,7 @@ if contains(identifier, '.')
46
46
  end
47
47
 
48
48
  % Try built-in aliases with which
49
- if contains(which(identifier), ' built-in ')
49
+ if contains(which(identifier), {' built-in ', matlabroot})
50
50
  data = docstring.case.builtin(identifier);
51
51
  jsonString = jsonencode(data);
52
52
  return
@@ -1,8 +0,0 @@
1
- function data = builtin(identifier)
2
- data.name = identifier;
3
- data.type = 'function';
4
- data.doc = help(identifier);
5
- data.location = string(which(identifier));
6
- data.inputs = struct.empty();
7
- data.outputs = struct.empty();
8
- end