2

Tl;dr

When I create a sphinx doc locally it builds as expected, but the GitHub Sphinx Build Action creates an empty doc. It must have to do with the sphinx-action not finding the target python modules as specified in conf.py.

Any ideas to configure the sphinx-action or conf.py correctly?

Expected Sphinx Doc

When I build the sphinx doc locally on my machine via cd docs/ && make html the resulting html looks as expected

expected_sphinx_doc

Empty Sphinx Doc generated by sphinx-action

My .github/workflows/sphinx_action.yml includes

    steps:
    # Checkout repo
    - uses: actions/checkout@v2
    # Build sphinx doc
    - uses: ammaraskar/sphinx-action@master
      with:
        docs-folder: "docs/"

and generates an empty skeleton of a Sphinx Doc

output_shpinx_doc

Project Setup

Project Structure
.
├── docs
│   ├── conf.py
│   ├── index.rst
│   ├── make.bat
│   ├── Makefile
│   ├── requirements.txt
│   └── sync.log
├── .github
│   └── workflows
│       └── sphinx_action.yml
├── .gitignore
├── mypackage
│   ├── __init__.py
│   ├── subfolder
│   │   ├── __init__.py
│   │   └── subclass.py
│   └── superclass.py
├── Pipfile
├── Pipfile.lock
└── README.md

conf.py Configuration

My docs/conf.py looks as follows. (Mind that I added three entries to the sys.path manually in order to make Sphinx find all python modules.)

# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html


# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
from m2r import MdInclude

sys.path.insert(0, os.path.abspath('..'))
sys.path.insert(0, os.path.abspath('../mypackage'))
sys.path.insert(0, os.path.abspath('../mypackage/subfolder'))


# -- Project information -----------------------------------------------------

project = 'MyPackage'
copyright = ''
author = 'Testuser'


# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc',
              'recommonmark'
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

#
source_suffix = ['.rst', '.md']

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']

# document the init of a class, too
autoclass_content = 'both'

# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
html_theme = 'nature'

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# from m2r to make `mdinclude` work
def setup(app):
    config = {
        # 'url_resolver': lambda url: github_doc_root + url,
        'auto_toc_tree_section': 'Contents',
        'enable_eval_rst': True,
    }

    # from m2r to make `mdinclude` work
    app.add_config_value('no_underscore_emphasis', False, 'env')
    app.add_config_value('m2r_parse_relative_links', False, 'env')
    app.add_config_value('m2r_anonymous_references', False, 'env')
    app.add_config_value('m2r_disable_inline_math', False, 'env')
    app.add_directive('mdinclude', MdInclude)

Pipfile

[[source]]
verify_ssl = true
url = "https://pypi.org/simple"
name = "pypi"

[dev-packages]

[packages]
m2r = {index = "pypi",version = "==0.2.1"}
pandas = {index = "pypi",version = "==1.0.3"}
sphinx = {index = "pypi",version = "==3.1.0"}
recommonmark = {index = "pypi",version = "==0.6.0"}
mypackage = "*"

[requires]
python_version = "3.8"

Note: I posted this question also as an issue in the GitHub repo of the sphinx-action.

chamaoskurumi
  • 2,271
  • 2
  • 23
  • 30
  • From the README: "If you have any Python dependencies that your project needs (themes, build tools, etc) then place them in a requirements.txt file inside your docs folder." Your project is a dependency and it must be installed. – Steve Piercy Aug 05 '20 at 09:08
  • Mh you are right. But how can I add `mypackage` itself to the requirements? Doesn't `pip` assume that every package mentioned is to be downloaded from the same index (= `PyPi`)? I managed to install `mypackage` via adding `pre-build-command: "pip install -e .`, yet the sphinx builds an empty doc. I realized that locally sphinx only builds successfully within the pipenv shell. But adding `pre-build-command: "apt install pipenv && pipenv install -e . && pipenv shell"` didn't help either. – chamaoskurumi Aug 05 '20 at 14:40
  • Try `-e .`. That's what Read the Docs does. – Steve Piercy Aug 05 '20 at 20:16
  • Unfortunately `-e .` didn't work @StevePiercy. I surrendered and try to automate the sphinx doc building without GitHubActions. – chamaoskurumi Aug 06 '20 at 13:59

2 Answers2

1

I had the exact same issue. Simply putting

import mypackage

in conf.py fixed things for me.

Edit: mypackage above refers to the actual package name and will be specific. In order for this to work, you need to make sure that the package is actually installed (e.g. using setuptools). Below are code snippets for GitHub actions

    - uses: ammaraskar/sphinx-action@master
      with:
        #pre-build-command: "apt-get update -y && apt-get install -y pandoc"
        docs-folder: "docs/"

and my requirements.txt file (in docs)

sphinx>=3.3
sphinx-autodoc-typehints
sphinx-argparse
-e .

I left the commented-out pre-build-command as you can use it to pip install -e . also. I don't think the sphinx version matters.

  • I tried ur solution, but the GithubAction failed - because Github couldn't find `mypackage`: `Configuration error: There is a programmable error in your configuration file: Traceback (most recent call last): File "/usr/local/lib/python3.8/site-packages/sphinx/config.py", line 348, in eval_config_file execfile_(filename, namespace) File "/usr/local/lib/python3.8/site-packages/sphinx/util/pycompat.py", line 81, in execfile_ exec(code, _globals) File "/github/workspace/docs/conf.py", line 16, in import mypackage ModuleNotFoundError: No module named 'mypackage'`. – chamaoskurumi Dec 01 '20 at 13:49
  • `mypackage` just refers to the package name (not sure what you use) but that’s likely not the issue ... Sphinx needs to find the package: in my case, I use setuptools to get it installed. Putting `-e .` in the requirements.txt file (see Sphinx-action instructions) should make it available (same as running `pip install -e .` in the preconfiguration step). – Ingmar Schoegl Dec 02 '20 at 14:26
0

Build your path inserts deterministically. For example, using __file__:

_HERE = os.path.dirname(__file__)
_ROOT_DIR = os.path.abspath(os.path.join(_HERE, '..'))
_PACKAGE_DIR = os.path.abspath(os.path.join(_HERE, '../mypackage'))
_SUBPACKAGE_DIR = os.path.abspath(os.path.join(_HERE, '../mypackage/subfolder'))

sys.path.insert(0, _ROOT_DIR)
sys.path.insert(0, _PACKAGE_DIR)
sys.path.insert(0, _SUBPACKAGE_DIR)

# test the path; not strictly needed
import mypackage

This way, the resolved locations are always the same, regardless of the present working directory.

sytech
  • 29,298
  • 3
  • 45
  • 86