Skip to content

Commit

Permalink
added docs path guessing; fixes #14
Browse files Browse the repository at this point in the history
  • Loading branch information
Cielquan committed Oct 9, 2020
1 parent dcb03a9 commit 18005f1
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 11 deletions.
80 changes: 69 additions & 11 deletions src/formelsammlung/flask_sphinx_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
:copyright: (c) Christian Riedel
:license: GPLv3
"""
from pathlib import Path
from typing import Optional

from flask import Flask, Response
Expand All @@ -18,20 +19,25 @@ class SphinxDocServer: # pylint: disable=R0903
.. highlight:: python
You can either include the plugin directly::
app = Flask(__name__)
SphinxDocServer(app, doc_dir="../../docs/build/html")
or you can invoke it in your app factory::
You can invoke it in your app factory::
sds = SphinxDocServer()
def create_app():
app = Flask(__name__)
sds.init_app(app, doc_dir="../../docs/build/html"))
sds.init_app(app)
return app
or you can include the plugin directly without setting a ``doc_dir``::
app = Flask(__name__)
SphinxDocServer(app)
or with setting a ``doc_dir``::
app = Flask(__name__)
SphinxDocServer(app, doc_dir="../../docs/build/html")
.. highlight:: default
"""

Expand All @@ -40,12 +46,14 @@ def __init__(self, app: Optional[Flask] = None, **kwargs) -> None:
if app is not None:
self.init_app(app, **kwargs)

@staticmethod
def init_app(app: Flask, doc_dir: str, index_file: str = "index.html") -> None:
def init_app(
self, app: Flask, doc_dir: Optional[str] = None, index_file: str = "index.html"
) -> None:
"""Add the `/docs/` route to the `app` object.
:param app: Flask object to add the route to.
:param doc_dir: The base directory holding the sphinx docs to serve.
:param doc_dir: The base directory holding the sphinx docs to serve. If not set
the ``doc_dir`` is guessed up to 3 directories above.
:param index_file: The html file containing the base toctree.
Default: "index.html"
"""
Expand All @@ -58,7 +66,57 @@ def web_docs(filename: str) -> Response: # pylint: disable=W0612
:param filename: File name from URL
:return: Requested doc page
"""
app.static_folder = doc_dir
app.static_folder = doc_dir or self._find_build_docs(app.root_path)
doc_file = app.send_static_file(filename)
app.static_folder = "static"
return doc_file

@staticmethod
def _find_build_docs(app_root: str, steps_up_the_tree: int = 3):
"""Find build sphinx html docs.
:param app_root: Root directory of the app.
:param steps_up_the_tree: Amount of steps to go up the file tree, defaults to 3
:raises IOError: if no 'doc' or 'docs' directory is found.
:raises IOError: if no '_build' or 'build' directory is found in the doc/docs dir.
:raises IOError: if no 'html' directory is found in the _build/build dir.
:return: Path to directory holding the build sphinx docs.
"""
check_dir = file_dir = Path(app_root).parent

#: Search doc(s) dir up the tree
doc_dir = None
for i in range(0, steps_up_the_tree + 1):
if (check_dir / "doc").is_dir():
doc_dir = check_dir / "doc"
if (check_dir / "docs").is_dir():
doc_dir = check_dir / "docs"

if doc_dir:
break

check_dir = file_dir.parents[i]

if not doc_dir:
raise IOError("No 'doc' or 'docs' directory found.")

#: search for (_)build dir
build_dir = None
if (doc_dir / "_build").is_dir():
build_dir = doc_dir / "_build"
if (doc_dir / "build").is_dir():
build_dir = doc_dir / "build"

if not build_dir:
raise IOError(
f"No '_build' or 'build' directory found in {doc_dir}."
"Maybe you forgot to build the docs."
)

#: check for html dir
if Path("html") in build_dir.iterdir():
return build_dir / "html"
raise IOError(
f"No 'html' directory found in {build_dir}."
"Maybe you forgot to build the HTML docs."
)
91 changes: 91 additions & 0 deletions tests/test_flask_sphinx_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
:copyright: (c) Christian Riedel
:license: GPLv3
"""
from pathlib import Path

import pytest
from flask import Flask

from formelsammlung.flask_sphinx_docs import SphinxDocServer
Expand Down Expand Up @@ -49,3 +52,91 @@ def _create_app():
resp = client.get("/docs/")
assert resp.status_code == 200
assert resp.data.decode() == "TEST_CONTENT_2"


def test_custom_index_file(tmp_path):
"""Test custom index file."""
test_dir = tmp_path / "docs"
test_dir.mkdir()
test_file = test_dir / "custom.html"
test_file.write_text("TEST_CONTENT")

app = Flask(__name__)
SphinxDocServer(app, doc_dir=str(test_dir), index_file="custom.html")
client = app.test_client()

resp = client.get("/docs/")
assert resp.status_code == 200
assert resp.data.decode() == "TEST_CONTENT"


def doc_dir_guessing_option_1(tmp_path, monkeypatch):
"""Test guessing of doc dir with 'doc/_build'."""
test_repo = tmp_path / "testrepo"
test_repo.mkdir()

py_code_dir = test_repo / "src" / "testrepo"
py_code_dir.mkdir(parents=True)

monkeypatch.setattr(Path, "parent", py_code_dir)

with pytest.raises(IOError) as excinfo:
SphinxDocServer._find_build_docs("")
assert "No 'doc' or 'docs'" in str(excinfo.value)

doc_dir = test_repo / "doc"
doc_dir.mkdir()

for child in doc_dir.iterdir(): print(child)

with pytest.raises(IOError) as excinfo:
SphinxDocServer._find_build_docs("")
assert "No '_build' or 'build'" in str(excinfo.value)

build_dir = doc_dir / "_build"
build_dir.mkdir()

with pytest.raises(IOError) as excinfo:
SphinxDocServer._find_build_docs("")
assert "No 'html'" in str(excinfo.value)

html_dir = build_dir / "html"
html_dir.mkdir()

assert SphinxDocServer._find_build_docs("") == html_dir


def doc_dir_guessing_option_2(tmp_path, monkeypatch):
"""Test guessing of doc dir with 'docs/build'."""
test_repo = tmp_path / "testrepo"
test_repo.mkdir()

py_code_dir = test_repo / "src" / "testrepo"
py_code_dir.mkdir(parents=True)

monkeypatch.setattr(Path, "parent", py_code_dir)

with pytest.raises(IOError) as excinfo:
SphinxDocServer._find_build_docs("")
assert "No 'doc' or 'docs'" in str(excinfo.value)

doc_dir = test_repo / "docs"
doc_dir.mkdir()

for child in doc_dir.iterdir(): print(child)

with pytest.raises(IOError) as excinfo:
SphinxDocServer._find_build_docs("")
assert "No '_build' or 'build'" in str(excinfo.value)

build_dir = doc_dir / "build"
build_dir.mkdir()

with pytest.raises(IOError) as excinfo:
SphinxDocServer._find_build_docs("")
assert "No 'html'" in str(excinfo.value)

html_dir = build_dir / "html"
html_dir.mkdir()

assert SphinxDocServer._find_build_docs("") == html_dir

0 comments on commit 18005f1

Please sign in to comment.