mirror of https://github.com/Nonannet/pyladoc.git
Compare commits
7 Commits
c4fdb5040a
...
a413d771b3
Author | SHA1 | Date |
---|---|---|
|
a413d771b3 | |
|
727ab55b3d | |
|
b20773364c | |
|
ad6fe7c6e7 | |
|
37ad1231c8 | |
|
250885d44f | |
|
76944d1829 |
|
@ -7,6 +7,41 @@ on:
|
|||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build-ubuntu-no-optional-dependencies:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.12]
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install from source and install pytest
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -e .
|
||||
python -m pip install pytest lxml requests
|
||||
|
||||
- name: Run tests with pytest (no matplotlib, no pandas)
|
||||
run: |
|
||||
pytest tests/test_rendering_markdown.py::test_markdown_styling
|
||||
pytest tests/test_rendering_markdown.py::test_markdown_table
|
||||
|
||||
- name: Install matplotlib
|
||||
run: |
|
||||
python -m pip install matplotlib
|
||||
|
||||
- name: Run tests with pytest rendering equations (with matplotlib)
|
||||
run: |
|
||||
pytest tests/test_rendering_markdown.py::test_markdown_equations
|
||||
|
||||
build-ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
name: Build and Deploy Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Install dependencies
|
||||
run: pip install sphinx sphinx_rtd_theme sphinx-autodoc-typehints myst-parser
|
||||
- name: Generate Class List
|
||||
run: |
|
||||
pip install .
|
||||
python ./docs/source/generate_class_list.py
|
||||
- name: Build Docs
|
||||
run: |
|
||||
cd docs
|
||||
sphinx-apidoc -o source/ ../src/ -M --no-toc
|
||||
rm source/*.rst
|
||||
make html
|
||||
touch build/html/.nojekyll
|
||||
mkdir -p build/html/media
|
||||
cp ../media/output_example.png build/html/media/
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: docs/build/html
|
|
@ -131,4 +131,7 @@ cython_debug/
|
|||
pyModbusTCP_old/
|
||||
test.py
|
||||
test_*.ipynb
|
||||
settings.json
|
||||
settings.json
|
||||
|
||||
# Autogenerated doc file
|
||||
docs/source/modules.md
|
||||
|
|
14
README.md
14
README.md
|
@ -21,7 +21,7 @@ is a hard problem where LaTeX is superior.
|
|||
|
||||
## Example outputs
|
||||
|
||||
[](https://raw.githubusercontent.com/Nonannet/pyladoc/refs/heads/main/tests/out/test_latex_render1.pdf)
|
||||
[](https://raw.githubusercontent.com/Nonannet/pyladoc/refs/heads/main/tests/out/test_latex_render1.pdf)
|
||||
|
||||
- HTML: [test_html_render1.html](https://html-preview.github.io/?url=https://github.com/Nonannet/pyladoc/blob/main/tests/out/test_html_render1.html) ([code](https://github.com/Nonannet/pyladoc/blob/main/tests/out/test_html_render1.html))
|
||||
- PDF: [test_latex_render1.pdf](https://raw.githubusercontent.com/Nonannet/pyladoc/refs/heads/main/tests/out/test_latex_render1.pdf) ([code](https://github.com/Nonannet/pyladoc/blob/main/tests/out/test_html_render1.tex))
|
||||
|
@ -60,13 +60,15 @@ Pyladoc depends on the markdown package.
|
|||
Optional dependencies are:
|
||||
- Matplotlib python package for rendering LaTeX equations for HTML output
|
||||
- LaTeX for exporting to PDF or exporting Matplotlib figures to LaTeX (PGF/TikZ rendering)
|
||||
- Pandas and Matplotlib for including Pandas Tables and Matplotlib figures (obviously)
|
||||
- Pandas and Jinja2 for rendering pandas tables
|
||||
- Matplotlib for rendering matplotlib figures (obviously)
|
||||
|
||||
For the included template the following LaTeX setup works on Ubuntu:
|
||||
For the included template the `miktex`-LaTeX distribution works on Windows
|
||||
and the following LaTeX setup works on Ubuntu (both tested in CI):
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y texlive-latex-extra texlive-fonts-extra lmodern texlive-xetex texlive-science
|
||||
sudo apt-get install -y texlive-latex-extra texlive-fonts-recommended lmodern texlive-xetex texlive-science
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
@ -121,8 +123,8 @@ cd pyladoc
|
|||
It's recommended to setup an venv:
|
||||
|
||||
```bash
|
||||
python -m venv venv
|
||||
source venv/bin/activate # On Windows use `venv\Scripts\activate`
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate # On Windows use `.venv\Scripts\activate`
|
||||
```
|
||||
|
||||
Install the package and dev-dependencies while keeping files in the
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@ -0,0 +1,35 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.https://www.sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
|
@ -0,0 +1,32 @@
|
|||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# For the full list of built-in configuration values, see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath("../src/"))
|
||||
|
||||
project = 'pyladoc'
|
||||
copyright = '2025, Nicolas Kruse'
|
||||
author = 'Nicolas Kruse'
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||
|
||||
extensions = ["sphinx.ext.autodoc", "sphinx.ext.napoleon", "sphinx_autodoc_typehints", "myst_parser"]
|
||||
|
||||
templates_path = ['_templates']
|
||||
exclude_patterns = []
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||
|
||||
# html_theme = 'alabaster'
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_static_path = ['_static']
|
||||
|
||||
autodoc_inherit_docstrings = True
|
|
@ -0,0 +1,61 @@
|
|||
import importlib
|
||||
import inspect
|
||||
import fnmatch
|
||||
from io import TextIOWrapper
|
||||
|
||||
|
||||
def write_classes(f: TextIOWrapper, patterns: list[str], module_name: str, title: str, description: str = '', exclude: list[str] = []) -> None:
|
||||
|
||||
module = importlib.import_module(module_name)
|
||||
|
||||
classes = [
|
||||
name for name, obj in inspect.getmembers(module, inspect.isclass)
|
||||
if (obj.__module__ == module_name and
|
||||
any(fnmatch.fnmatch(name, pat) for pat in patterns if pat not in exclude) and
|
||||
obj.__doc__ and '(Automatic generated stub)' not in obj.__doc__)
|
||||
]
|
||||
|
||||
"""Write the classes to the file."""
|
||||
f.write(f'## {title}\n\n')
|
||||
if description:
|
||||
f.write(f'{description}\n\n')
|
||||
|
||||
for cls in classes:
|
||||
f.write('```{eval-rst}\n')
|
||||
f.write(f'.. autoclass:: {module_name}.{cls}\n')
|
||||
f.write(' :members:\n')
|
||||
f.write(' :undoc-members:\n')
|
||||
f.write(' :show-inheritance:\n')
|
||||
f.write(' :inherited-members:\n')
|
||||
if title != 'Base classes':
|
||||
f.write(' :exclude-members: select\n')
|
||||
f.write('```\n\n')
|
||||
|
||||
|
||||
def write_functions(f: TextIOWrapper, patterns: list[str], module_name: str, title: str, description: str = '', exclude: list[str] = []) -> None:
|
||||
|
||||
module = importlib.import_module(module_name)
|
||||
|
||||
classes = [
|
||||
name for name, obj in inspect.getmembers(module, inspect.isfunction)
|
||||
if (obj.__module__ == module_name and
|
||||
any(fnmatch.fnmatch(name, pat) for pat in patterns if pat not in exclude))
|
||||
]
|
||||
|
||||
"""Write the classes to the file."""
|
||||
f.write(f'## {title}\n\n')
|
||||
if description:
|
||||
f.write(f'{description}\n\n')
|
||||
|
||||
for func in classes:
|
||||
if not func.startswith('_'):
|
||||
f.write('```{eval-rst}\n')
|
||||
f.write(f'.. autofunction:: {module_name}.{func}\n')
|
||||
f.write('```\n\n')
|
||||
|
||||
|
||||
with open('docs/source/modules.md', 'w') as f:
|
||||
f.write('# Pyladoc classes, functions and submodules\n\n')
|
||||
write_classes(f, ['DocumentWriter'], 'pyladoc', title='DocumentWriter Class')
|
||||
write_functions(f, ['*'], 'pyladoc', title='Functions')
|
||||
write_functions(f, ['*'], 'pyladoc.latex', title='Submodule latex')
|
|
@ -0,0 +1,10 @@
|
|||
```{toctree}
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
readme
|
||||
modules
|
||||
```
|
||||
|
||||
```{include} ../../README.md
|
||||
```
|
|
@ -0,0 +1,2 @@
|
|||
```{include} ../../README.md
|
||||
```
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
|
@ -29,6 +29,7 @@ dev = [
|
|||
Homepage = "https://github.com/Nonannet/pyladoc"
|
||||
Repository = "https://github.com/Nonannet/pyladoc"
|
||||
Issues = "https://github.com/Nonannet/pyladoc/issues"
|
||||
documentation = "https://nonannet.github.io/pyladoc/"
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=61.0", "wheel"]
|
||||
|
|
|
@ -33,6 +33,7 @@ else:
|
|||
Table = DataFrame | Styler
|
||||
except ImportError:
|
||||
Table = DataFrame
|
||||
Styler = None
|
||||
|
||||
try:
|
||||
import matplotlib.pyplot as plt
|
||||
|
@ -475,8 +476,8 @@ class DocumentWriter():
|
|||
centered: Whether to center the table in LaTeX output
|
||||
"""
|
||||
assert Table and isinstance(table, Table), 'Table has to be a pandas DataFrame oder DataFrame Styler'
|
||||
styler = table if isinstance(table, Styler) else getattr(table, 'style', None)
|
||||
assert isinstance(styler, Styler), 'Jinja2 package is required for rendering tables'
|
||||
styler = table if Styler and isinstance(table, Styler) else getattr(table, 'style', None) # type: ignore[truthy-function]
|
||||
assert Styler and isinstance(styler, Styler), 'Jinja2 package is required for rendering pandas tables' # type: ignore[truthy-function]
|
||||
|
||||
def render_to_html() -> str:
|
||||
caption_prefix, reference = self._add_item(ref_id, ref_type, prefix_pattern)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from html.parser import HTMLParser
|
||||
from typing import Generator, Any, Literal, get_args
|
||||
from pandas.io.formats.style import Styler
|
||||
from typing import Generator, Any, Literal, get_args, TYPE_CHECKING
|
||||
import re
|
||||
import os
|
||||
import shutil
|
||||
|
@ -8,6 +7,13 @@ import subprocess
|
|||
import tempfile
|
||||
from .latex_escaping import unicode_to_latex_dict, latex_escape_dict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pandas.io.formats.style import Styler
|
||||
else:
|
||||
try:
|
||||
from pandas.io.formats.style import Styler
|
||||
except ImportError:
|
||||
Styler = None
|
||||
|
||||
LatexEngine = Literal['pdflatex', 'lualatex', 'xelatex', 'tectonic']
|
||||
|
||||
|
@ -116,6 +122,9 @@ def render_pandas_styler_table(df_style: Styler, caption: str = '', label: str =
|
|||
Returns:
|
||||
The LaTeX code.
|
||||
"""
|
||||
assert Styler, 'Jinja2 package is required for rendering pandas tables' # type: ignore[truthy-function]
|
||||
assert isinstance(df_style, Styler), 'df_style has to be of type Styler'
|
||||
|
||||
def iter_table(table: dict[str, Any]) -> Generator[str, None, None]:
|
||||
yield '\\begin{table}\n'
|
||||
if centering:
|
||||
|
|
Loading…
Reference in New Issue