mkdocstrings-matlab 0.6.0__py3-none-any.whl → 0.8.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (22) hide show
  1. mkdocstrings_handlers/matlab/collect.py +84 -32
  2. mkdocstrings_handlers/matlab/handler.py +31 -10
  3. mkdocstrings_handlers/matlab/models.py +60 -28
  4. mkdocstrings_handlers/matlab/templates/material/children.html.jinja +172 -0
  5. mkdocstrings_handlers/matlab/templates/material/docstring/namespaces.html.jinja +86 -0
  6. mkdocstrings_handlers/matlab/templates/material/docstring/properties.html.jinja +109 -0
  7. mkdocstrings_handlers/matlab/templates/material/folder.html.jinja +121 -0
  8. mkdocstrings_handlers/matlab/templates/material/namespace.html.jinja +121 -0
  9. mkdocstrings_handlers/matlab/templates/material/property.html.jinja +120 -0
  10. mkdocstrings_handlers/matlab/templates/material/style.css +26 -0
  11. mkdocstrings_handlers/matlab/templates/material/summary/namespaces.html.jinja +21 -0
  12. mkdocstrings_handlers/matlab/templates/material/summary/properties.html.jinja +21 -0
  13. mkdocstrings_handlers/matlab/templates/material/summary.html.jinja +26 -0
  14. {mkdocstrings_matlab-0.6.0.dist-info → mkdocstrings_matlab-0.8.0.dist-info}/METADATA +9 -9
  15. mkdocstrings_matlab-0.8.0.dist-info/RECORD +21 -0
  16. mkdocs_material_matlab/__init__.py +0 -4
  17. mkdocs_material_matlab/css/style.css +0 -7
  18. mkdocs_material_matlab/mkdocs_material_matlab.py +0 -20
  19. mkdocstrings_matlab-0.6.0.dist-info/RECORD +0 -15
  20. mkdocstrings_matlab-0.6.0.dist-info/entry_points.txt +0 -2
  21. {mkdocstrings_matlab-0.6.0.dist-info → mkdocstrings_matlab-0.8.0.dist-info}/WHEEL +0 -0
  22. {mkdocstrings_matlab-0.6.0.dist-info → mkdocstrings_matlab-0.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -3,7 +3,7 @@
3
3
  from collections import defaultdict, deque
4
4
  from copy import copy, deepcopy
5
5
  from pathlib import Path
6
- from typing import Mapping, Sequence
6
+ from typing import Mapping, Sequence, Callable, TypeVar
7
7
 
8
8
  from _griffe.collections import LinesCollection as GLC, ModulesCollection
9
9
  from _griffe.docstrings.models import (
@@ -24,14 +24,16 @@ from mkdocstrings_handlers.matlab.models import (
24
24
  Docstring,
25
25
  DocstringSectionText,
26
26
  Function,
27
+ Folder,
27
28
  MatlabMixin,
28
- Object,
29
29
  Namespace,
30
- ROOT,
30
+ PathMixin,
31
31
  )
32
32
  from mkdocstrings_handlers.matlab.treesitter import FileParser
33
33
 
34
34
 
35
+ PathType = TypeVar("PathType", bound=PathMixin)
36
+
35
37
  __all__ = ["LinesCollection", "PathCollection"]
36
38
 
37
39
 
@@ -104,6 +106,7 @@ class PathCollection(ModulesCollection):
104
106
  matlab_path (Sequence[str | Path]): A list of strings or Path objects representing the MATLAB paths.
105
107
  recursive (bool, optional): If True, recursively adds all subdirectories of the given paths to the search path. Defaults to False.
106
108
  config (Mapping, optional): Configuration settings for the PathCollection. Defaults to {}.
109
+ config_path (Path | None, optional): The path to the configuration file. Defaults to None.
107
110
 
108
111
  Methods:
109
112
  members() -> dict:
@@ -130,6 +133,7 @@ class PathCollection(ModulesCollection):
130
133
  matlab_path: Sequence[str | Path],
131
134
  recursive: bool = False,
132
135
  config: Mapping = {},
136
+ config_path: Path | None = None,
133
137
  ) -> None:
134
138
  """
135
139
  Initialize an instance of PathCollection.
@@ -148,6 +152,8 @@ class PathCollection(ModulesCollection):
148
152
  self._mapping: dict[str, deque[Path]] = defaultdict(deque)
149
153
  self._models: dict[Path, LazyModel] = {}
150
154
  self._members: dict[Path, list[tuple[str, Path]]] = defaultdict(list)
155
+ self._folders: dict[str, LazyModel] = {}
156
+ self._config_path = config_path
151
157
 
152
158
  self.config = config
153
159
  self.lines_collection = LinesCollection()
@@ -188,6 +194,26 @@ class PathCollection(ModulesCollection):
188
194
  model = self._models[self._mapping[identifier][0]].model()
189
195
  if model is not None:
190
196
  model = self.update_model(model, config)
197
+
198
+ elif self._config_path is not None and "/" in identifier:
199
+ absolute_path = (self._config_path / Path(identifier)).resolve()
200
+ if absolute_path.exists():
201
+ path = absolute_path.relative_to(self._config_path)
202
+ if path.suffix:
203
+ path, member = path.parent, path.stem
204
+ else:
205
+ member = None
206
+ lazymodel = self._folders.get(str(path), None)
207
+
208
+ if lazymodel is not None:
209
+ model = lazymodel.model()
210
+ if model is not None and member is not None:
211
+ model = model.members.get(member, None)
212
+ else:
213
+ model = None
214
+ else:
215
+ model = None
216
+
191
217
  else:
192
218
  model = None
193
219
  name_parts = identifier.split(".")
@@ -511,13 +537,25 @@ class PathCollection(ModulesCollection):
511
537
  else:
512
538
  self._path.appendleft(path)
513
539
 
514
- members = PathGlobber(path, recursive=recursive)
515
- for member in members:
540
+ for member in PathGlobber(path, recursive=recursive):
516
541
  model = LazyModel(member, self)
517
542
  self._models[member] = model
518
543
  self._mapping[model.name].append(member)
519
544
  self._members[path].append((model.name, member))
520
545
 
546
+ if self._config_path is not None and member.parent.stem[0] not in [
547
+ "+",
548
+ "@",
549
+ ]:
550
+ if member.parent.is_relative_to(self._config_path):
551
+ relative_path = member.parent.relative_to(self._config_path)
552
+ if member.parent not in self._folders:
553
+ self._folders[str(relative_path)] = LazyModel(
554
+ member.parent, self
555
+ )
556
+ else:
557
+ pass # TODO: Issue warning?
558
+
521
559
  def rm_path(self, path: str | Path, recursive: bool = False):
522
560
  """
523
561
  Removes a path from the search path and updates the namespace and database accordingly.
@@ -610,6 +648,10 @@ class LazyModel:
610
648
  self._path_collection: PathCollection = path_collection
611
649
  self._lines_collection: LinesCollection = path_collection.lines_collection
612
650
 
651
+ @property
652
+ def is_folder(self) -> bool:
653
+ return self._path.is_dir() and self._path.name[0] not in ["+", "@"]
654
+
613
655
  @property
614
656
  def is_class_folder(self) -> bool:
615
657
  return self._path.is_dir() and self._path.name[0] == "@"
@@ -648,7 +690,7 @@ class LazyModel:
648
690
  else:
649
691
  return name
650
692
 
651
- def model(self):
693
+ def model(self) -> MatlabMixin | None:
652
694
  if not self._path.exists():
653
695
  return None
654
696
 
@@ -657,19 +699,22 @@ class LazyModel:
657
699
  self._model = self._collect_classfolder(self._path)
658
700
  elif self.is_namespace:
659
701
  self._model = self._collect_namespace(self._path)
702
+ elif self.is_folder:
703
+ self._model = self._collect_folder(self._path)
660
704
  else:
661
705
  self._model = self._collect_path(self._path)
662
706
  if self._model is not None:
663
707
  self._model.parent = self._collect_parent(self._path.parent)
664
708
  return self._model
665
709
 
666
- def _collect_parent(self, path: Path) -> Object | _ParentGrabber:
710
+ def _collect_parent(self, path: Path) -> _ParentGrabber | None:
667
711
  if self.is_in_namespace:
668
- parent = _ParentGrabber(
669
- lambda: self._path_collection._models[path].model() or ROOT
670
- )
712
+ grabber: Callable[[], MatlabMixin | None] = self._path_collection._models[
713
+ path
714
+ ].model
715
+ parent = _ParentGrabber(grabber)
671
716
  else:
672
- parent = ROOT
717
+ parent = None
673
718
  return parent
674
719
 
675
720
  def _collect_path(self, path: Path) -> MatlabMixin:
@@ -678,6 +723,27 @@ class LazyModel:
678
723
  self._lines_collection[path] = file.content.split("\n")
679
724
  return model
680
725
 
726
+ def _collect_directory(self, path: Path, model: PathType) -> PathType:
727
+ for member in path.iterdir():
728
+ if member.is_dir() and member.name[0] in ["+", "@"]:
729
+ submodel = self._path_collection._models[member].model()
730
+ if submodel is not None:
731
+ model.members[submodel.name] = submodel
732
+
733
+ elif member.is_file() and member.suffix == ".m":
734
+ if member.name == "Contents.m":
735
+ contentsfile = self._collect_path(member)
736
+ model.docstring = contentsfile.docstring
737
+ else:
738
+ submodel = self._path_collection._models[member].model()
739
+ if submodel is not None:
740
+ model.members[submodel.name] = submodel
741
+
742
+ if model.docstring is None:
743
+ model.docstring = self._collect_readme_md(path, model)
744
+
745
+ return model
746
+
681
747
  def _collect_classfolder(self, path: Path) -> Classfolder | None:
682
748
  classfile = path / (path.name[1:] + ".m")
683
749
  if not classfile.exists():
@@ -698,31 +764,17 @@ class LazyModel:
698
764
  model.docstring = self._collect_readme_md(path, model)
699
765
  return model
700
766
 
701
- def _collect_namespace(self, path: Path) -> Namespace | None:
767
+ def _collect_namespace(self, path: Path) -> Namespace:
702
768
  name = self.name[1:].split(".")[-1]
703
769
  model = Namespace(name, filepath=path, path_collection=self._path_collection)
770
+ return self._collect_directory(path, model)
704
771
 
705
- for member in path.iterdir():
706
- if member.is_dir() and member.name[0] in ["+", "@"]:
707
- submodel = self._path_collection._models[member].model()
708
- if submodel is not None:
709
- model.members[submodel.name] = submodel
710
-
711
- elif member.is_file() and member.suffix == ".m":
712
- if member.name == "Contents.m":
713
- contentsfile = self._collect_path(member)
714
- model.docstring = contentsfile.docstring
715
- else:
716
- submodel = self._path_collection._models[member].model()
717
- if submodel is not None:
718
- model.members[submodel.name] = submodel
719
-
720
- if model.docstring is None:
721
- model.docstring = self._collect_readme_md(path, model)
722
-
723
- return model
772
+ def _collect_folder(self, path: Path) -> Folder:
773
+ name = path.stem
774
+ model = Folder(name, filepath=path, path_collection=self._path_collection)
775
+ return self._collect_directory(path, model)
724
776
 
725
- def _collect_readme_md(self, path, parent: MatlabMixin) -> Docstring | None:
777
+ def _collect_readme_md(self, path, parent: PathMixin) -> Docstring | None:
726
778
  if (path / "README.md").exists():
727
779
  readme = path / "README.md"
728
780
  elif (path / "readme.md").exists():
@@ -2,8 +2,9 @@
2
2
 
3
3
  from pathlib import Path
4
4
  from collections import ChainMap
5
+ from jinja2.loaders import FileSystemLoader
5
6
  from markdown import Markdown
6
- from mkdocstrings.extension import PluginError
7
+ from mkdocs.exceptions import PluginError
7
8
  from mkdocstrings.handlers.base import BaseHandler, CollectorItem, CollectionError
8
9
  from mkdocstrings_handlers.python import rendering
9
10
  from typing import Any, ClassVar, Mapping
@@ -152,7 +153,9 @@ class MatlabHandler(BaseHandler):
152
153
 
153
154
  def __init__(
154
155
  self,
155
- *args: Any,
156
+ handler: str,
157
+ theme: str,
158
+ custom_templates: str | None = None,
156
159
  config_file_path: str | None = None,
157
160
  paths: list[str] | None = None,
158
161
  paths_recursive: bool = False,
@@ -163,7 +166,9 @@ class MatlabHandler(BaseHandler):
163
166
  Initialize the handler with the given configuration.
164
167
 
165
168
  Args:
166
- *args (Any): Variable length argument list.
169
+ handler: The name of the handler.
170
+ theme: The name of theme to use.
171
+ custom_templates: Directory containing custom templates.
167
172
  config_file_path (str | None, optional): Path to the configuration file. Defaults to None.
168
173
  paths (list[str] | None, optional): List of paths to include. Defaults to None.
169
174
  paths_recursive (bool, optional): Whether to include paths recursively. Defaults to False.
@@ -173,21 +178,37 @@ class MatlabHandler(BaseHandler):
173
178
  Returns:
174
179
  None
175
180
  """
176
- super().__init__(*args, **kwargs)
181
+
182
+ super().__init__(handler, theme, custom_templates=custom_templates)
183
+
184
+ theme_path = Path(__file__).resolve().parent / "templates" / theme
185
+ if theme_path.exists() and isinstance(self.env.loader, FileSystemLoader):
186
+ # Insert our templates directory at the beginning of the search path to overload the Python templates
187
+ self.env.loader.searchpath.insert(0, str(theme_path))
188
+ css_path = theme_path / "style.css"
189
+ if css_path.exists():
190
+ self.extra_css += "\n" + css_path.read_text(encoding="utf-8")
177
191
 
178
192
  if paths is None or config_file_path is None:
193
+ config_path = None
179
194
  full_paths = []
180
195
  else:
181
196
  config_path = Path(config_file_path).parent
182
197
  full_paths = [(config_path / path).resolve() for path in paths]
183
198
 
199
+ if pathIds := [str(path) for path in full_paths if not path.is_dir()]:
200
+ raise PluginError(
201
+ "The following paths do not exist or are not directories: "
202
+ + ", ".join(pathIds)
203
+ )
204
+
184
205
  self.paths: PathCollection = PathCollection(
185
- full_paths, recursive=paths_recursive
206
+ full_paths, recursive=paths_recursive, config_path=config_path
186
207
  )
187
208
  self.lines: LinesCollection = self.paths.lines_collection
188
209
  self._locale: str = locale
189
210
 
190
- def get_templates_dir(self, handler: str | None = None) -> Path:
211
+ def get_templates_dir(self, *args, **kwargs) -> Path:
191
212
  # use the python handler templates
192
213
  # (it assumes the python handler is installed)
193
214
  return super().get_templates_dir("python")
@@ -253,9 +274,6 @@ class MatlabHandler(BaseHandler):
253
274
  }
254
275
 
255
276
  # Map docstring options
256
- final_config["show_submodules"] = config.get(
257
- "show_subnamespaces", False
258
- )
259
277
  final_config["show_docstring_attributes"] = config.get(
260
278
  "show_docstring_properties", True
261
279
  )
@@ -340,7 +358,10 @@ class MatlabHandler(BaseHandler):
340
358
  raise CollectionError("Empty identifier")
341
359
 
342
360
  final_config = ChainMap(config, self.default_config) # type: ignore[arg-type]
343
- return self.paths.resolve(identifier, config=final_config)
361
+ model = self.paths.resolve(identifier, config=final_config)
362
+ if model is None:
363
+ raise CollectionError(f"Identifier '{identifier}' not found")
364
+ return model
344
365
 
345
366
 
346
367
  def get_handler(
@@ -99,7 +99,7 @@ class _ParentGrabber:
99
99
  __call__(): Calls the grabber function and returns a MatlabObject.
100
100
  """
101
101
 
102
- def __init__(self, grabber: "Callable[[], Object]") -> None:
102
+ def __init__(self, grabber: "Callable[[], MatlabMixin | None]") -> None:
103
103
  """
104
104
  Initializes the _ParentGrabber with a grabber function.
105
105
 
@@ -109,7 +109,7 @@ class _ParentGrabber:
109
109
  self._grabber = grabber
110
110
 
111
111
  @property
112
- def parent(self) -> "Object":
112
+ def parent(self) -> "MatlabMixin | None":
113
113
  """
114
114
  Calls the grabber function and returns a MatlabObject.
115
115
 
@@ -141,13 +141,24 @@ class MatlabObject(Object):
141
141
  path_collection (PathCollection | None): The collection of paths related to the object.
142
142
  **kwargs: Arbitrary keyword arguments.
143
143
  """
144
-
145
144
  self.path_collection: "PathCollection | None" = path_collection
146
145
  lines_collection = (
147
146
  path_collection.lines_collection if path_collection is not None else None
148
147
  )
149
148
  super().__init__(*args, lines_collection=lines_collection, **kwargs)
150
149
 
150
+ @property
151
+ def namespaces(self) -> dict[str, "Namespace"]:
152
+ return {}
153
+
154
+ @property
155
+ def is_namespace(self) -> bool:
156
+ return False
157
+
158
+ @property
159
+ def is_folder(self) -> bool:
160
+ return False
161
+
151
162
  @property
152
163
  def canonical_path(self) -> str:
153
164
  """
@@ -156,7 +167,7 @@ class MatlabObject(Object):
156
167
  Returns:
157
168
  str: The canonical path of the object.
158
169
  """
159
- if isinstance(self.parent, _Root):
170
+ if self.parent is None:
160
171
  return self.name
161
172
 
162
173
  if isinstance(self.parent, MatlabObject):
@@ -165,7 +176,7 @@ class MatlabObject(Object):
165
176
  parent = getattr(self.parent, "model", self.parent)
166
177
 
167
178
  if isinstance(parent, Classfolder) and self.name == parent.name:
168
- if isinstance(parent.parent, _Root) or parent.parent is None:
179
+ if parent.parent is None:
169
180
  return self.name
170
181
  else:
171
182
  return f"{parent.parent.canonical_path}.{self.name}"
@@ -173,23 +184,6 @@ class MatlabObject(Object):
173
184
  return f"{parent.canonical_path}.{self.name}" if parent else self.name
174
185
 
175
186
 
176
- class _Root(MatlabObject):
177
- """
178
- A class representing the root object in a MATLAB structure.
179
- All the objects that have the root object as parent are at the top level,
180
- and can be called directly.
181
- """
182
-
183
- def __init__(self) -> None:
184
- super().__init__("ROOT", parent=None)
185
-
186
- def __repr__(self) -> str:
187
- return "MATLABROOT"
188
-
189
-
190
- ROOT = _Root()
191
-
192
-
193
187
  class PathMixin(Object):
194
188
  """
195
189
  A mixin class that provides a filepath attribute and related functionality.
@@ -200,7 +194,6 @@ class PathMixin(Object):
200
194
 
201
195
  def __init__(self, *args: Any, filepath: Path | None = None, **kwargs: Any) -> None:
202
196
  self._filepath: Path | None = filepath
203
-
204
197
  super().__init__(*args, **kwargs)
205
198
 
206
199
  @property
@@ -215,22 +208,22 @@ class MatlabMixin(Object):
215
208
  def __init__(
216
209
  self,
217
210
  *args: Any,
218
- parent: "Class | Classfolder | Namespace | _Root | None" = None,
211
+ parent: "Class | Classfolder | Namespace | None" = None,
219
212
  docstring: Docstring | None = None,
220
213
  **kwargs: Any,
221
214
  ):
222
- self._parent: "Class | Classfolder | Namespace | _Root | _ParentGrabber | None" = parent
215
+ self._parent: "Class | Classfolder | Namespace | _ParentGrabber | None" = parent
223
216
  self._docstring: Docstring | None = docstring
224
217
  super().__init__(*args, **kwargs)
225
218
 
226
219
  @property
227
- def parent(self) -> Object:
220
+ def parent(self) -> Object | None:
228
221
  if isinstance(self._parent, MatlabMixin):
229
222
  return self._parent
230
223
  elif isinstance(self._parent, _ParentGrabber):
231
224
  return self._parent.parent
232
225
  else:
233
- return ROOT
226
+ return None
234
227
 
235
228
  @parent.setter
236
229
  def parent(self, value):
@@ -444,6 +437,8 @@ class Property(MatlabMixin, Attribute, MatlabObject):
444
437
  self.SetAccess: AccessEnum = SetAccess
445
438
  self.getter: Function | None = None
446
439
 
440
+ self.extra["mkdocstrings"] = {"template": "property.html.jinja"}
441
+
447
442
  @property
448
443
  def Private(self) -> bool:
449
444
  private = self.Access != AccessEnum.public
@@ -559,19 +554,52 @@ class Function(MatlabMixin, PathMixin, GriffeFunction, MatlabObject):
559
554
  pass
560
555
 
561
556
 
557
+ class Folder(MatlabMixin, PathMixin, Module, MatlabObject):
558
+ """
559
+ A class representing a Folder in a MATLAB project.
560
+
561
+ Inherits from:
562
+ - MatlabMixin: A mixin class providing MATLAB-specific functionality.
563
+ - PathMixin: A mixin class providing path-related functionality.
564
+ - Module: A class representing a module.
565
+ - MatlabObject: A base class for MATLAB objects.
566
+ """
567
+
568
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
569
+ super().__init__(*args, **kwargs)
570
+ self.extra["mkdocstrings"] = {"template": "folder.html.jinja"}
571
+
572
+ def __repr__(self) -> str:
573
+ return f"Folder({self.filepath!r})"
574
+
575
+ @property
576
+ def namespaces(self) -> dict[str, "Namespace"]:
577
+ return {
578
+ name: member
579
+ for name, member in self.members.items()
580
+ if isinstance(member, Namespace)
581
+ }
582
+
583
+ @property
584
+ def is_folder(self) -> bool:
585
+ return True
586
+
587
+
562
588
  class Namespace(MatlabMixin, PathMixin, Module, MatlabObject):
563
589
  """
564
590
  A class representing a namespace in a MATLAB project.
565
591
 
566
592
  Inherits from:
593
+ - MatlabMixin: A mixin class providing MATLAB-specific functionality.
567
594
  - PathMixin: A mixin class providing path-related functionality.
568
- - MatlabObject: A base class for MATLAB objects.
569
595
  - Module: A class representing a module.
596
+ - MatlabObject: A base class for MATLAB objects.
570
597
  """
571
598
 
572
599
  def __init__(self, *args: Any, **kwargs: Any) -> None:
573
600
  super().__init__(*args, **kwargs)
574
601
  self._access: AccessEnum = AccessEnum.public
602
+ self.extra["mkdocstrings"] = {"template": "namespace.html.jinja"}
575
603
 
576
604
  def __repr__(self) -> str:
577
605
  return f"Namespace({self.path!r})"
@@ -583,3 +611,7 @@ class Namespace(MatlabMixin, PathMixin, Module, MatlabObject):
583
611
  if self.filepath
584
612
  else False
585
613
  )
614
+
615
+ @property
616
+ def is_namespace(self) -> bool:
617
+ return True
@@ -0,0 +1,172 @@
1
+ {#- Template for members (children) of an object.
2
+
3
+ This template iterates on members of a given object and renders them.
4
+ It can group members by category (attributes, classes, functions, modules) or render them in a flat list.
5
+
6
+ Context:
7
+ obj (griffe.Object): The object to render.
8
+ config (dict): The configuration options.
9
+ root_members (bool): Whether the object is the root object.
10
+ heading_level (int): The HTML heading level to use.
11
+ -#}
12
+
13
+ {% if obj.all_members %}
14
+ {% block logs scoped %}
15
+ {#- Logging block.
16
+
17
+ This block can be used to log debug messages, deprecation messages, warnings, etc.
18
+ -#}
19
+ {{ log.debug("Rendering children of " + obj.path) }}
20
+ {% endblock logs %}
21
+
22
+ <div class="doc doc-children">
23
+
24
+ {% if root_members %}
25
+ {% set members_list = config.members %}
26
+ {% else %}
27
+ {% set members_list = none %}
28
+ {% endif %}
29
+
30
+ {% if config.group_by_category %}
31
+
32
+ {% with %}
33
+
34
+ {% if config.show_category_heading %}
35
+ {% set extra_level = 1 %}
36
+ {% else %}
37
+ {% set extra_level = 0 %}
38
+ {% endif %}
39
+
40
+ {% with attributes = obj.attributes|filter_objects(
41
+ filters=config.filters,
42
+ members_list=members_list,
43
+ inherited_members=config.inherited_members,
44
+ keep_no_docstrings=config.show_if_no_docstring,
45
+ ) %}
46
+ {% if attributes %}
47
+ {% if config.show_category_heading %}
48
+ {% filter heading(heading_level, id=html_id ~ "-properties") %}Properties{% endfilter %}
49
+ {% endif %}
50
+ {% with heading_level = heading_level + extra_level %}
51
+ {% for attribute in attributes|order_members(config.members_order, members_list) %}
52
+ {% if members_list is not none or (not attribute.is_imported or attribute.is_public) %}
53
+ {% include attribute|get_template with context %}
54
+ {% endif %}
55
+ {% endfor %}
56
+ {% endwith %}
57
+ {% endif %}
58
+ {% endwith %}
59
+
60
+ {% with classes = obj.classes|filter_objects(
61
+ filters=config.filters,
62
+ members_list=members_list,
63
+ inherited_members=config.inherited_members,
64
+ keep_no_docstrings=config.show_if_no_docstring,
65
+ ) %}
66
+ {% if classes %}
67
+ {% if config.show_category_heading %}
68
+ {% filter heading(heading_level, id=html_id ~ "-classes") %}Classes{% endfilter %}
69
+ {% endif %}
70
+ {% with heading_level = heading_level + extra_level %}
71
+ {% for class in classes|order_members(config.members_order, members_list) %}
72
+ {% if members_list is not none or (not class.is_imported or class.is_public) %}
73
+ {% include class|get_template with context %}
74
+ {% endif %}
75
+ {% endfor %}
76
+ {% endwith %}
77
+ {% endif %}
78
+ {% endwith %}
79
+
80
+ {% with functions = obj.functions|filter_objects(
81
+ filters=config.filters,
82
+ members_list=members_list,
83
+ inherited_members=config.inherited_members,
84
+ keep_no_docstrings=config.show_if_no_docstring,
85
+ ) %}
86
+ {% if functions %}
87
+ {% if config.show_category_heading %}
88
+ {% filter heading(heading_level, id=html_id ~ "-functions") %}Functions{% endfilter %}
89
+ {% endif %}
90
+ {% with heading_level = heading_level + extra_level %}
91
+ {% for function in functions|order_members(config.members_order, members_list) %}
92
+ {% if not (obj.kind.value == "class" and function.name == "__init__" and config.merge_init_into_class) %}
93
+ {% if members_list is not none or (not function.is_imported or function.is_public) %}
94
+ {% include function|get_template with context %}
95
+ {% endif %}
96
+ {% endif %}
97
+ {% endfor %}
98
+ {% endwith %}
99
+ {% endif %}
100
+ {% endwith %}
101
+
102
+ {% if config.show_submodules or obj.is_folder %}
103
+ {% with modules = obj.modules|filter_objects(
104
+ filters=config.filters,
105
+ members_list=members_list,
106
+ inherited_members=config.inherited_members,
107
+ keep_no_docstrings=config.show_if_no_docstring,
108
+ ) %}
109
+ {% if modules %}
110
+ {% if config.show_category_heading %}
111
+ {% filter heading(heading_level, id=html_id ~ "-namespaces") %}Modules{% endfilter %}
112
+ {% endif %}
113
+ {% with heading_level = heading_level + extra_level %}
114
+ {% for module in modules|order_members(config.members_order.alphabetical, members_list) %}
115
+ {% if members_list is not none or (not module.is_alias or module.is_public) %}
116
+ {% include module|get_template with context %}
117
+ {% endif %}
118
+ {% endfor %}
119
+ {% endwith %}
120
+ {% endif %}
121
+ {% endwith %}
122
+ {% endif %}
123
+
124
+ {% endwith %}
125
+
126
+ {% else %}
127
+
128
+ {% for child in obj.all_members
129
+ |filter_objects(
130
+ filters=config.filters,
131
+ members_list=members_list,
132
+ inherited_members=config.inherited_members,
133
+ keep_no_docstrings=config.show_if_no_docstring,
134
+ )
135
+ |order_members(config.members_order, members_list)
136
+ %}
137
+
138
+ {% if not (obj.is_class and child.name == "__init__" and config.merge_init_into_class) %}
139
+
140
+ {% if members_list is not none or child.is_public %}
141
+ {% if child.is_attribute %}
142
+ {% with attribute = child %}
143
+ {% include attribute|get_template with context %}
144
+ {% endwith %}
145
+
146
+ {% elif child.is_class %}
147
+ {% with class = child %}
148
+ {% include class|get_template with context %}
149
+ {% endwith %}
150
+
151
+ {% elif child.is_function %}
152
+ {% with function = child %}
153
+ {% include function|get_template with context %}
154
+ {% endwith %}
155
+
156
+ {% elif (child.is_namespace and config.show_submodules) or obj.is_folder %}
157
+ {% with module = child %}
158
+ {% include module|get_template with context %}
159
+ {% endwith %}
160
+
161
+ {% endif %}
162
+ {% endif %}
163
+
164
+ {% endif %}
165
+
166
+ {% endfor %}
167
+
168
+ {% endif %}
169
+
170
+ </div>
171
+
172
+ {% endif %}