mkdocstrings-matlab 0.1.0__tar.gz

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.
Files changed (29) hide show
  1. mkdocstrings_matlab-0.1.0/.gitignore +196 -0
  2. mkdocstrings_matlab-0.1.0/LICENSE +21 -0
  3. mkdocstrings_matlab-0.1.0/PKG-INFO +17 -0
  4. mkdocstrings_matlab-0.1.0/README.md +3 -0
  5. mkdocstrings_matlab-0.1.0/debug.py +17 -0
  6. mkdocstrings_matlab-0.1.0/docs/index.md +25 -0
  7. mkdocstrings_matlab-0.1.0/mkdocs.yml +28 -0
  8. mkdocstrings_matlab-0.1.0/pyproject.toml +30 -0
  9. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/__init__.py +5 -0
  10. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/handler.py +383 -0
  11. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+case/builtin.m +8 -0
  12. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+case/class.m +12 -0
  13. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+case/func.m +5 -0
  14. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+case/method.m +6 -0
  15. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+case/namespace.m +28 -0
  16. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+metadata/argument.m +58 -0
  17. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+metadata/class.m +44 -0
  18. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+metadata/func.m +14 -0
  19. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+metadata/namespace.m +14 -0
  20. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+metadata/property.m +41 -0
  21. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+metadata/script.m +15 -0
  22. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+utils/dedent.m +34 -0
  23. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+utils/get_namespace_path.m +26 -0
  24. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/+utils/parse_doc.m +21 -0
  25. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/exception.m +7 -0
  26. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/+docstring/resolve.m +94 -0
  27. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/matlab/matlab_startup.m +21 -0
  28. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/models.py +127 -0
  29. mkdocstrings_matlab-0.1.0/src/mkdocstrings_handlers/matlab/py.typed +0 -0
@@ -0,0 +1,196 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
110
+ .pdm.toml
111
+ .pdm-python
112
+ .pdm-build/
113
+
114
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
115
+ __pypackages__/
116
+
117
+ # Celery stuff
118
+ celerybeat-schedule
119
+ celerybeat.pid
120
+
121
+ # SageMath parsed files
122
+ *.sage.py
123
+
124
+ # Environments
125
+ .env
126
+ .venv
127
+ env/
128
+ venv/
129
+ ENV/
130
+ env.bak/
131
+ venv.bak/
132
+
133
+ # Spyder project settings
134
+ .spyderproject
135
+ .spyproject
136
+
137
+ # Rope project settings
138
+ .ropeproject
139
+
140
+ # mkdocs documentation
141
+ /site
142
+
143
+ # mypy
144
+ .mypy_cache/
145
+ .dmypy.json
146
+ dmypy.json
147
+
148
+ # Pyre type checker
149
+ .pyre/
150
+
151
+ # pytype static type analyzer
152
+ .pytype/
153
+
154
+ # Cython debug symbols
155
+ cython_debug/
156
+
157
+ # PyCharm
158
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
159
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
160
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
161
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
162
+ #.idea/
163
+
164
+
165
+ # Windows default autosave extension
166
+ *.asv
167
+
168
+ # OSX / *nix default autosave extension
169
+ *.m~
170
+
171
+ # Compiled MEX binaries (all platforms)
172
+ *.mex*
173
+
174
+ # Packaged app and toolbox files
175
+ *.mlappinstall
176
+ *.mltbx
177
+
178
+ # Generated helpsearch folders
179
+ helpsearch*/
180
+
181
+ # Simulink code generation folders
182
+ slprj/
183
+ sccprj/
184
+
185
+ # Matlab code generation folders
186
+ codegen/
187
+
188
+ # Simulink autosave extension
189
+ *.autosave
190
+
191
+ # Simulink cache files
192
+ *.slxc
193
+
194
+ # Octave session info
195
+ octave-workspace
196
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Mark Shui Hu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.3
2
+ Name: mkdocstrings-matlab
3
+ Version: 0.1.0
4
+ Summary: Add your description here
5
+ Author-email: Mark Hu <mark.hu@asml.com>
6
+ License-File: LICENSE
7
+ Requires-Dist: griffe>=1.2.0
8
+ Requires-Dist: markdown>=3.7
9
+ Requires-Dist: mkdocs-material>=9.5.33
10
+ Requires-Dist: mkdocs>=1.6.0
11
+ Requires-Dist: mkdocstrings>=0.25.2
12
+ Requires-Dist: mkdocstrings[python]>=0.18
13
+ Description-Content-Type: text/markdown
14
+
15
+ # mkdocstrings-matlab
16
+
17
+ Describe your project here.
@@ -0,0 +1,3 @@
1
+ # mkdocstrings-matlab
2
+
3
+ Describe your project here.
@@ -0,0 +1,17 @@
1
+ from mkdocs.commands import serve
2
+ from pathlib import Path
3
+
4
+ config_file = str(Path(__file__).parent / "mkdocs.yml")
5
+
6
+ kwargs = {
7
+ "dev_addr": None,
8
+ "open_in_browser": False,
9
+ "livereload": True,
10
+ "build_type": None,
11
+ "watch_theme": True,
12
+ "config_file": config_file,
13
+ "strict": None,
14
+ "theme": None,
15
+ "use_directory_urls": None,
16
+ }
17
+ serve.serve(**kwargs)
@@ -0,0 +1,25 @@
1
+
2
+ # Docs
3
+
4
+ <!-- ::: matlab_startupP455W0rd
5
+
6
+ handler: matlab -->
7
+
8
+ <!-- ::: docstring.resolve
9
+ handler: matlab -->
10
+
11
+ <!-- ::: mkdocstrings_handlers.matlab.handler.MatlabHandler
12
+ handler: python
13
+ options:
14
+ show_source: false
15
+ members:
16
+ - collect -->
17
+
18
+ ::: ghtest.testrunner
19
+ handler: matlab
20
+ options:
21
+ members:
22
+ - run
23
+ - get_suite
24
+ - get_runner
25
+
@@ -0,0 +1,28 @@
1
+ site_name: "mkdocstrings-matlab"
2
+ repo_name: "watermarkhu/mkdocstrings-matlab"
3
+ site_dir: "site"
4
+
5
+ nav:
6
+ - Home: index.md
7
+
8
+ theme:
9
+ name: material
10
+
11
+ watch:
12
+ - src
13
+
14
+ plugins:
15
+ - search
16
+ - autorefs
17
+ - mkdocstrings:
18
+ default_handler: python
19
+ handlers:
20
+ # python:
21
+ # paths: ["src"]
22
+ # options:
23
+ # show_root_heading: true
24
+ # show_docstring_attributes: false
25
+ matlab:
26
+ paths: ["/home/mahu/repositories/github-matlab-test-action/src"]
27
+ options:
28
+ show_root_heading: true
@@ -0,0 +1,30 @@
1
+ [project]
2
+ name = "mkdocstrings-matlab"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ authors = [
6
+ { name = "Mark Hu", email = "mark.hu@asml.com" }
7
+ ]
8
+ dependencies = [
9
+ "mkdocs>=1.6.0",
10
+ "mkdocstrings>=0.25.2",
11
+ "mkdocstrings[python]>=0.18",
12
+ "griffe>=1.2.0",
13
+ "mkdocs-material>=9.5.33",
14
+ "markdown>=3.7",
15
+ ]
16
+ readme = "README.md"
17
+
18
+ [build-system]
19
+ requires = ["hatchling"]
20
+ build-backend = "hatchling.build"
21
+
22
+ [tool.rye]
23
+ managed = true
24
+ dev-dependencies = []
25
+
26
+ [tool.hatch.metadata]
27
+ allow-direct-references = true
28
+
29
+ [tool.hatch.build.targets.wheel]
30
+ packages = ["src/mkdocstrings_handlers"]
@@ -0,0 +1,5 @@
1
+ """MATLAB handler for mkdocstrings."""
2
+
3
+ from mkdocstrings_handlers.matlab.handler import get_handler
4
+
5
+ __all__ = ["get_handler"]
@@ -0,0 +1,383 @@
1
+ from pathlib import Path
2
+ from collections import ChainMap
3
+ from markdown import Markdown
4
+ from mkdocstrings.handlers.base import BaseHandler, CollectorItem, CollectionError
5
+ from mkdocstrings_handlers.python import rendering
6
+ from typing import Any, ClassVar, Mapping
7
+ from griffe import Docstring, Parameters, Parameter, ParameterKind
8
+ from pprint import pprint
9
+
10
+
11
+ import json
12
+
13
+
14
+ from mkdocstrings_handlers.matlab_engine import MatlabEngine, MatlabExecutionError
15
+ from mkdocstrings_handlers.matlab.models import Function, Class, Classfolder, Namespace, Property
16
+
17
+
18
+ ROOT_NAMESPACE = Namespace("", filepath="")
19
+ MODELS = {}
20
+
21
+
22
+ class MatlabHandler(BaseHandler):
23
+ """The `MatlabHandler` class is a handler for processing Matlab code documentation.
24
+
25
+ Attributes:
26
+ name (str): The handler's name.
27
+ domain (str): The cross-documentation domain/language for this handler.
28
+ enable_inventory (bool): Whether this handler is interested in enabling the creation of the `objects.inv` Sphinx inventory file.
29
+ fallback_theme (str): The fallback theme.
30
+ fallback_config (ClassVar[dict]): The configuration used to collect item during autorefs fallback.
31
+ default_config (ClassVar[dict]): The default configuration for the handler.
32
+
33
+ Methods:
34
+ __init__(self, *args, config_file_path=None, paths=None, startup_expression="", locale="en", **kwargs): Initializes a new instance of the `MatlabHandler` class.
35
+ get_templates_dir(self, handler=None): Returns the templates directory for the handler.
36
+ collect(self, identifier, config): Collects the documentation for the given identifier.
37
+ render(self, data, config): Renders the collected documentation data.
38
+ update_env(self, md, config): Updates the Jinja environment with custom filters and tests.
39
+ """
40
+
41
+ name: str = "matlab"
42
+ """The handler's name."""
43
+ domain: str = "mat" # to match Sphinx's default domain
44
+ """The cross-documentation domain/language for this handler."""
45
+ enable_inventory: bool = True
46
+ """Whether this handler is interested in enabling the creation of the `objects.inv` Sphinx inventory file."""
47
+ fallback_theme = "material"
48
+ """The fallback theme."""
49
+ fallback_config: ClassVar[dict] = {"fallback": True}
50
+ """The configuration used to collect item during autorefs fallback."""
51
+ default_config: ClassVar[dict] = {
52
+ # https://mkdocstrings.github.io/python/usage/
53
+ # General options
54
+ # "find_stubs_package": False,
55
+ # "allow_inspection": True,
56
+ "show_bases": True,
57
+ "show_inheritance_diagram": False, # not implemented
58
+ "show_source": False, # not implemented
59
+ # "preload_modules": None,
60
+ # Heading options
61
+ "heading_level": 2,
62
+ "parameter_headings": False,
63
+ "show_root_heading": False,
64
+ "show_root_toc_entry": True,
65
+ "show_root_full_path": True,
66
+ "show_root_members_full_path": False,
67
+ "show_object_full_path": False,
68
+ "show_category_heading": False,
69
+ "show_symbol_type_heading": False,
70
+ "show_symbol_type_toc": False,
71
+ # Member options
72
+ "inherited_members": False,
73
+ "members": None,
74
+ "members_order": rendering.Order.alphabetical.value,
75
+ "filters": ["!^_[^_]"],
76
+ "group_by_category": True,
77
+ "show_submodules": False,
78
+ "summary": False,
79
+ "show_labels": True,
80
+ # Docstring options
81
+ "docstring_style": "google",
82
+ "docstring_options": {},
83
+ "docstring_section_style": "table",
84
+ "merge_init_into_class": False,
85
+ "show_if_no_docstring": False,
86
+ "show_docstring_attributes": True,
87
+ "show_docstring_functions": True,
88
+ "show_docstring_classes": True,
89
+ "show_docstring_modules": True,
90
+ "show_docstring_description": True,
91
+ "show_docstring_examples": True,
92
+ "show_docstring_other_parameters": True,
93
+ "show_docstring_parameters": True,
94
+ "show_docstring_raises": True,
95
+ "show_docstring_receives": True,
96
+ "show_docstring_returns": True,
97
+ "show_docstring_warns": True,
98
+ "show_docstring_yields": True,
99
+ # Signature options
100
+ "annotations_path": "brief",
101
+ "line_length": 60,
102
+ "show_signature": True,
103
+ "show_signature_annotations": False,
104
+ "signature_crossrefs": False,
105
+ "separate_signature": True,
106
+ "unwrap_annotated": False,
107
+ "modernize_annotations": False,
108
+ }
109
+
110
+ def __init__(
111
+ self,
112
+ *args: Any,
113
+ config_file_path: str | None = None,
114
+ paths: list[str] | None = None,
115
+ startup_expression: str = "",
116
+ locale: str = "en",
117
+ **kwargs: Any,
118
+ ) -> None:
119
+ super().__init__(*args, **kwargs)
120
+
121
+ if paths is None:
122
+ paths = ""
123
+
124
+ self.engine = MatlabEngine()
125
+ self.engine.addpath(str(Path(__file__).parent / "matlab"))
126
+ self.engine.matlab_startup(paths, startup_expression)
127
+ self._locale = locale
128
+
129
+ def get_templates_dir(self, handler: str | None = None) -> Path:
130
+ # use the python handler templates
131
+ # (it assumes the python handler is installed)
132
+ return super().get_templates_dir("python")
133
+
134
+ def collect(self, identifier: str, config: Mapping[str, Any]) -> CollectorItem:
135
+ """Collect data given an identifier and user configuration.
136
+
137
+ In the implementation, you typically call a subprocess that returns JSON, and load that JSON again into
138
+ a Python dictionary for example, though the implementation is completely free.
139
+
140
+ Arguments:
141
+ identifier: An identifier for which to collect data.
142
+ config: The handler's configuration options.
143
+
144
+ Returns:
145
+ CollectorItem
146
+ """
147
+ final_config = ChainMap(config, self.default_config) # type: ignore[arg-type]
148
+ try:
149
+ ast_json = self.engine.docstring.resolve(identifier)
150
+ except MatlabExecutionError as error:
151
+ raise CollectionError(error.args[0].strip()) from error
152
+ ast_dict = json.loads(ast_json)
153
+
154
+ match ast_dict["type"]:
155
+ case "function":
156
+ return collect_function(ast_dict, final_config)
157
+ case "method":
158
+ return collect_function(ast_dict, final_config)
159
+ case "class":
160
+ return self.collect_class(ast_dict, final_config)
161
+ case _:
162
+ return None
163
+
164
+ def render(self, data: CollectorItem, config: Mapping[str, Any]) -> str:
165
+ """Render a template using provided data and configuration options.
166
+
167
+ Arguments:
168
+ data: The collected data to render.
169
+ config: The handler's configuration options.
170
+
171
+ Returns:
172
+ The rendered template as HTML.
173
+ """
174
+ final_config = ChainMap(config, self.default_config) # type: ignore[arg-type]
175
+
176
+ template_name = rendering.do_get_template(self.env, data)
177
+ template = self.env.get_template(template_name)
178
+
179
+ heading_level = final_config["heading_level"]
180
+
181
+ return template.render(
182
+ **{
183
+ "config": final_config,
184
+ data.kind.value: data,
185
+ "heading_level": heading_level,
186
+ "root": True,
187
+ "locale": self._locale,
188
+ },
189
+ )
190
+
191
+ def get_anchors(self, data: CollectorItem) -> tuple[str, ...]:
192
+ """Return the possible identifiers (HTML anchors) for a collected item.
193
+
194
+ Arguments:
195
+ data: The collected data.
196
+
197
+ Returns:
198
+ The HTML anchors (without '#'), or an empty tuple if this item doesn't have an anchor.
199
+ """
200
+ anchors = [data.path]
201
+ return tuple(anchors)
202
+
203
+ def update_env(self, md: Markdown, config: dict) -> None:
204
+ """Update the Jinja environment with custom filters and tests.
205
+
206
+ Parameters:
207
+ md: The Markdown instance.
208
+ config: The configuration dictionary.
209
+ """
210
+ super().update_env(md, config)
211
+ self.env.trim_blocks = True
212
+ self.env.lstrip_blocks = True
213
+ self.env.keep_trailing_newline = False
214
+ self.env.filters["split_path"] = rendering.do_split_path
215
+ self.env.filters["crossref"] = rendering.do_crossref
216
+ self.env.filters["multi_crossref"] = rendering.do_multi_crossref
217
+ self.env.filters["order_members"] = rendering.do_order_members
218
+ self.env.filters["format_code"] = rendering.do_format_code
219
+ self.env.filters["format_signature"] = rendering.do_format_signature
220
+ self.env.filters["format_attribute"] = rendering.do_format_attribute
221
+ self.env.filters["filter_objects"] = rendering.do_filter_objects
222
+ self.env.filters["stash_crossref"] = lambda ref, length: ref
223
+ self.env.filters["get_template"] = rendering.do_get_template
224
+ self.env.filters["as_attributes_section"] = rendering.do_as_attributes_section
225
+ self.env.filters["as_functions_section"] = rendering.do_as_functions_section
226
+ self.env.filters["as_classes_section"] = rendering.do_as_classes_section
227
+ self.env.filters["as_modules_section"] = rendering.do_as_modules_section
228
+ self.env.tests["existing_template"] = (
229
+ lambda template_name: template_name in self.env.list_templates()
230
+ )
231
+
232
+
233
+ def collect_class(self, ast_dict: dict, config: Mapping) -> Class:
234
+ docstring = (
235
+ Docstring(ast_dict["docstring"], parser=config["docstring_style"])
236
+ if ast_dict["docstring"]
237
+ else None
238
+ )
239
+ object = Class(
240
+ ast_dict["name"],
241
+ docstring=docstring,
242
+ parent=get_parent(Path(ast_dict["path"]).parent),
243
+ hidden=ast_dict["hidden"],
244
+ sealed=ast_dict["sealed"],
245
+ abstract=ast_dict["abstract"],
246
+ enumeration=ast_dict["enumeration"],
247
+ handle=ast_dict["handle"],
248
+ )
249
+
250
+
251
+ for property_dict in ast_dict["properties"]:
252
+ name = property_dict.pop("name")
253
+ defining_class = property_dict.pop("class")
254
+ property_doc = property_dict.pop("docstring")
255
+ docstring = (
256
+ Docstring(property_doc, parser=config["docstring_style"])
257
+ if property_doc
258
+ else None
259
+ )
260
+ if defining_class != object.canonical_path and not config["inherited_members"]:
261
+ continue
262
+
263
+ object.members[name] = Property(name, docstring=docstring, **property_dict)
264
+
265
+ for method_dict in ast_dict["methods"]:
266
+ name = method_dict.pop("name")
267
+ defining_class = method_dict.pop("class")
268
+ if defining_class != object.canonical_path and not config["inherited_members"]:
269
+ continue
270
+
271
+ method = self.collect(f"{defining_class}.{name}", config)
272
+ method._access = method_dict["access"]
273
+ method._static = method_dict["static"]
274
+ method._abstract = method_dict["abstract"]
275
+ method._sealed = method_dict["sealed"]
276
+ method._hidden = method_dict["hidden"]
277
+
278
+ object.members[name] = method
279
+
280
+ return object
281
+
282
+ def get_parent(path: Path) -> Namespace | Classfolder:
283
+ if path.stem[0] == "+":
284
+ if path in MODELS:
285
+ parent = MODELS[path]
286
+ else:
287
+ parent = Namespace(
288
+ path.stem[1:], filepath=str(path), parent=get_parent(path.parent)
289
+ )
290
+ MODELS[path] = parent
291
+ elif path.stem[0] == "@":
292
+ if path in MODELS:
293
+ parent = MODELS[path]
294
+ else:
295
+ parent = Classfolder(
296
+ path.stem[1:], filepath=str(path), parent=get_parent(path.parent)
297
+ )
298
+ MODELS[path] = parent
299
+ else:
300
+ parent = ROOT_NAMESPACE
301
+ return parent
302
+
303
+
304
+
305
+
306
+
307
+ def collect_function(ast_dict: dict, config: Mapping) -> Function:
308
+ parameters = []
309
+
310
+ inputs = (
311
+ ast_dict["inputs"]
312
+ if isinstance(ast_dict["inputs"], list)
313
+ else [ast_dict["inputs"]]
314
+ )
315
+ for input_dict in inputs:
316
+ if input_dict["name"] == "varargin":
317
+ parameter_kind = ParameterKind.var_positional
318
+ elif input_dict["kind"] == "positional":
319
+ parameter_kind = ParameterKind.positional_only
320
+ else:
321
+ parameter_kind = ParameterKind.keyword_only
322
+
323
+ parameters.append(
324
+ Parameter(
325
+ input_dict["name"],
326
+ kind=parameter_kind,
327
+ annotation=input_dict["class"],
328
+ default=input_dict["default"] if input_dict["default"] else None,
329
+ )
330
+ )
331
+
332
+ func = Function(
333
+ ast_dict["name"],
334
+ parameters=Parameters(*parameters),
335
+ docstring=Docstring(
336
+ ast_dict["docstring"],
337
+ parser=config["docstring_style"],
338
+ parser_options=config["docstring_options"],
339
+ )
340
+ if ast_dict["docstring"]
341
+ else None,
342
+ parent=get_parent(Path(ast_dict["path"]).parent),
343
+ )
344
+
345
+ return func
346
+
347
+
348
+ def get_handler(
349
+ *,
350
+ theme: str,
351
+ custom_templates: str | None = None,
352
+ config_file_path: str | None = None,
353
+ paths: list[str] | None = None,
354
+ startup_expression: str = "",
355
+ **config: Any,
356
+ ) -> MatlabHandler:
357
+ """
358
+ Returns a MatlabHandler object.
359
+
360
+ Parameters:
361
+ theme (str): The theme to use.
362
+ custom_templates (str | None, optional): Path to custom templates. Defaults to None.
363
+ config_file_path (str | None, optional): Path to configuration file. Defaults to None.
364
+ paths (list[str] | None, optional): List of paths to include. Defaults to None.
365
+ startup_expression (str, optional): Startup expression. Defaults to "".
366
+ **config (Any): Additional configuration options.
367
+
368
+ Returns:
369
+ MatlabHandler: The created MatlabHandler object.
370
+ """
371
+ return MatlabHandler(
372
+ handler="matlab",
373
+ theme=theme,
374
+ custom_templates=custom_templates,
375
+ config_file_path=config_file_path,
376
+ paths=paths,
377
+ startup_expression=startup_expression,
378
+ )
379
+
380
+
381
+ if __name__ == "__main__":
382
+ handler = get_handler(theme="material")
383
+ pprint(handler.collect("matlab_startup", {}).docstring.parse("google"))
@@ -0,0 +1,8 @@
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
@@ -0,0 +1,12 @@
1
+ function data = class(identifier)
2
+
3
+ if isMATLABReleaseOlderThan('R2024a')
4
+ metaclass = @meta.class.fromName;
5
+ else
6
+ metaclass = @matlab.metadata.Class.fromName;
7
+ end
8
+
9
+ object = metaclass(identifier);
10
+ data = docstring.metadata.class(object);
11
+
12
+ end
@@ -0,0 +1,5 @@
1
+ function data = func(identifier)
2
+
3
+ object = matlab.internal.metafunction(identifier);
4
+ data = docstring.metadata.func(object);
5
+ end
@@ -0,0 +1,6 @@
1
+ function data = method(identifier)
2
+
3
+ object = matlab.internal.metafunction(identifier);
4
+ data = docstring.metadata.func(object);
5
+ data.type = 'method';
6
+ end
@@ -0,0 +1,28 @@
1
+ function data = namespace(identifier)
2
+
3
+ currentpath = split(pwd, filesep);
4
+
5
+ name = identifier(2:end);
6
+
7
+ if isfolder(identifier)
8
+ for i = numel(currentpath):-1:1
9
+ directory = currentpath(i);
10
+ if isempty(directory)
11
+ break
12
+ elseif strcmp(directory(1), '+')
13
+ name = sprintf("%s.%s", directory(2:end), name);
14
+ else
15
+ break
16
+ end
17
+ end
18
+ end
19
+
20
+ object = matlab.metadata.Namespace.fromName(name);
21
+
22
+ if isempty(object)
23
+ docstring.exception(identifier)
24
+ end
25
+
26
+ data = docstring.metadata.namespace(object);
27
+ data.name = name;
28
+ end
@@ -0,0 +1,58 @@
1
+ function data = argument(object)
2
+ arguments
3
+ object (1,:) matlab.internal.metadata.Argument
4
+ end
5
+
6
+ if isempty(object)
7
+ data = struct.empty();
8
+ return
9
+ elseif numel(object) > 1
10
+ for iArg = numel(object):-1:1
11
+ data(iArg) = docstring.metadata.argument(object(iArg));
12
+ end
13
+ return
14
+ end
15
+
16
+ data.name = object.Name;
17
+ data.kind = string(object.Kind);
18
+ data.presence = string(object.Presence);
19
+
20
+ if isempty(object.DefaultValue)
21
+ data.default = "";
22
+ elseif object.DefaultValue.IsConstant
23
+ data.default = string(object.DefaultValue.Value);
24
+ else
25
+ data.default = "*expression*";
26
+ end
27
+
28
+ if ~isempty(object.Validation)
29
+ if ~isempty(object.Validation.Class)
30
+ data.class = string(object.Validation.Class.Name);
31
+ else
32
+ data.class = "";
33
+ end
34
+ if ~isempty(object.Validation.Size)
35
+ for iSize = numel(object.Validation.Size):-1:1
36
+
37
+ if isprop(object.Validation.Size(iSize), 'Length')
38
+ data.size(iSize) = object.Validation.Size(iSize).Length;
39
+ else
40
+ data.size(iSize) = ":";
41
+ end
42
+ end
43
+ else
44
+ data.size = "";
45
+ end
46
+
47
+ if ~isempty(object.Validation.Functions)
48
+ data.validators = arrayfun(@(f) string(f.Name), object.Validation.Functions);
49
+ else
50
+ data.validators = "";
51
+ end
52
+ else
53
+ data.class = "";
54
+ data.size = "";
55
+ data.validators = "";
56
+ end
57
+
58
+ end
@@ -0,0 +1,44 @@
1
+ function data = class(object)
2
+ arguments
3
+ object (1,1) matlab.metadata.Class
4
+ end
5
+ data.type = 'class';
6
+
7
+ namespaces = split(object.Name, '.');
8
+ data.name = namespaces{end};
9
+
10
+ data.docstring = docstring.utils.parse_doc(object, true);
11
+ data.path = matlab.internal.metafunction(object.Name).Location;
12
+ data.hidden = object.Hidden;
13
+ data.sealed = object.Sealed;
14
+ data.abstract = object.Abstract;
15
+ data.enumeration = object.Enumeration;
16
+ data.superclasses = arrayfun(@(o) string(o.Name), object.SuperclassList);
17
+ data.handle = object.HandleCompatible;
18
+ data.aliases = object.Aliases;
19
+
20
+ data.methods = [];
21
+ for methodObject = object.MethodList'
22
+ if any(strcmp(methodObject.Name, {'empty', 'forInteractiveUse'}))
23
+ break
24
+ else
25
+ method.name = string(methodObject.Name);
26
+ method.class = string(methodObject.DefiningClass.Name);
27
+ method.access = methodObject.Access;
28
+ method.static = methodObject.Static;
29
+ method.abstract = methodObject.Abstract;
30
+ method.sealed = methodObject.Sealed;
31
+ method.hidden = methodObject.Hidden;
32
+ data.methods = [data.methods, method];
33
+ end
34
+ end
35
+
36
+ numProp = numel(object.PropertyList);
37
+ for iProp = numProp:-1:1
38
+ data.properties(iProp) = docstring.metadata.property(object.PropertyList(iProp));
39
+ end
40
+
41
+ nameparts = split(object.Name, '.');
42
+ data.constructor = any(strcmp(nameparts(end), [data.methods.name]));
43
+
44
+ end
@@ -0,0 +1,14 @@
1
+ function data = func(object)
2
+
3
+ arguments
4
+ object (1,1) matlab.metadata.MetaData
5
+ end
6
+
7
+ data.type = 'function';
8
+ data.name = object.Name;
9
+ data.docstring = docstring.utils.parse_doc(object);
10
+ data.path = object.Location;
11
+
12
+ data.inputs = docstring.metadata.argument(object.Signature.Inputs);
13
+ data.outputs = docstring.metadata.argument(object.Signature.Outputs);
14
+ end
@@ -0,0 +1,14 @@
1
+ function data = namespace(object)
2
+
3
+ arguments
4
+ object (1,1) matlab.metadata.Namespace
5
+ end
6
+
7
+ data.type = 'namespace';
8
+ data.docstring = docstring.utils.parse_doc(object);
9
+
10
+ data.classes = arrayfun(@(o) string(o.Name), object.ClassList);
11
+ data.functions = arrayfun(@(o) string(o.Name), object.FunctionList);
12
+ data.namespaces = arrayfun(@(o) string(o.Name), object.InnerNamespaces);
13
+ data.path = docstring.utils.get_namespace_path(object);
14
+ end
@@ -0,0 +1,41 @@
1
+ function data = argument(object)
2
+ arguments
3
+ object (1,:) meta.property
4
+ end
5
+
6
+ data.name = string(object.Name);
7
+ data.class = string(object.DefiningClass.Name);
8
+ data.docstring = docstring.utils.parse_doc(object);
9
+ data.get_access = object.GetAccess;
10
+ data.set_access = object.SetAccess;
11
+ data.dependent = object.Dependent;
12
+ data.constant = object.Constant;
13
+ data.abstract = object.Abstract;
14
+ data.transient = object.Transient;
15
+ data.hidden = object.Hidden;
16
+
17
+ if ~isempty(object.Validation) && ~isempty(object.Validation.Class)
18
+ data.annotation = string(object.Validation.Class.Name);
19
+ else
20
+ data.annotation = "";
21
+ end
22
+
23
+ if ~isempty(object.Validation) && ~isempty(object.Validation.Size)
24
+ for iSize = numel(object.Validation.Size):-1:1
25
+ if isprop(object.Validation.Size(iSize), 'Length')
26
+ sizeStr(iSize) = string(object.Validation.Size(iSize).Length);
27
+ else
28
+ sizeStr(iSize) = ":";
29
+ end
30
+ end
31
+ data.size = sprintf("[%s]", join(sizeStr, ","));
32
+ else
33
+ data.size = "";
34
+ end
35
+
36
+ if ~isempty(object.Validation) && ~isempty(object.Validation.ValidatorFunctions)
37
+ data.validation = join(cellfun(@(f) string(char(f)), object.Validation.ValidatorFunctions), ", ");
38
+ else
39
+ data.validation = "";
40
+ end
41
+ end
@@ -0,0 +1,15 @@
1
+ function data = script(object)
2
+ %SCRIPT Summary of this function goes here
3
+ % Detailed explanation goes here
4
+
5
+ arguments
6
+ object (1,1) matlab.metadata.MetaData
7
+ end
8
+
9
+ data.type = 'script';
10
+ data.Name = object.Name;
11
+ data.docstring = docstring.utils.parse_doc(object);
12
+ data.path = object.Location;
13
+
14
+ end
15
+
@@ -0,0 +1,34 @@
1
+ function parsedDoc = dedent(doc)
2
+ %DEDENT Summary of this function goes here
3
+ % Detailed explanation goes here
4
+ arguments
5
+ doc (1,1) string
6
+ end
7
+
8
+ lines = cellstr(splitlines(doc));
9
+
10
+
11
+ for iLine = numel(lines):-1:1
12
+ line = lines{iLine};
13
+ if ~isempty(line) && ~all(line == ' ')
14
+ indentations(iLine) = find(line~= ' ', 1);
15
+ else
16
+ indentations(iLine) = inf;
17
+ end
18
+ end
19
+
20
+ indentation = min(indentations);
21
+
22
+ for iLine = 1:numel(lines)
23
+ line = lines{iLine};
24
+ if isempty(line) || numel(line) <= indentation
25
+ lines{iLine} = '';
26
+ else
27
+ lines{iLine} = line(indentation:end);
28
+ end
29
+ end
30
+
31
+ parsedDoc = string(strjoin(lines, '\n'));
32
+
33
+ end
34
+
@@ -0,0 +1,26 @@
1
+ function path = get_namespace_path(object, parents)
2
+
3
+ arguments
4
+ object (1,1) matlab.metadata.Namespace
5
+ parents (1,1) double {mustBeInteger, mustBeNonnegative} = 0
6
+ end
7
+
8
+ if ~isempty(object.ClassList)
9
+
10
+ function_path = which(sprintf("%s.%s", object.Name, object.ClassList(1).Name));
11
+ path = fileparts(function_path);
12
+ elseif ~isempty(object.FunctionList)
13
+
14
+ function_path = which(sprintf("%s.%s", object.Name, object.FunctionList(1).Name));
15
+ path = fileparts(function_path);
16
+ elseif ~isempty(object.InnerNamespaces)
17
+ path = docstring.utils.get_namespace_path(...
18
+ object.InnerNamespaces(1), parents + 1);
19
+ else
20
+ error("Cannot get path of namespace %s", object.Name);
21
+ end
22
+
23
+ for i = 1:parents
24
+ path = fileparts(path);
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ function doc = parse_doc(object, combine)
2
+
3
+ arguments
4
+ object (1,1) matlab.metadata.MetaData
5
+ combine (1,1) logical = false
6
+ end
7
+
8
+ if isempty(object.DetailedDescription)
9
+ doc = object.Description;
10
+ else
11
+ if combine
12
+ doc = sprintf("%s\n%s", object.Description, ...
13
+ docstring.utils.dedent(object.DetailedDescription));
14
+ else
15
+ doc = docstring.utils.dedent(object.DetailedDescription);
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+
@@ -0,0 +1,7 @@
1
+ function exception(identifier)
2
+
3
+ notFoundException = MException('mkdocs:callerInput', '%s %s %s', ...
4
+ 'The input', identifier, 'could not be found on the MATLAB path');
5
+ throwAsCaller(notFoundException)
6
+
7
+ end
@@ -0,0 +1,94 @@
1
+ function [jsonString, data] = resolve(identifier, cwd)
2
+ % Resolve the docstring for a given MATLAB entity
3
+ %
4
+ % ```matlab
5
+ % jsonString = resolve(name, cwd)
6
+ % ```
7
+ %
8
+ % Parameters:
9
+ % identifier (string): Name of the MATLAB entity
10
+ % cwd (string): Current working directory
11
+ %
12
+ % Returns:
13
+ % jsonString(string): JSON-encoded metadata object
14
+ % data(struct): metadata object
15
+
16
+ arguments
17
+ identifier (1, :) char
18
+ cwd (1,1) string {mustBeFolder} = pwd()
19
+ end
20
+
21
+ cd(cwd);
22
+
23
+ % Check if namespace
24
+ if strcmp(identifier(1), '+')
25
+ data = docstring.case.namespace(identifier);
26
+ jsonString = jsonencode(data);
27
+ return;
28
+ end
29
+
30
+ % Try namespace functions
31
+ if contains(identifier, '.')
32
+ object = matlab.internal.metafunction(identifier);
33
+ if ~isempty(object) && isa(object, 'matlab.internal.metadata.Function')
34
+ if isempty(object.Signature)
35
+ data = docstring.metadata.script(object);
36
+ else
37
+ data = docstring.metadata.func(object);
38
+ end
39
+ jsonString = jsonencode(data);
40
+ return;
41
+ end
42
+ end
43
+
44
+ % Try built-in aliases with which
45
+ if contains(which(identifier), ' built-in ')
46
+ data = docstring.case.builtin(identifier);
47
+ jsonString = jsonencode(data);
48
+ return
49
+ end
50
+
51
+ switch exist(identifier) %#ok<EXIST>
52
+ case 2
53
+ % if NAME is a file with extension .m, .mlx, .mlapp, or .sfx, or NAME
54
+ % is the name of a file with a non-registered file extension
55
+ % (.mat, .fig, .txt).
56
+
57
+ % Try with metafunction
58
+ object = matlab.internal.metafunction(identifier);
59
+ if ~isempty(object) && isa(object, 'matlab.internal.metadata.Function')
60
+ if isempty(object.Signature)
61
+ data = docstring.metadata.script(object);
62
+ else
63
+ data = docstring.metadata.func(object);
64
+ end
65
+ data.name = identifier;
66
+ else
67
+ docstring.exception(identifier);
68
+ end
69
+ case 5
70
+ % if NAME is a built-in MATLAB function. This does not include classes
71
+ data = docstring.case.builtin(identifier);
72
+ case 8
73
+ % if NAME is a class (exist returns 0 for Java classes if you
74
+ % start MATLAB with the -nojvm option.)
75
+ data = docstring.case.class(identifier);
76
+ case 0
77
+ if contains(identifier, '.')
78
+ nameparts = split(identifier, '.');
79
+ tryclassname = strjoin(nameparts(1:end-1), '.');
80
+ if exist(tryclassname, 'class')
81
+ data = docstring.case.method(identifier);
82
+ else
83
+ docstring.exception(identifier);
84
+ end
85
+ else
86
+ docstring.exception(identifier);
87
+ end
88
+ otherwise
89
+ docstring.exception(identifier);
90
+ end
91
+
92
+ jsonString = jsonencode(data);
93
+
94
+ end
@@ -0,0 +1,21 @@
1
+ function result = matlab_startup(paths, expression)
2
+ % Add paths and evaluate an expression
3
+ %
4
+ % Parameters:
5
+ % paths (string): Paths to add to the MATLAB path
6
+ % expression (string): MATLAB startup expression
7
+
8
+ arguments
9
+ paths (1, :) string
10
+ expression (1, 1) string = string.empty()
11
+ end
12
+ for path = paths
13
+ addpath(genpath(path));
14
+ end
15
+
16
+ if ~isempty(expression)
17
+ eval(expression);
18
+ end
19
+
20
+ result = nan;
21
+ end
@@ -0,0 +1,127 @@
1
+ from enum import Enum
2
+ from typing import Any
3
+ from griffe import Function as GriffeFunction, Class as GriffeClass, Module, Attribute
4
+ from _griffe.exceptions import BuiltinModuleError
5
+
6
+
7
+ class Access(Enum):
8
+ PUBLIC = "public"
9
+ PROTECTED = "protected"
10
+ PRIVATE = "private"
11
+ IMMUTABLE = "immutable"
12
+
13
+
14
+ class CanonicalPathMixin:
15
+ @property
16
+ def canonical_path(self) -> str:
17
+ """The full dotted path of this object.
18
+
19
+ The canonical path is the path where the object was defined (not imported).
20
+ """
21
+ if self.parent is None or self.parent.path == "":
22
+ return self.name
23
+ return f"{self.parent.path}.{self.name}"
24
+
25
+
26
+ class Class(CanonicalPathMixin, GriffeClass):
27
+ def __init__(
28
+ self,
29
+ *args: Any,
30
+ hidden: bool = False,
31
+ sealed: bool = False,
32
+ abstract: bool = False,
33
+ enumeration: bool = False,
34
+ handle: bool = False,
35
+ **kwargs: Any,
36
+ ) -> None:
37
+ super().__init__(*args, **kwargs)
38
+ self._hidden: bool = hidden
39
+ self._sealed: bool = sealed
40
+ self._abstract: bool = abstract
41
+ self._enumeration: bool = enumeration
42
+ self._handle: bool = handle
43
+
44
+ @property
45
+ def is_private(self) -> bool:
46
+ return self._hidden
47
+
48
+ @property
49
+ def canonical_path(self) -> str:
50
+ if isinstance(self.parent, Classfolder):
51
+ return self.parent.canonical_path
52
+ else:
53
+ return super().canonical_path
54
+
55
+
56
+ class Property(CanonicalPathMixin, Attribute):
57
+ def __init__(
58
+ self,
59
+ *args: Any,
60
+ get_access: Access = Access.PUBLIC,
61
+ set_access: Access = Access.PUBLIC,
62
+ dependent: bool = False,
63
+ constant: bool = False,
64
+ abstract: bool = False,
65
+ transient: bool = False,
66
+ hidden: bool = False,
67
+ get_observable: bool = False,
68
+ set_observable: bool = False,
69
+ abort_set: bool = False,
70
+ non_copyable: bool = False,
71
+ has_default: bool = False,
72
+ size: str | None = None,
73
+ validation: str | None = None,
74
+ **kwargs: Any,
75
+ ) -> None:
76
+ super().__init__(*args, **kwargs)
77
+ self._get_access: Access = get_access
78
+ self._set_access: Access = set_access
79
+ self._dependent: bool = dependent
80
+ self._constant: bool = constant
81
+ self._abstract: bool = abstract
82
+ self._transient: bool = transient
83
+ self._hidden: bool = hidden
84
+ self._get_observable: bool = get_observable
85
+ self._set_observable: bool = set_observable
86
+ self._abort_set: bool = abort_set
87
+ self._non_copyable: bool = non_copyable
88
+ self._has_default: bool = has_default
89
+ self._size: str | None = size
90
+ self._validation: str | None = validation
91
+
92
+ @property
93
+ def is_private(self) -> bool:
94
+ set_public = self._access == Access.PUBLIC | self._access == Access.IMMUTABLE
95
+ get_public = self._access == Access.PUBLIC
96
+ return (set_public or get_public) and not self._hidden
97
+
98
+
99
+ class Function(CanonicalPathMixin, GriffeFunction):
100
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
101
+ super().__init__(*args, **kwargs)
102
+ self._access: Access = Access.PUBLIC
103
+ self._static: bool = False
104
+ self._abstract: bool = False
105
+ self._sealed: bool = False
106
+ self._hidden: bool = False
107
+
108
+ @property
109
+ def is_private(self) -> bool:
110
+ public = self._access == Access.PUBLIC | self._access == Access.IMMUTABLE
111
+ return public and not self._hidden
112
+
113
+
114
+ class Namespace(CanonicalPathMixin, Module):
115
+ def __repr__(self) -> str:
116
+ try:
117
+ return f"Namespace({self.filepath!r})"
118
+ except BuiltinModuleError:
119
+ return f"Namespace({self.name!r})"
120
+
121
+
122
+ class Classfolder(CanonicalPathMixin, Module):
123
+ def __repr__(self) -> str:
124
+ try:
125
+ return f"Classfolder({self.filepath!r})"
126
+ except BuiltinModuleError:
127
+ return f"Classfolder({self.name!r})"