Sphinx with both Python and Matlab (sphinxcontrib-matlabdomain): Import fail - python

I have a project including a Python package as well as some Matlab code, which should all go into the same documentation created by Sphinx.
The Python part of the documentation works flawlessly quite some time already - the Matlab part was added now and makes some trouble.
The data structure more or less is as follows:
|- python
|- modules
|- including subpackages
|- some sub-modules
|- matlab
|- scripts
|- functions
|- docs
|- source
|- conf.py
|- matlab.rst
|- python.rst
|- index.rst
|- ...
The most relevant lines in conf.py are prob. the following:
import os
import sys
# for the Python autodoc package
sys.path.insert(0, os.path.abspath('../..'))
extensions = ['sphinx.ext.napoleon', 'sphinxcontrib.matlab', 'sphinx.ext.autodoc']
# Path to the Matlab files
matlab_src_dir = '../../matlab'
#matlab_src_dir = '<<abssolute_path>>/matlab'
As you see, I tried both relative and absolute paths for matlab_src_dir. So far, without any difference.
The python.rst, which was created automatically by apidoc, contains:
python package
==============
.. automodule:: python
:members:
:undoc-members:
:show-inheritance:
Subpackages
-----------
.. toctree::
:maxdepth: 4
python.subpackages
The matlab.rst was created manually and contains:
matlab package
==============
.. mat:automodule:: matlab
:members:
:undoc-members:
:show-inheritance:
Subscripts
----------
.. toctree::
:maxdepth: 4
matlab.function_file
Thus, python.rst and matlab.rst are more or less the same but with mat:automodule for Matlab according to the documentation.
Finally, index.rst contains:
.. toctree::
:maxdepth: 2
python
.. toctree::
:maxdepth: 2
matlab
Now, when I run Sphinx' make html I receive the following error, which results in a nice Python documentation but an empty Matlab documentation:
WARNING: [sphinxcontrib-matlabdomain]: failed to import module 'matlab'; the following exception was raised:
Traceback (most recent call last):
File "C:\Users\<<username>>\AppData\Roaming\Python\Python39\site-packages\sphinxcontrib\mat_documenters.py", line 117, in import_object
obj = self.module = modules[self.modname]
KeyError: 'matlab'
What am I missing here. Why can't Sphinx find the matlab folder with the containing m-files?
And if that should be solved, maybe a secondary question: is there any similar function as apidoc for Matlab files, so that I do not need to create all *.rst files myself?
Thank you for any hints!
BTW: I am running on Sphinx v4.4.0 under Python 3.9.7.

Neither providing a hard-coded absolute path to matlab_src_dir nor providing os.path.abspath(relative_path) lead to success.
Thanks to Steve Piercy, who mentioned an example in the comments, I found that I should use os.path.dirname(os.path.abspath(relative_path)). As such, the errors are gone and Sphinx is working.
This is interesting, because I have already tried os.path.abspath(relative_path to the parent of the package) before, which I would expect is doing the same than os.path.dirname(). Anyway, I got a working solution now.
If anybody would have an idea about the second question ("is there any similar function as apidoc for Matlab files, so that I do not need to create all *.rst files myself?") I would be really happy.

Related

Sphinx: the simplest usage scenario, how to? [duplicate]

I am running Sphinx on a rst file containing automodule but it does not seem to have any effect.
Here are the details: I have a Python project with a file agent.py containing a class Agent in it. I also have a subdirectory apidoc with a file agent.rst in it (generated by sphinx-apidoc):
agent module
============
.. automodule:: agent
:members:
:undoc-members:
:show-inheritance:
I run sphinx with sphinx-build -b html apidoc apidoc/_build with the project's directory as the current working directory.
To make sure the Python files are found, I've included the following in apidoc/conf.py:
import os
import sys
sys.path.insert(0, os.path.abspath('.'))
It runs without errors but when I open the resulting HTML file it only shows "agent module" and everything is blank. Why isn't it showing the class Agent and its members?
Update: the original problem was likely caused by the fact that I had not included sphinx.ext.autodoc in conf.py. Now that I did, though, I get warnings like:
WARNING: invalid signature for automodule ('My Project.agent')
WARNING: don't know which module to import for autodocumenting 'My Project.agent' (try placing a "module" or "currentmodule" directive in the document, or giving an explicit module name)
WARNING: autodoc: failed to import module 'agent'; the following exception was raised:
No module named 'agent'
I'll try answering by putting the "canonical" approach side-by-side with your case.
The usual "getting started approach" follows these steps:
create a doc directory in your project directory (it's from this directory the commands in the following steps are executed).
sphinx-quickstart (choosing separate source from build).
sphinx-apidoc -o ./source ..
make html
This would yield the following structure:
C:\Project
|
| agent.py
|
|---docs
| | make.bat
| | Makefile
| |
| |---build
| |
| |---source
| | conf.py
| | agent.rst
| | index.rst
| | modules.rst
In your conf.py you'd add (after step 2):
sys.path.insert(0, os.path.abspath(os.path.join('..', '..')))
and in index.rst you'd link modules.rst:
Welcome to Project's documentation!
================================
.. toctree::
:maxdepth: 2
:caption: Contents:
modules
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
Now compare the above with what you have - from what you shared in your question:
C:\Project
|
| agent.py
|
|---apidoc
| | agent.rst
| | conf.py
| |
| |-- _build
You ran:
sphinx-build -b html apidoc apidoc/_build
and in your conf.py:
sys.path.insert(0, os.path.abspath('.'))
Your error stacktrace says it couldn't find the module agent. That's probably because you didn't go 1 level down in your conf.py (it's pointing to the path with .rst, not the path with .py), this should work:
sys.path.insert(0, os.path.abspath('..')). Also, if you didn't manually edit/connect your modules.rst in your index.rst you are likely to only see that module.
You may care to notice the signatures of the sphinx commands at play:
sphinx-apidoc [OPTIONS] -o <OUTPUT_PATH> <MODULE_PATH>
sphinx-build [options] <sourcedir> <outputdir> [filenames …]
<sourcedir> refers to where .rst are, and <MODULE_PATH> to where .py are. <OUTPUT_PATH> to where .rst are placed, and <outputdir> to where .html are placed.
Please also notice, you mentioned: "the project's directory as the current working directory." I've seen "working directory" mentioned in sphinx threads on stackoverflow, interchangeably as both the Project base directory, or the docs directory. However, if you search the Sphinx documentation for "working directory" you'll find no mention of it.
Finally, there is an advantage to using the file/directory structure of the "getting started approach". It basically "puts you on the same page" with most threads on the Sphinx tag, and that way alleviates the mental work of mapping the cases to different directory/file structures.
I hope this helps.

Can you autodoc only submodules using sphinx-apidoc?

I use sphinx-click extension for my click application, and i want to use sphinx-apidoc to generate .rst files for only submodules.
I've been working with pythons Sphinx documentation library for about a year now, and I have a usecase... I cannot quite figure out.. maybe I'm just blind right now.
Anyways, I have a cli tool structured something like
my_tool/
+-- __init__.py
+-- cli_entry.py
+-- utils
| +-- __init__.py
| +-- foo.py
| +-- bar.py
Where cli_entry is a click application, and it imports my_tool.utils.foo and my_tools.utils.bar
Since this is using the Click library. I've decided to use the sphinx_click extension to document any command that is in cli_entry.py (which documents all the commands great).
But heres the issue, I want to use sphinx-apidoc to generate the .rst files for everything that is in the ./my_tool/utils/ modules.
When I use the command as sphinx-apidoc -o ../docs/utils my_tool/utils the output files that I get include
docs/
+-- utils
| +-- module.rst
| +-- utils.rst
Which looks great at first, but upon opening utils.rst the file looks something like
utils package
=============
Submodules
----------
utils.foo module
----------------------
.. automodule:: utils.foo
:members:
:undoc-members:
:show-inheritance:
utils.bar module
----------------------
.. automodule:: utils.bar
:members:
:undoc-members:
:show-inheritance:
Then when I build the documentation using make html (from sphinx generated makefile) I get an error saying Failed to import 'utils.foo': no module named utils.foo thats because the import should exist as my_tool.utils.foo
How can I use sphinx-apidoc to generate only submodules and include the correct import paths?? Maybe its something I'm missing in the conf.py.. maybe it's an option I'm missing from sphinx-apidoc?
EDIT: I should mention that I could use the exclude_pattern argument... but I would prefer to not have to specify each cli file in my root. ex. In the case that I have cli_entry.py, cli_commandgroup1.py... cli_commandgroupN.py. I want this solution to be dynamic enough to just support only submodules.
EDIT: I tried using sphinx-apidoc -o ../docs/utils my_tool/ and this creates the following output
docs/
+-- utils
| +-- module.rst
| +-- my_tool.cli_entry.rst
| +-- my_tool.utils.rst
Now in the my_tool.utils.rst file, the imports are correct, and the docs can be generated.
my_tool.utils.foo module
----------------------
.. automodule:: my_tool.utils.foo
:members:
:undoc-members:
:show-inheritance:
The issue with specifying my_tool/ is that my_tool.cli_entry.rst gets created, when this .rst file would already be created using the click-sphinx extension.

How to make Sphinx autodoc extension include an underscore/private Python module

I am autogenerating documentation for a Python package using Sphinx with the autodoc extension. The issue I am facing is that the autodoc skips any modules with an underscore.
Some modules were underscored to discourage users from importing them. However, the classes inside these underscored files have no underscores.
When I add the underscored module manually to the package_name.rst and ran make html, it shows. So my problem is how to automate that from autodoc.
I am trying to avoid parsing the package_name.rst via a script to add them. I am hoping for an autodoc flag or a hack!
It's perhaps a misconception to think the ..automodule :: directive applied to a package will automatically document sub-modules as members (by comparison with classes, variables, etc).
I just tested this but it can not be done using :private-members: and or :special-members:. Not by writing either option in the .. automodule:: directive corresponding to the package. (Trying to set both options in autodoc_default_options gives the same result.)
The following example of package and module layout:
C:.
│
└────your_package
│
│ public_module.py
│ _private_module.py
│ __init__.py
Using a .rst with a single .. automodule:: for the package:
Your package rst
================
.. automodule:: your_package
:members:
:undoc-members:
:private-members:
:special-members:
Minimal example _private_module.py with docstrings (public_module.py is the same except for the title):
"""Private module docstring."""
class PublicClass:
"""Docstring."""
pass
Does indeed give an empty documentation:
But if you remove the underscore from the module you get the exact same result.
I am trying to avoid parsing the package_name.rst via a script to add them
If you are generating the .rst files with sphinx-apidoc if using the -P flag:
-P, --private
Include “_private” modules.
New in version 1.2.
The generated files will include an .. automodule:: directive for the private modules, this does have the side-effect of also including the :private-members: option as noted in another post "Include __main__.py in sphinx-apidoc generated files".
Example explicitly including the .. automodule:: directives:
Your package rst
================
.. automodule:: your_package
:members:
:undoc-members:
.. automodule:: your_package.public_module
:members:
:undoc-members:
.. automodule:: your_package._private_module
:members:
:undoc-members:
The result:

sphinx-apidoc vs autosummary

I'm running into a bit of brick wall trying to work out the best way to implement automatic documentation generation for a Django project
my project structure is similar to the following:
myproj/ # project root
|- docs/ # docs root
|- myproj/ # package root
|- app1/
|- app2/
|- app3/
utils.py
...
I would like to automatically generate documentation for everything under the package root directory- and initially started using sphinx-apidoc, but then read something that implied I should be using autosummary instead and have not been able to find any information outlining what the difference between these two options is.
To anyone else struggling to work it out, this is the guide I finally found that helped me clear up the confusion:
https://romanvm.pythonanywhere.com/post/autodocumenting-your-python-code-sphinx-part-ii-6/
In short, use autosummary

sphinx-build fail - autodoc can't import/find module

I'm trying to get started with Sphinx and seem to have relentless problems.
Command: docs/sphinx-quickstart
I answer all the questions and everything works fine.
Command: docs/ls
Everything looks normal. Result: build Makefile source
Command: sphinx-build -d build/doctrees source build/html
It seems to work. I was able to open the index.html file and see a "shell" of what I'm wanting.
When I try and put my actual source code as the source folder I run into problems.
Command: sphinx-build -d build/doctrees ../ys_utils build/html
Result:
Making output directory...
Running Sphinx v1.1.3
loading pickled environment... not yet created
No builder selected, using default: html
loading intersphinx inventory from http://docs.python.org/objects.inv...
building [html]: targets for 1 source files that are out of date
updating environment: 1 added, 0 changed, 0 removed
Traceback (most recent call last):
File "/usr/local/lib/python2.6/dist-packages/Sphinx-1.1.3-py2.6.egg/sphinx/ext/autodoc.py", line 321, in import_object
__import__(self.modname)
ImportError: No module named ys_utils
Traceback (most recent call last):
File "/usr/local/lib/python2.6/dist-packages/Sphinx-1.1.3-py2.6.egg/sphinx/ext/autodoc.py", line 321, in import_object
__import__(self.modname)
ImportError: No module named ys_utils.test_validate_ut
Traceback (most recent call last):
File "/usr/local/lib/python2.6/dist-packages/Sphinx-1.1.3-py2.6.egg/sphinx/ext/autodoc.py", line 321, in import_object
__import__(self.modname)
ImportError: No module named ys_utils.git_utils
Traceback (most recent call last):
File "/usr/local/lib/python2.6/dist-packages/Sphinx-1.1.3-py2.6.egg/sphinx/ext/autodoc.py", line 321, in import_object
__import__(self.modname)
ImportError: No module named setup.setup
/home/ricomoss/workspace/nextgen/ys_utils/ys_utils.rst:4: WARNING: autodoc can't import/find module 'ys_utils', it reported error: "No module named ys_utils", please check your spelling and sys.path
/home/ricomoss/workspace/nextgen/ys_utils/ys_utils.rst:10: WARNING: autodoc can't import/find module 'ys_utils.test_validate_ut', it reported error: "No module named ys_utils.test_validate_ut", please check your spelling and sys.path
/home/ricomoss/workspace/nextgen/ys_utils/ys_utils.rst:12: WARNING: don't know which module to import for autodocumenting u'UnitTests' (try placing a "module" or "currentmodule" directive in the document, or giving an explicit module name)
/home/ricomoss/workspace/nextgen/ys_utils/ys_utils.rst:18: WARNING: autodoc can't import/find module 'ys_utils.git_utils', it reported error: "No module named ys_utils.git_utils", please check your spelling and sys.path
/home/ricomoss/workspace/nextgen/ys_utils/ys_utils.rst:24: WARNING: autodoc can't import/find module 'setup.setup', it reported error: "No module named setup.setup", please check your spelling and sys.path
WARNING: master file /home/ricomoss/workspace/nextgen/ys_utils/index.rst not found
looking for now-outdated files... none found
pickling environment... done
checking consistency... /home/ricomoss/workspace/nextgen/ys_utils/ys_utils.rst:: WARNING: document isn't included in any toctree
done
preparing documents... done
writing output... [ 50%] index
Exception occurred:
File "/usr/local/lib/python2.6/dist-packages/Sphinx-1.1.3-py2.6.egg/sphinx/environment.py", line 1213, in get_doctree
f = open(doctree_filename, 'rb')
IOError: [Errno 2] No such file or directory: '/home/ricomoss/workspace/nextgen/docs/build/doctrees/index.doctree'
The full traceback has been saved in /tmp/sphinx-err-jjJ7gM.log, if you want to report the issue to the developers.
Please also report this if it was a user error, so that a better error message can be provided next time.
Either send bugs to the mailing list at <http://groups.google.com/group/sphinx-dev/>,
or report them in the tracker at <http://bitbucket.org/birkenfeld/sphinx/issues/>. Thanks!
What is wrong, and how can I fix it?
Edit:
I'd like to be able to use a Makefile to handle this. As of now I have two folders in my project.
nextgen/ls
docs ys_utils
I need nextgen/docs/Makefile to generate the HTML for ys_utils and all other modules I'm going to have.
Autodoc can't find your modules, because they are not in sys.path.
You have to include the path to your modules in in the sys.path in your conf.py.
Look at the top of your conf.py (just after the import of sys), there is a sys.path.insert() statement, which you can adapt.
By the way: you can use the Makefile created by Sphinx to create your documentation.
Just call
make
to see the options.
If something went wrong before try:
make clean
before running make html.
solution
It sounds like os.path.append() is working OK for folks, but if you follow the conf.py template, you would insert the module path to the front of sys.path using os.path.insert(0, ...), and just add an extra .
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
If you have setup your sphinx project to use separate build and source directories, that call should instead be:
sys.path.insert(0, os.path.abspath('../..'))
about sys.path ...
To run python code, the python interpreter needs to know where it is. With the sphinx config being a python script, it's location needs to be made known, which is done by adding it the the sys.path variable using the insert method (see the docs on module search path).
The path added to sys.path in this case is a "relative" path, which is specified using dots. This is a general way of specifying the path, which allows the code to be moved and still point correctly to the correct path in your codebase.
. - current path of the conf.py
.. - parent path of the conf.py
../.. - parent of the parent path, etc.
I use linux, so directories are specified with a forward slash, but a cross-platform method for specifying parent directories can be acheived with pathlib.
from pathlib import Path
parent = Path(__file__).parent
parents_parent = Path(__file__).parents[1]
in conf.py
just add the path to your project folder.
sys.path.append('/home/workspace/myproj/myproj')
If
module root path is correctly set in conf.py
__init__.py is placed correctly
rst syntax is correct
and your autodoc still cannot find the modules...
It may be because the dependencies of those modules are not satisfied under your python environment. You will want to check if all the import statements are working within the modules.
I don't know why (maybe in my case autodoc couldn't install my package), but I always got module-not-found errors until I explicitly included all directories containing modules to the path.
For the following example folder structure
project_dir
|- setup.py
|- src
| |- __init__.py
| |- source1.py
| |- sub_project
| |- __init__.py
| |- source2.py
|- docs
|- conf.py
|- source
| |- index.rst
|- _build
I included
for x in os.walk('../../src'):
sys.path.insert(0, x[0])
to the beginning of conf.py such that all involved directories would be added.
I got this same error but it was caused by a completely different reason than explained in the other answers.
My .. automethod:: mymodule.func directive should actually have been:
.. automethod:: mymodule::func
See the New in version 1.3 section in the autoclass documentation.
i add the following line at the beggining of file conf.py:
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
sys.path.append(os.path.abspath(
os.path.join(__file__, "../../src")
))
my project has the next structure:
project_dir
|- setup.py
|- src
| |- __init__.py
| |- ....
|- docs
|- conf.py
|- ...
I think I did this the first time I tried to add a file to the toctree. I think it was because I left out the blank line between the :maxdepth line and the file name.
.. Animatrix Concepts documentation master file, created by
sphinx-quickstart on Thu Mar 22 18:06:15 2012.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Animatrix Concepts documentation!
============================================
Contents:
.. toctree::
:maxdepth: 2
stuff
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
Above is my index.rst file. stuff.rst resides in the same directory as it.
You can use Pweave and noweb formatting to generate rst documents that include the output of the code embedded in them. Basically, you write your rst file, with python code embedded in marked chunks like this:
<<echo=False>>=
print("some text that will appear in the rst file")
#
and Pweave will execute those chunks, and replace them with their output in a resulting rst file, which you can then use with sphinx. See the Pweave reST example for more details of how it looks.
A lot of solutions in the thread are discussed in the right direction.
For me, the command on the official docs was helpful.
import pathlib
import sys
sys.path.insert(0, pathlib.Path(__file__).parents[2].resolve().as_posix())

Categories