mkdocstrings-matlab 0.3.2__py3-none-any.whl → 0.4.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,26 @@
1
1
  """MATLAB handler for mkdocstrings."""
2
2
 
3
3
  from mkdocstrings_handlers.matlab.handler import get_handler
4
+ from _griffe.enumerations import DocstringSectionKind
5
+ from _griffe.docstrings import numpy, google
4
6
 
5
7
  __all__ = ["get_handler"]
8
+
9
+
10
+ # Add custom sections to the numpy and google docstring parsers
11
+ extensions = {
12
+ "arguments": DocstringSectionKind.parameters,
13
+ "input arguments": DocstringSectionKind.parameters,
14
+ "outputs": DocstringSectionKind.returns,
15
+ "output arguments": DocstringSectionKind.returns,
16
+ "name value arguments": DocstringSectionKind.other_parameters,
17
+ "name-value arguments": DocstringSectionKind.other_parameters,
18
+ "name value pairs": DocstringSectionKind.other_parameters,
19
+ "name-value pairs": DocstringSectionKind.other_parameters,
20
+ "properties": DocstringSectionKind.attributes,
21
+ "namespaces": DocstringSectionKind.modules,
22
+ "packages": DocstringSectionKind.modules,
23
+ }
24
+
25
+ google._section_kind.update(extensions)
26
+ numpy._section_kind.update(extensions)
@@ -1,15 +1,17 @@
1
1
  from collections import defaultdict, deque
2
- from copy import deepcopy
2
+ from copy import copy, deepcopy
3
3
  from pathlib import Path
4
4
  from typing import Mapping, Sequence
5
5
 
6
6
  from _griffe.collections import LinesCollection as GLC, ModulesCollection
7
7
  from _griffe.docstrings.models import (
8
+ DocstringSectionOtherParameters,
8
9
  DocstringSectionParameters,
9
10
  DocstringSectionReturns,
10
11
  DocstringParameter,
11
12
  DocstringReturn,
12
13
  )
14
+ from _griffe.enumerations import DocstringSectionKind
13
15
  from _griffe.expressions import Expr
14
16
 
15
17
  from mkdocstrings_handlers.matlab.enums import ParameterKind
@@ -223,9 +225,24 @@ class PathCollection(ModulesCollection):
223
225
  model.docstring.parser = config.get("docstring_style", "google")
224
226
  model.docstring.parser_options = config.get("docstring_options", {})
225
227
 
228
+ # Patch docstring section titles
229
+ if model.docstring is not None:
230
+ for section in model.docstring.parsed:
231
+ match section.kind:
232
+ case DocstringSectionKind.attributes:
233
+ section.title = "Properties:"
234
+ case DocstringSectionKind.modules:
235
+ section.title = "Namespaces:"
236
+ case DocstringSectionKind.parameters:
237
+ section.title = "Input arguments:"
238
+ case DocstringSectionKind.returns:
239
+ section.title= "Output arguments:"
240
+ case DocstringSectionKind.other_parameters:
241
+ section.title = "Name-Value Arguments:"
242
+
226
243
  # Patch returns annotation
227
244
  # In _griffe.docstrings.<parser>.py the function _read_returns_section will enforce an annotation
228
- # on the return parameter. This annotation is grabbed from the parent. For MATLAB is is invalid.
245
+ # on the return parameter. This annotation is grabbed from the parent. For MATLAB this is invalid.
229
246
  # Thus the return annotation needs to be patched back to a None.
230
247
  if (
231
248
  isinstance(model, Function)
@@ -244,31 +261,128 @@ class PathCollection(ModulesCollection):
244
261
  if not isinstance(returns.annotation, Expr):
245
262
  returns.annotation = None
246
263
 
264
+ # previous updates do not edit the model attributes persistently
265
+ # However, the following updates do edit the model attributes persistently
266
+ # such as adding new sections to the docstring or editing its members.abs
267
+ # Thus, we need to copy the model to avoid editing the original model
268
+ alias = copy(model)
269
+ alias.docstring = (
270
+ deepcopy(model.docstring) if model.docstring is not None else None
271
+ )
272
+ alias.members = {key: value for key, value in model.members.items()}
273
+ if isinstance(alias, Class):
274
+ alias._inherited_members = None
275
+
276
+ for name, member in getattr(alias, "members", {}).items():
277
+ alias.members[name] = self.update_model(member, config)
278
+
279
+ # Merge constructor docstring into class
280
+ if (
281
+ isinstance(alias, Class)
282
+ and config.get("merge_constructor_into_class", False)
283
+ and alias.name in alias.members
284
+ and alias.members[alias.name].docstring is not None
285
+ ):
286
+ constructor = alias.members.pop(alias.name)
287
+ if constructor.docstring is not None:
288
+ if alias.docstring is None:
289
+ alias.docstring = Docstring("", parent=alias)
290
+
291
+ if config.get("merge_constructor_ignore_summary", False):
292
+ alias.docstring._suffixes.extend(constructor.docstring.parsed[1:])
293
+ else:
294
+ alias.docstring._suffixes.extend(constructor.docstring.parsed)
295
+
296
+ # Hide hidden members (methods and properties)
297
+ hidden_members = config.get("hidden_members", False)
298
+ if isinstance(hidden_members, bool):
299
+ filter_hidden = not hidden_members
300
+ show_hidden = []
301
+ else:
302
+ filter_hidden = True
303
+ show_hidden: list[str] = hidden_members
304
+ if isinstance(alias, Class) and filter_hidden:
305
+ alias.members = {
306
+ key: value
307
+ for key, value in alias.members.items()
308
+ if not getattr(value, "Hidden", False)
309
+ or (
310
+ show_hidden
311
+ and getattr(value, "Hidden", False)
312
+ and key in show_hidden
313
+ )
314
+ }
315
+ alias._inherited_members = {
316
+ key: value
317
+ for key, value in alias.inherited_members.items()
318
+ if not getattr(value, "Hidden", False)
319
+ or (
320
+ show_hidden
321
+ and getattr(value, "Hidden", False)
322
+ and key in show_hidden
323
+ )
324
+ }
325
+
326
+ # Hide private members (methods and properties)
327
+ private_members = config.get("private_members", False)
328
+ if isinstance(private_members, bool):
329
+ filter_private = not private_members
330
+ show_private = []
331
+ else:
332
+ filter_private = True
333
+ show_private: list[str] = private_members
334
+ if isinstance(alias, Class) and filter_private:
335
+ alias.members = {
336
+ key: value
337
+ for key, value in alias.members.items()
338
+ if not getattr(value, "Private", False)
339
+ or (
340
+ show_private
341
+ and getattr(value, "Private", False)
342
+ and key in show_private
343
+ )
344
+ }
345
+ alias._inherited_members = {
346
+ key: value
347
+ for key, value in alias.inherited_members.items()
348
+ if not getattr(value, "Private", False)
349
+ or (
350
+ show_private
351
+ and getattr(value, "Private", False)
352
+ and key in show_private
353
+ )
354
+ }
355
+
247
356
  # Create parameters and returns sections from argument blocks
248
357
  if (
249
- isinstance(model, Function)
250
- and model.docstring is not None
251
- and config.get("create_from_argument_blocks", True)
358
+ isinstance(alias, Function)
359
+ and alias.docstring is not None
360
+ and config.get("parse_arguments", True)
361
+ and (
362
+ config.get("show_docstring_input_arguments", True)
363
+ or config.get("show_docstring_name_value_arguments", True)
364
+ or config.get("show_docstring_output_arguments", True)
365
+ )
252
366
  ):
253
367
  docstring_parameters = any(
254
368
  isinstance(doc, DocstringSectionParameters)
255
- for doc in model.docstring.parsed
369
+ for doc in alias.docstring.parsed
256
370
  )
257
371
  docstring_returns = any(
258
372
  isinstance(doc, DocstringSectionReturns)
259
- for doc in model.docstring.parsed
373
+ for doc in alias.docstring.parsed
260
374
  )
261
375
 
262
- if not docstring_parameters and model.parameters:
376
+ if not docstring_parameters and alias.parameters:
263
377
  arguments_parameters = any(
264
- param.docstring is not None for param in model.parameters
378
+ param.docstring is not None for param in alias.parameters
265
379
  )
266
380
  else:
267
381
  arguments_parameters = False
268
382
 
269
- if not docstring_returns and model.returns:
383
+ if not docstring_returns and alias.returns:
270
384
  arguments_returns = any(
271
- ret.docstring is not None for ret in model.returns
385
+ ret.docstring is not None for ret in alias.returns
272
386
  )
273
387
  else:
274
388
  arguments_returns = False
@@ -277,17 +391,23 @@ class PathCollection(ModulesCollection):
277
391
  document_returns = not docstring_returns and arguments_returns
278
392
 
279
393
  standard_parameters = [
280
- param for param in model.parameters
394
+ param
395
+ for param in alias.parameters
281
396
  if param.kind is not ParameterKind.keyword_only
282
397
  ]
283
398
 
284
399
  keyword_parameters = [
285
- param for param in model.parameters
400
+ param
401
+ for param in alias.parameters
286
402
  if param.kind is ParameterKind.keyword_only
287
403
  ]
288
404
 
289
- if document_parameters and standard_parameters:
290
- model.docstring._extra_sections.append(
405
+ if (
406
+ config.get("show_docstring_input_arguments", True)
407
+ and document_parameters
408
+ and standard_parameters
409
+ ):
410
+ alias.docstring._suffixes.append(
291
411
  DocstringSectionParameters(
292
412
  [
293
413
  DocstringParameter(
@@ -305,10 +425,13 @@ class PathCollection(ModulesCollection):
305
425
  )
306
426
  )
307
427
 
308
- if document_parameters and keyword_parameters:
309
-
310
- model.docstring._extra_sections.append(
311
- DocstringSectionParameters(
428
+ if (
429
+ config.get("show_docstring_name_value_arguments", True)
430
+ and document_parameters
431
+ and keyword_parameters
432
+ ):
433
+ alias.docstring._suffixes.append(
434
+ DocstringSectionOtherParameters(
312
435
  [
313
436
  DocstringParameter(
314
437
  name=param.name,
@@ -322,11 +445,11 @@ class PathCollection(ModulesCollection):
322
445
  )
323
446
  for param in keyword_parameters
324
447
  ],
325
- title="Keyword Arguments:",
448
+ title="Name-Value Arguments:",
326
449
  )
327
450
  )
328
451
 
329
- if document_returns:
452
+ if config.get("show_docstring_output_arguments", True) and document_returns:
330
453
  returns = DocstringSectionReturns(
331
454
  [
332
455
  DocstringReturn(
@@ -339,46 +462,30 @@ class PathCollection(ModulesCollection):
339
462
  if param.docstring is not None
340
463
  else "",
341
464
  )
342
- for param in model.returns or []
465
+ for param in alias.returns or []
343
466
  ]
344
467
  )
345
- model.docstring._extra_sections.append(returns)
346
-
347
- for member in getattr(model, "members", {}).values():
348
- self.update_model(member, config)
349
-
350
- if (
351
- isinstance(model, Class)
352
- and config.get("merge_constructor_into_class", False)
353
- and model.name in model.members
354
- and model.members[model.name].docstring is not None
355
- ):
356
- model = deepcopy(model)
357
- constructor = model.members.pop(model.name)
358
- if constructor.docstring is not None:
359
- if model.docstring is None:
360
- model.docstring = Docstring("", parent=model)
361
- model.docstring._extra_sections.extend(constructor.docstring.parsed)
468
+ alias.docstring._suffixes.append(returns)
362
469
 
470
+ # Add inheritance diagram to class docstring
363
471
  if (
364
- isinstance(model, Class)
472
+ isinstance(alias, Class)
365
473
  and config.get("show_inheritance_diagram", False)
366
474
  and (
367
475
  (
368
- model.docstring is not None
369
- and "Inheritance Diagram" not in model.docstring.parsed
476
+ alias.docstring is not None
477
+ and "Inheritance Diagram" not in alias.docstring.parsed
370
478
  )
371
- or model.docstring is None
479
+ or alias.docstring is None
372
480
  )
373
481
  ):
374
- diagram = self.get_inheritance_diagram(model)
482
+ diagram = self.get_inheritance_diagram(alias)
375
483
  if diagram is not None:
376
- model = deepcopy(model)
377
- if model.docstring is None:
378
- model.docstring = Docstring("", parent=model)
379
- model.docstring._extra_sections.append(diagram)
484
+ if alias.docstring is None:
485
+ alias.docstring = Docstring("", parent=alias)
486
+ alias.docstring._prefixes.append(diagram)
380
487
 
381
- return model
488
+ return alias
382
489
 
383
490
  def addpath(self, path: str | Path, to_end: bool = False, recursive: bool = False):
384
491
  """
@@ -469,7 +576,7 @@ class PathCollection(ModulesCollection):
469
576
 
470
577
  nodes_str = "\n".join(list(nodes))
471
578
  links_str = "\n".join(list(get_links(model)))
472
- section = f"## Inheritance Diagram\n\n```mermaid\nflowchart TB\n{nodes_str}\n{links_str}\n```"
579
+ section = f"```mermaid\nflowchart TB\n{nodes_str}\n{links_str}\n```"
473
580
 
474
581
  return DocstringSectionText(section, title="Inheritance Diagram")
475
582
 
@@ -577,11 +684,7 @@ class LazyModel:
577
684
  if not isinstance(model, Classfolder):
578
685
  return None
579
686
  for member in path.iterdir():
580
- if (
581
- member.is_file()
582
- and member.suffix == ".m"
583
- and member != classfile
584
- ):
687
+ if member.is_file() and member.suffix == ".m" and member != classfile:
585
688
  if member.name == "Contents.m" and model.docstring is None:
586
689
  contentsfile = self._collect_path(member)
587
690
  model.docstring = contentsfile.docstring
@@ -618,14 +721,13 @@ class LazyModel:
618
721
  return model
619
722
 
620
723
  def _collect_readme_md(self, path, parent: MatlabMixin) -> Docstring | None:
621
-
622
724
  if (path / "README.md").exists():
623
725
  readme = path / "README.md"
624
726
  elif (path / "readme.md").exists():
625
727
  readme = path / "readme.md"
626
728
  else:
627
729
  return None
628
-
730
+
629
731
  with open(readme, "r") as file:
630
732
  content = file.read()
631
- return Docstring(content, parent=parent)
733
+ return Docstring(content, parent=parent)
@@ -1,11 +1,13 @@
1
1
  from pathlib import Path
2
2
  from collections import ChainMap
3
3
  from markdown import Markdown
4
+ from mkdocstrings.extension import PluginError
4
5
  from mkdocstrings.handlers.base import BaseHandler, CollectorItem, CollectionError
5
6
  from mkdocstrings_handlers.python import rendering
6
7
  from typing import Any, ClassVar, Mapping
7
8
  from pprint import pprint
8
9
 
10
+ import re
9
11
 
10
12
  from mkdocstrings_handlers.matlab.collect import LinesCollection, PathCollection
11
13
 
@@ -23,7 +25,6 @@ class MatlabHandler(BaseHandler):
23
25
  """The fallback theme."""
24
26
  fallback_config: ClassVar[dict] = {
25
27
  "fallback": True,
26
- "merge_constructor_into_class": True,
27
28
  }
28
29
  """The configuration used to collect item during autorefs fallback."""
29
30
  default_config: ClassVar[dict] = {
@@ -33,6 +34,7 @@ class MatlabHandler(BaseHandler):
33
34
  "show_source": True,
34
35
  # Heading options
35
36
  "heading_level": 2,
37
+ "parameter_headings": True,
36
38
  "show_root_heading": False,
37
39
  "show_root_toc_entry": True,
38
40
  "show_root_full_path": True,
@@ -42,37 +44,37 @@ class MatlabHandler(BaseHandler):
42
44
  "show_symbol_type_heading": False,
43
45
  "show_symbol_type_toc": False,
44
46
  # Member options
45
- "inherited_members": False,
46
47
  "members": None,
47
- "members_order": rendering.Order.alphabetical, # TODO broken
48
- "filters": [],
49
- "group_by_category": True, # TODO broken
50
- "summary": False, # TODO broken
48
+ "hidden_members": False,
49
+ "private_members": False,
50
+ "inherited_members": False,
51
+ "members_order": rendering.Order.alphabetical.value,
52
+ "filters": ["!^delete$|^disp$"],
53
+ "group_by_category": True,
54
+ "summary": False,
51
55
  "show_labels": True,
52
56
  # Docstring options
53
57
  "docstring_style": "google",
54
58
  "docstring_options": {},
55
59
  "docstring_section_style": "table",
56
- "create_from_argument_blocks": False,
57
- "merge_constructor_into_class": True,
60
+ "parse_arguments": False,
61
+ "merge_constructor_into_class": False,
62
+ "merge_constructor_ignore_summary": False,
58
63
  "show_if_no_docstring": False,
59
- "show_docstring_attributes": True,
64
+ "show_docstring_propeties": True,
60
65
  "show_docstring_functions": True,
61
66
  "show_docstring_classes": True,
62
- "show_docstring_modules": True, # TODO should be replaced with namespaces
67
+ "show_docstring_namespaces": True,
63
68
  "show_docstring_description": True,
64
69
  "show_docstring_examples": True,
65
- "show_docstring_other_parameters": True, # TODO should be name value pairs
66
- "show_docstring_parameters": True,
67
- "show_docstring_raises": True, # TODO need to additional parsing for this
68
- "show_docstring_returns": True,
69
- "show_docstring_warns": True, # TODO need to additional parsing for this
70
+ "show_docstring_input_arguments": True,
71
+ "show_docstring_name_value_arguments": True,
72
+ "show_docstring_output_arguments": True,
70
73
  # Signature options
71
- "annotations_path": "brief",
72
- "line_length": 60,
73
74
  "show_signature": True,
74
75
  "show_signature_annotations": False,
75
76
  "separate_signature": False,
77
+ "signature_crossrefs": False,
76
78
  }
77
79
  """Default handler configuration.
78
80
 
@@ -84,6 +86,7 @@ class MatlabHandler(BaseHandler):
84
86
 
85
87
  Attributes: Headings options:
86
88
  heading_level (int): The initial heading level to use. Default: `2`.
89
+ parameter_headings (bool): Whether to render headings for parameters (therefore showing parameters in the ToC). Default: `False`.
87
90
  show_root_heading (bool): Show the heading of the object at the root of the documentation tree
88
91
  (i.e. the object referenced by the identifier after `:::`). Default: `False`.
89
92
  show_root_toc_entry (bool): If the root heading is not shown, at least add a ToC entry for it. Default: `True`.
@@ -95,50 +98,52 @@ class MatlabHandler(BaseHandler):
95
98
  show_symbol_type_toc (bool): Show the symbol type in the Table of Contents (e.g. mod, class, methd, func and attr). Default: `False`.
96
99
 
97
100
  Attributes: Members options:
98
- inherited_members (list[str] | bool | None): A boolean, or an explicit list of inherited members to render.
99
- If true, select all inherited members, which can then be filtered with `members`.
100
- If false or empty list, do not select any inherited member. Default: `False`.
101
101
  members (list[str] | bool | None): A boolean, or an explicit list of members to render.
102
102
  If true, select all members without further filtering.
103
103
  If false or empty list, do not render members.
104
104
  If none, select all members and apply further filtering with filters and docstrings. Default: `None`.
105
+ hidden_members (list[str] | bool | None): A boolean, or an explicit list of hidden members to render.
106
+ If true, select all inherited members, which can then be filtered with `members`.
107
+ If false or empty list, do not select any hidden member. Default: `False`.
108
+ private_members (list[str] | bool | None): A boolean, or an explicit list of private members to render.
109
+ If true, select all inherited members, which can then be filtered with `members`.
110
+ If false or empty list, do not select any private member. Default: `False`.
111
+ inherited_members (list[str] | bool | None): A boolean, or an explicit list of inherited members to render.
112
+ If true, select all inherited members, which can then be filtered with `members`.
113
+ If false or empty list, do not select any inherited member. Default: `False`.
105
114
  members_order (str): The members ordering to use. Options: `alphabetical` - order by the members names,
106
115
  `source` - order members as they appear in the source file. Default: `"alphabetical"`.
107
116
  filters (list[str] | None): A list of filters applied to filter objects based on their name.
108
117
  A filter starting with `!` will exclude matching objects instead of including them.
109
118
  The `members` option takes precedence over `filters` (filters will still be applied recursively
110
- to lower members in the hierarchy). Default: `["!^_[^_]"]`.
111
- group_by_category (bool): Group the object's children by categories: attributes, classes, functions, and modules. Default: `True`.
112
- summary (bool | dict[str, bool]): Whether to render summaries of modules, classes, functions (methods) and attributes.
119
+ to lower members in the hierarchy). Default: `["!^delete$|^disp$"]`.
120
+ group_by_category (bool): Group the object's children by categories: properties, classes, functions, and namespaces. Default: `True`.
121
+ summary (bool | dict[str, bool]): Whether to render summaries of namespaces, classes, functions (methods) and properties. Default: `False`.
113
122
  show_labels (bool): Whether to show labels of the members. Default: `True`.
114
123
 
115
124
  Attributes: Docstrings options:
116
125
  docstring_style (str): The docstring style to use: `google`, `numpy`, `sphinx`, or `None`. Default: `"google"`.
117
126
  docstring_options (dict): The options for the docstring parser. See [docstring parsers](https://mkdocstrings.github.io/griffe/reference/docstrings/) and their options in Griffe docs.
118
127
  docstring_section_style (str): The style used to render docstring sections. Options: `table`, `list`, `spacy`. Default: `"table"`.
128
+ parse_arguments (bool): Whether to load inputs and output parameters based on argument validation blocks. Default: `True`.
119
129
  merge_constructor_into_class (bool): Whether to merge the constructor method into the class' signature and docstring. Default: `False`.
120
- create_from_argument_blocks (bool): Whether to create sections for inputs and output arguments based on argument validation blocks. Default: `False`.
121
- relative_crossrefs (bool): Whether to enable the relative crossref syntax. Default: `False`.
122
- scoped_crossrefs (bool): Whether to enable the scoped crossref ability. Default: `False`.
130
+ merge_constructor_ignore_summary (bool): Whether to ignore the constructor summary when merging it into the class. Default: `False`.
123
131
  show_if_no_docstring (bool): Show the object heading even if it has no docstring or children with docstrings. Default: `False`.
124
- show_docstring_attributes (bool): Whether to display the "Attributes" section in the object's docstring. Default: `True`.
132
+ show_docstring_properties (bool): Whether to display the "Properties" section in the object's docstring. Default: `True`.
125
133
  show_docstring_functions (bool): Whether to display the "Functions" or "Methods" sections in the object's docstring. Default: `True`.
126
134
  show_docstring_classes (bool): Whether to display the "Classes" section in the object's docstring. Default: `True`.
127
- show_docstring_modules (bool): Whether to display the "Modules" section in the object's docstring. Default: `True`.
135
+ show_docstring_namespaces (bool): Whether to display the "Namespaces" section in the object's docstring. Default: `True`.
128
136
  show_docstring_description (bool): Whether to display the textual block (including admonitions) in the object's docstring. Default: `True`.
129
137
  show_docstring_examples (bool): Whether to display the "Examples" section in the object's docstring. Default: `True`.
130
- show_docstring_other_parameters (bool): Whether to display the "Other Parameters" section in the object's docstring. Default: `True`.
131
- show_docstring_parameters (bool): Whether to display the "Parameters" section in the object's docstring. Default: `True`.
132
- show_docstring_raises (bool): Whether to display the "Raises" section in the object's docstring. Default: `True`.
133
- show_docstring_returns (bool): Whether to display the "Returns" section in the object's docstring. Default: `True`.
134
- show_docstring_warns (bool): Whether to display the "Warns" section in the object's docstring. Default: `True`.
138
+ show_docstring_input_arguments (bool): Whether to display the "Input arguments" section in the object's docstring. Default: `True`.
139
+ show_docstring_name_value_arguments (bool): Whether to display the "Name-value pairs" section in the object's docstring. Default: `True`.
140
+ show_docstring_output_arguments (bool): Whether to display the "Output arguments" section in the object's docstring. Default: `True`.
135
141
 
136
142
  Attributes: Signatures/annotations options:
137
- annotations_path (str): The verbosity for annotations path: `brief` (recommended), or `source` (as written in the source). Default: `"brief"`.
138
- line_length (int): Maximum line length when formatting code/signatures. Default: `60`.
139
143
  show_signature (bool): Show methods and functions signatures. Default: `True`.
140
144
  show_signature_annotations (bool): Show the type annotations in methods and functions signatures. Default: `False`.
141
145
  separate_signature (bool): Whether to put the whole signature in a code block below the heading.
146
+ signature_crossrefs (bool): Whether to render cross-references for type annotations in signatures. Default: `False`.
142
147
  """
143
148
 
144
149
  def __init__(
@@ -200,6 +205,77 @@ class MatlabHandler(BaseHandler):
200
205
 
201
206
  heading_level = final_config["heading_level"]
202
207
 
208
+ try:
209
+ final_config["members_order"] = rendering.Order(
210
+ final_config["members_order"]
211
+ )
212
+ except ValueError as error:
213
+ choices = "', '".join(item.value for item in rendering.Order)
214
+ raise PluginError(
215
+ f"Unknown members_order '{final_config['members_order']}', choose between '{choices}'.",
216
+ ) from error
217
+
218
+ if final_config["filters"]:
219
+ final_config["filters"] = [
220
+ (re.compile(filtr.lstrip("!")), filtr.startswith("!"))
221
+ for filtr in final_config["filters"]
222
+ ]
223
+
224
+ summary = final_config["summary"]
225
+ if summary is True:
226
+ final_config["summary"] = {
227
+ "attributes": True,
228
+ "functions": True,
229
+ "classes": True,
230
+ "modules": True,
231
+ }
232
+ elif summary is False:
233
+ final_config["summary"] = {
234
+ "attributes": False,
235
+ "functions": False,
236
+ "classes": False,
237
+ "modules": False,
238
+ }
239
+ else:
240
+ final_config["summary"] = {
241
+ "attributes": summary.get(
242
+ "properties", False
243
+ ), # Map properties (MATLAB) to attributes (Python)
244
+ "functions": summary.get("functions", False),
245
+ "classes": summary.get("classes", False),
246
+ "modules": summary.get(
247
+ "namespaces", False
248
+ ), # Map namespaces (MATLAB) to modules (Python)
249
+ }
250
+
251
+ # Map docstring options
252
+ final_config["show_docstring_attributes"] = config.get(
253
+ "show_docstring_properties", True
254
+ )
255
+ final_config["show_docstring_modules"] = config.get(
256
+ "show_docstring_namespaces", True
257
+ )
258
+ final_config["show_docstring_parameters"] = config.get(
259
+ "show_docstring_input_arguments", True
260
+ )
261
+ final_config["show_docstring_other_parameters"] = config.get(
262
+ "show_docstring_name_value_arguments", True
263
+ )
264
+ final_config["show_docstring_returns"] = config.get(
265
+ "show_docstring_output_arguments", True
266
+ )
267
+
268
+ # These settings must be present to avoid errors
269
+ for setting in [
270
+ "merge_init_into_class",
271
+ "show_docstring_raises",
272
+ "show_docstring_receives",
273
+ "show_docstring_yields",
274
+ "show_docstring_warns",
275
+ ]:
276
+ final_config[setting] = False
277
+ final_config["line_length"] = 88
278
+
203
279
  return template.render(
204
280
  **{
205
281
  "config": final_config,
@@ -229,12 +305,13 @@ class MatlabHandler(BaseHandler):
229
305
  self.env.filters["format_signature"] = rendering.do_format_signature
230
306
  self.env.filters["format_attribute"] = rendering.do_format_attribute
231
307
  self.env.filters["filter_objects"] = rendering.do_filter_objects
232
- self.env.filters["stash_crossref"] = lambda ref, length: ref
308
+ self.env.filters["stash_crossref"] = rendering.do_stash_crossref
233
309
  self.env.filters["get_template"] = rendering.do_get_template
234
310
  self.env.filters["as_attributes_section"] = rendering.do_as_attributes_section
235
311
  self.env.filters["as_functions_section"] = rendering.do_as_functions_section
236
312
  self.env.filters["as_classes_section"] = rendering.do_as_classes_section
237
313
  self.env.filters["as_modules_section"] = rendering.do_as_modules_section
314
+ self.env.globals["AutorefsHook"] = rendering.AutorefsHook
238
315
  self.env.tests["existing_template"] = (
239
316
  lambda template_name: template_name in self.env.list_templates()
240
317
  )
@@ -2,6 +2,7 @@ from typing import Any, TYPE_CHECKING, Callable
2
2
  from functools import cached_property
3
3
  from pathlib import Path
4
4
  from griffe import (
5
+ Alias,
5
6
  Attribute,
6
7
  Function as GriffeFunction,
7
8
  Class as GriffeClass,
@@ -45,7 +46,7 @@ class Docstring(GriffeDocstring):
45
46
  that can be added to the parsed docstring.
46
47
 
47
48
  Attributes:
48
- _extra_sections (list[DocstringSection]): A list to store additional docstring sections.
49
+ _suffixes (list[DocstringSection]): A list to store additional docstring sections.
49
50
 
50
51
  Methods:
51
52
  parsed: Returns the parsed docstring sections combined with extra sections.
@@ -61,7 +62,8 @@ class Docstring(GriffeDocstring):
61
62
  **kwargs (Any): Arbitrary keyword arguments.
62
63
  """
63
64
  super().__init__(*args, **kwargs)
64
- self._extra_sections: list[DocstringSection] = []
65
+ self._prefixes: list[DocstringSection] = []
66
+ self._suffixes: list[DocstringSection] = []
65
67
 
66
68
  @property
67
69
  def parsed(self) -> list[DocstringSection]:
@@ -71,7 +73,7 @@ class Docstring(GriffeDocstring):
71
73
  Returns:
72
74
  list[DocstringSection]: The combined list of parsed and extra docstring sections.
73
75
  """
74
- return self._parsed + self._extra_sections
76
+ return self._prefixes + self._parsed + self._suffixes
75
77
 
76
78
  @cached_property
77
79
  def _parsed(self) -> list[DocstringSection]:
@@ -318,9 +320,10 @@ class Class(MatlabMixin, PathMixin, GriffeClass, MatlabObject):
318
320
  **kwargs: Any,
319
321
  ) -> None:
320
322
  super().__init__(*args, **kwargs)
321
- self.abstract: bool = Abstract
322
- self.hidden: bool = Hidden
323
- self.sealed: bool = Sealed
323
+ self.Abstract: bool = Abstract
324
+ self.Hidden: bool = Hidden
325
+ self.Sealed: bool = Sealed
326
+ self._inherited_members: dict[str, MatlabObject] | None = None
324
327
 
325
328
  @property
326
329
  def parameters(self) -> Parameters:
@@ -350,6 +353,8 @@ class Class(MatlabMixin, PathMixin, GriffeClass, MatlabObject):
350
353
  Returns:
351
354
  dict[str, MatlabObject]: A dictionary where the keys are member names and the values are the corresponding MatlabObject instances.
352
355
  """
356
+ if self._inherited_members is not None:
357
+ return self._inherited_members
353
358
 
354
359
  inherited_members = {}
355
360
  for base in reversed(self.bases):
@@ -364,28 +369,28 @@ class Class(MatlabMixin, PathMixin, GriffeClass, MatlabObject):
364
369
 
365
370
  for name, member in model.members.items():
366
371
  if name not in self.members:
367
- inherited_members[name] = member
372
+ inherited_members[name] = Alias(
373
+ name, target=member, parent=self, inherited=True
374
+ )
375
+
376
+ self._inherited_members = inherited_members
368
377
  return inherited_members
369
378
 
370
379
  @property
371
380
  def labels(self) -> set[str]:
372
381
  labels = set()
373
- if self.abstract:
374
- labels.add("abstract")
375
- if self.hidden:
376
- labels.add("hidden")
377
- if self.sealed:
378
- labels.add("sealed")
382
+ if self.Abstract:
383
+ labels.add("Abstract")
384
+ if self.Hidden:
385
+ labels.add("Hidden")
386
+ if self.Sealed:
387
+ labels.add("Sealed")
379
388
  return labels
380
389
 
381
390
  @labels.setter
382
391
  def labels(self, *args):
383
392
  pass
384
393
 
385
- @property
386
- def is_private(self) -> bool:
387
- return self.hidden
388
-
389
394
  @property
390
395
  def canonical_path(self) -> str:
391
396
  if isinstance(self.parent, Classfolder):
@@ -416,54 +421,61 @@ class Property(MatlabMixin, Attribute, MatlabObject):
416
421
  SetObservable: bool = False,
417
422
  Transient: bool = False,
418
423
  WeakHandle: bool = False,
424
+ Access: AccessEnum = AccessEnum.public,
419
425
  GetAccess: AccessEnum = AccessEnum.public,
420
426
  SetAccess: AccessEnum = AccessEnum.public,
421
427
  **kwargs: Any,
422
428
  ) -> None:
423
429
  super().__init__(*args, **kwargs)
424
- self.abort_set: bool = AbortSet
425
- self.abstract: bool = Abstract
426
- self.constant: bool = Constant
427
- self.dependent: bool = Dependent
428
- self.get_observable: bool = GetObservable
429
- self.hidden: bool = Hidden
430
- self.non_copyable: bool = NonCopyable
431
- self.set_observable: bool = SetObservable
432
- self.transient: bool = Transient
433
- self.weak_handle: bool = WeakHandle
434
- self.get_access: AccessEnum = GetAccess
435
- self.set_access: AccessEnum = SetAccess
430
+ self.AbortSet: bool = AbortSet
431
+ self.Abstract: bool = Abstract
432
+ self.Constant: bool = Constant
433
+ self.Dependent: bool = Dependent
434
+ self.GetObservable: bool = GetObservable
435
+ self.Hidden: bool = Hidden
436
+ self.NonCopyable: bool = NonCopyable
437
+ self.SetObservable: bool = SetObservable
438
+ self.Transient: bool = Transient
439
+ self.WeakHandle: bool = WeakHandle
440
+ self.Access = Access
441
+ self.GetAccess: AccessEnum = GetAccess
442
+ self.SetAccess: AccessEnum = SetAccess
436
443
  self.getter: Function | None = None
437
444
 
438
445
  @property
439
- def is_private(self) -> bool:
440
- set_public = (
441
- self.set_access == AccessEnum.public
442
- or self.set_access == AccessEnum.immutable
446
+ def Private(self) -> bool:
447
+ private = self.Access != AccessEnum.public
448
+ set_private = (
449
+ self.SetAccess != AccessEnum.public
450
+ and self.SetAccess != AccessEnum.immutable
443
451
  )
444
- get_public = self.get_access == AccessEnum.public
445
- return (set_public or get_public) and not self.hidden
452
+ get_private = self.GetAccess != AccessEnum.public
453
+ return private or set_private or get_private
454
+
455
+ @property
456
+ def is_private(self) -> bool:
457
+ return self.Private or self.Hidden
446
458
 
447
459
  @property
448
460
  def labels(self) -> set[str]:
449
461
  labels = set()
450
462
  for attr in [
451
- "abort_set",
452
- "abstract",
453
- "constant",
454
- "dependent",
455
- "get_observable",
456
- "hidden",
457
- "non_copyable",
458
- "set_observable",
459
- "transient",
460
- "weak_handle",
463
+ "AbortSet",
464
+ "Abstract",
465
+ "Constant",
466
+ "Dependent",
467
+ "GetObservable",
468
+ "Hidden",
469
+ "NonCopyable",
470
+ "SetObservable",
471
+ "Transient",
472
+ "WeakHandle",
461
473
  ]:
462
474
  if getattr(self, attr):
463
475
  labels.add(attr)
464
- for attr in ["get_access", "set_access"]:
476
+ for attr in ["Access", "GetAccess", "SetAccess"]:
465
477
  if getattr(self, attr) != AccessEnum.public:
466
- labels.add(f"{attr}={str(getattr(self, attr))}")
478
+ labels.add(f"{attr}={getattr(self, attr).value}")
467
479
  return labels
468
480
 
469
481
  @labels.setter
@@ -514,27 +526,30 @@ class Function(MatlabMixin, PathMixin, GriffeFunction, MatlabObject):
514
526
  super().__init__(*args, **kwargs)
515
527
  self.parameters: Parameters = Parameters()
516
528
  self.returns: Parameters | None = returns
517
- self.access: AccessEnum = Access
518
- self.static: bool = Static
519
- self.abstract: bool = Abstract
520
- self.sealed: bool = Sealed
521
- self.hidden: bool = Hidden
529
+ self.Access: AccessEnum = Access
530
+ self.Static: bool = Static
531
+ self.Abstract: bool = Abstract
532
+ self.Sealed: bool = Sealed
533
+ self.Hidden: bool = Hidden
522
534
  self._is_setter: bool = setter
523
535
  self._is_getter: bool = getter
524
536
 
537
+ @property
538
+ def Private(self) -> bool:
539
+ return self.Access != AccessEnum.public and self.Access != AccessEnum.immutable
540
+
525
541
  @property
526
542
  def is_private(self) -> bool:
527
- public = self.access == AccessEnum.public or self.access == AccessEnum.immutable
528
- return public and not self.hidden
543
+ return self.Private or self.Hidden
529
544
 
530
545
  @property
531
546
  def labels(self) -> set[str]:
532
547
  labels = set()
533
- for attr in ["abstract", "hidden", "sealed", "static"]:
548
+ for attr in ["Abstract", "Hidden", "Sealed", "Static"]:
534
549
  if getattr(self, attr):
535
550
  labels.add(attr)
536
- if self.access != AccessEnum.public:
537
- labels.add(f"access={str(self.access)}")
551
+ if self.Access != AccessEnum.public:
552
+ labels.add(f"Access={self.Access.value}")
538
553
  return labels
539
554
 
540
555
  @labels.setter
@@ -561,4 +576,8 @@ class Namespace(MatlabMixin, PathMixin, Module, MatlabObject):
561
576
 
562
577
  @property
563
578
  def is_internal(self) -> bool:
564
- return any(part == "+internal" for part in self.filepath.parts) if self.filepath else False
579
+ return (
580
+ any(part == "+internal" for part in self.filepath.parts)
581
+ if self.filepath
582
+ else False
583
+ )
@@ -105,9 +105,9 @@ CLASS_QUERY = LANGUAGE.query("""("classdef" .
105
105
  (attributes
106
106
  (attribute) @attributes
107
107
  )? .
108
- (identifier) @name ?
108
+ (identifier) @name .
109
109
  (superclasses
110
- (property_name)+ @bases
110
+ (property_name) @bases
111
111
  )? .
112
112
  (comment)* @docstring .
113
113
  ("\\n")? .
@@ -316,7 +316,7 @@ class FileParser(object):
316
316
  "WeakHandle",
317
317
  ]:
318
318
  property_kwargs[key] = value
319
- elif key in ["GetAccess", "SetAccess"]:
319
+ elif key in ["Access", "GetAccess", "SetAccess"]:
320
320
  if value in ["public", "protected", "private", "immutable"]:
321
321
  property_kwargs[key] = AccessEnum(value)
322
322
  else:
@@ -332,6 +332,7 @@ class FileParser(object):
332
332
  property_captures.get("comment", None)
333
333
  ),
334
334
  parent=model,
335
+ **property_kwargs,
335
336
  )
336
337
  model.members[prop.name] = prop
337
338
 
@@ -351,7 +352,7 @@ class FileParser(object):
351
352
  "Static",
352
353
  ]:
353
354
  method_kwargs[key] = value
354
- elif key in ["GetAccess", "SetAccess"]:
355
+ elif key == "Access":
355
356
  if value in ["public", "protected", "private", "immutable"]:
356
357
  method_kwargs[key] = AccessEnum(value)
357
358
  else:
@@ -362,7 +363,7 @@ class FileParser(object):
362
363
  )
363
364
  if (
364
365
  method.name != self.filepath.stem
365
- and not method.static
366
+ and not method.Static
366
367
  and method.parameters
367
368
  ):
368
369
  # Remove self from first method argument
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocstrings-matlab
3
- Version: 0.3.2
3
+ Version: 0.4.0
4
4
  Summary: A MATLAB handler for mkdocstrings
5
5
  Author-email: Mark Hu <watermarkhu@gmail.com>
6
6
  License: ISC
@@ -23,8 +23,9 @@ Classifier: Typing :: Typed
23
23
  Requires-Python: >=3.10
24
24
  Requires-Dist: charset-normalizer>=3.3.2
25
25
  Requires-Dist: griffe>=1.5.1
26
- Requires-Dist: mkdocs>=1.6.0
27
- Requires-Dist: mkdocstrings[python]>=0.18
26
+ Requires-Dist: mkdocs==1.6.1
27
+ Requires-Dist: mkdocstrings-python==1.13.0
28
+ Requires-Dist: mkdocstrings==0.27.0
28
29
  Requires-Dist: tree-sitter-matlab>=1.0.2
29
30
  Requires-Dist: tree-sitter>=0.23.2
30
31
  Description-Content-Type: text/markdown
@@ -36,7 +37,7 @@ Description-Content-Type: text/markdown
36
37
 
37
38
  ---
38
39
 
39
- <p align="center"><img src="logo.png"></p>
40
+ <p align="center"><img src="logo.svg"></p>
40
41
 
41
42
  The MATLAB handler uses [Tree-sitter](https://tree-sitter.github.io/tree-sitter/) and its [MATLAB parser](https://github.com/acristoffers/tree-sitter-matlab) to collect documentation from MATLAB source code. Via the python bindings the Abstract Syntax Tree (AST) of the source code is traversed to extract useful information. The imported objected are imported as custom [Griffe](https://mkdocstrings.github.io/griffe/) objects and mocked for the [python handler](https://mkdocstrings.github.io/python/).
42
43
 
@@ -0,0 +1,15 @@
1
+ mkdocs_material_matlab/__init__.py,sha256=9pmrwWbkIyr0T7qvADbsz3OR5bB3rWb231e6JSnwA7o,106
2
+ mkdocs_material_matlab/mkdocs_material_matlab.py,sha256=s7vI1lv6hD8s7kDHWBfYKgN6EcldyUstGYJ45sA-VWY,850
3
+ mkdocs_material_matlab/css/style.css,sha256=iVTPIKljgvK899jEQylD7yu9yjKfrVE_4GLaITjhk4g,132
4
+ mkdocstrings_handlers/matlab/__init__.py,sha256=7UCCosKn8S38xgJQQy9_1P2oMyPVsTeDkcLPVIoDneU,1000
5
+ mkdocstrings_handlers/matlab/collect.py,sha256=JAcYih8LMU9jDgxuyqR86p6zdp5qYJNxVnE3x9c529U,27440
6
+ mkdocstrings_handlers/matlab/enums.py,sha256=lr3wLlhPxyBym3O7Rt0cLUZYqPCz6wQ2PYBibLKLTek,982
7
+ mkdocstrings_handlers/matlab/handler.py,sha256=Peg4DJsulnJINpdYXMid9dezuVts_P85cOUlowCw7T4,18343
8
+ mkdocstrings_handlers/matlab/models.py,sha256=YmPE9NKsPJ4GBp6es--0yH6uH8BZLPC8xMOh1QHCmY4,18109
9
+ mkdocstrings_handlers/matlab/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ mkdocstrings_handlers/matlab/treesitter.py,sha256=e2rfMPFaprJ6XEPH8xk2i-DKBOY_9UNWFQWPX2R7U98,21756
11
+ mkdocstrings_matlab-0.4.0.dist-info/METADATA,sha256=Q98qVYeK2T1zPs6eToAsOUhif0g21MKv447vcle3-VQ,4134
12
+ mkdocstrings_matlab-0.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
13
+ mkdocstrings_matlab-0.4.0.dist-info/entry_points.txt,sha256=qUZFuB2TKh7KPlg4dR2npfbNgNExw6O6j1vF276PtPw,92
14
+ mkdocstrings_matlab-0.4.0.dist-info/licenses/LICENSE,sha256=z5Ee0lckFL6K9LhLKftDu0JDl2Uie24Po20IclVk2SI,743
15
+ mkdocstrings_matlab-0.4.0.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- mkdocs_material_matlab/__init__.py,sha256=9pmrwWbkIyr0T7qvADbsz3OR5bB3rWb231e6JSnwA7o,106
2
- mkdocs_material_matlab/mkdocs_material_matlab.py,sha256=s7vI1lv6hD8s7kDHWBfYKgN6EcldyUstGYJ45sA-VWY,850
3
- mkdocs_material_matlab/css/style.css,sha256=iVTPIKljgvK899jEQylD7yu9yjKfrVE_4GLaITjhk4g,132
4
- mkdocstrings_handlers/matlab/__init__.py,sha256=laA2bEP5rxdIWBLmfLiKKu7ChZ_HzCe-VeRvxmUTqww,128
5
- mkdocstrings_handlers/matlab/collect.py,sha256=9DKuE5Q6kXcNm6coQZnmtTNRzMNIeILlljMd1GgVEKk,23035
6
- mkdocstrings_handlers/matlab/enums.py,sha256=lr3wLlhPxyBym3O7Rt0cLUZYqPCz6wQ2PYBibLKLTek,982
7
- mkdocstrings_handlers/matlab/handler.py,sha256=KmQuCuaoS-K8HR2peS4LfvBUaJT4a8-428-3ZiHRdYY,15427
8
- mkdocstrings_handlers/matlab/models.py,sha256=y4ozShL4edxKKgb6jqBAfSI8Z9MEygSbEDnTDfBnRtk,17513
9
- mkdocstrings_handlers/matlab/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- mkdocstrings_handlers/matlab/treesitter.py,sha256=dW4RcSep4A0L505WbAE9PGL2sTqizX7nhXLwQqbJh8Y,21726
11
- mkdocstrings_matlab-0.3.2.dist-info/METADATA,sha256=c1mVS2_ocxD-sPdaTEWYauALHXUHoF1qVtnxdLl1k0M,4097
12
- mkdocstrings_matlab-0.3.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
13
- mkdocstrings_matlab-0.3.2.dist-info/entry_points.txt,sha256=qUZFuB2TKh7KPlg4dR2npfbNgNExw6O6j1vF276PtPw,92
14
- mkdocstrings_matlab-0.3.2.dist-info/licenses/LICENSE,sha256=z5Ee0lckFL6K9LhLKftDu0JDl2Uie24Po20IclVk2SI,743
15
- mkdocstrings_matlab-0.3.2.dist-info/RECORD,,