")
18 | assert len(data) > 100
19 |
20 |
21 | def test_basics(tmpdir):
22 | template_path = os.path.join("tests", "data", "example_template.pug")
23 | assert os.path.exists(template_path)
24 | pdf_path = os.path.join(str(tmpdir), "test.pdf")
25 | html = pug_to_html(template_path, title="Summary of your order")
26 | write_report(html, pdf_path)
27 | with open(pdf_path, "rb") as f:
28 | reader = PdfReader(f)
29 | assert len(reader.pages) == 2
30 |
31 | pdf_data = write_report(html)
32 | assert len(pdf_data) > 10000
33 |
34 |
35 | def test_with_plots_and_tables(tmpdir):
36 | template_path = os.path.join("tests", "data", "with_plots_and_tables.pug")
37 | assert os.path.exists(template_path)
38 |
39 | dataframe = pandas.DataFrame.from_records(
40 | {
41 | "Name": ["Anna", "Bob", "Claire", "Denis"],
42 | "Age": [12, 22, 33, 44],
43 | "Height (cm)": [140, 175, 173, 185],
44 | },
45 | columns=["Name", "Age", "Height (cm)"],
46 | )
47 |
48 | pdf_path = os.path.join(str(tmpdir), "test.pdf")
49 | html = pug_to_html(template_path, dataframe=dataframe)
50 | write_report(html, pdf_path)
51 | with open(pdf_path, "rb") as f:
52 | reader = PdfReader(f)
53 | assert len(reader.pages) == 2
54 |
55 | pdf_data = write_report(html)
56 | assert len(pdf_data) > 10000
57 |
58 |
59 | def test_preload_stylesheet(tmpdir):
60 | css = preload_stylesheet(os.path.join("tests", "data", "style.scss"))
61 | html = pug_to_html(string="p {{ var }}", var="Bla")
62 | pdf_path = os.path.join(str(tmpdir), "test.pdf")
63 | write_report(html, pdf_path, extra_stylesheets=[css])
64 |
65 |
66 | def test_ReportWriter(tmpdir):
67 | report_writer = ReportWriter(
68 | default_template=os.path.join("tests", "data", "template_rw.pug"),
69 | title="My default title",
70 | version="0.1.2",
71 | )
72 | html = report_writer.pug_to_html(my_name="Zulko", my_organization="EGF")
73 | report_writer.write_report(html, os.path.join(str(tmpdir), "test_rw.pdf"))
74 |
--------------------------------------------------------------------------------
/pdf_reports/tools.py:
--------------------------------------------------------------------------------
1 | """Utilities for report generation.
2 |
3 | The module contains in particular routines the creation of tables, plots, etc.
4 | inside the templates. Functions in this module are available from inside the
5 | templates under the domain name ``pdf_tools``. For instance
6 | ``pdf_tools.dataframe_to_html()``.
7 | """
8 |
9 | from bs4 import BeautifulSoup
10 | import base64
11 | import pandas
12 | from io import BytesIO
13 | import datetime
14 | import textwrap
15 |
16 |
17 | def dataframe_to_html(
18 | dataframe,
19 | extra_classes=(),
20 | index=False,
21 | header=True,
22 | use_default_classes=True,
23 | escape_html=False,
24 | ):
25 | """Return a HTML version of a dataframe with Semantic UI CSS style classes.
26 |
27 | By default, it applies the following Semantic UI classes:
28 | 'ui', 'compact', 'celled', 'striped', 'table', 'groups'.
29 |
30 | Parameters
31 | ----------
32 | dataframe : DataFrame
33 | The pandas dataframe to convert to HTML.
34 | extra_classes : list of str
35 | Classes to add to the default, which are 'ui', 'compact', 'celled',
36 | 'striped', 'table', 'groups', selected to create nicely-formatted
37 | Semantic UI tables. For instance, 'definition' can be added to add
38 | special emphasis on the first column. See Semantic UI documentation.
39 | index : bool
40 | Whether to display the dataframe's index.
41 | header : bool
42 | Whether to display the dataframe's headers.
43 | escape_html : bool
44 | Whether the content of the dataframe should be html-escaped. Leave to
45 | False if your dataframe contains images or any kind of HTML formatting.
46 | """
47 | default_classes = ()
48 | if use_default_classes:
49 | default_classes = (
50 | "ui",
51 | "compact",
52 | "celled",
53 | "striped",
54 | "table",
55 | "groups",
56 | )
57 | classes = default_classes + tuple(extra_classes)
58 | current_colwidth = pandas.get_option("display.max_colwidth")
59 | # pandas.set_option("display.max_colwidth", -1)
60 | result = dataframe.to_html(
61 | classes=classes, index=index, header=header, escape=escape_html
62 | )
63 | pandas.set_option("display.max_colwidth", current_colwidth)
64 | return result
65 |
66 |
67 | def style_table_rows(table_html, tr_modifier):
68 | """Return a new HTML string of the table, with rows modified.
69 |
70 | Parameters
71 | ----------
72 | table_html : str
73 | A string "
...
" of an HTML table.
74 | tr_modifier : function
75 | A function that takes a BeautifulSoup `tr` element as argument and changes its attributes inplace.
76 | For instance, modifications can be made with `tr.text = new_text`, or with the `add_css_class` method.
77 | """
78 | soup = BeautifulSoup(table_html, "html.parser")
79 | for tr in soup.find_all("tr"):
80 | tr_modifier(tr)
81 | return str(soup)
82 |
83 |
84 | def add_css_class(element, cls):
85 | """Add a given class to the given BeautifulSoup HTML element."""
86 | attrs = element.attrs
87 | new_class = (attrs["class"] + " " if "class" in attrs else "") + cls
88 | element.attrs["class"] = new_class
89 |
90 |
91 | class JupyterPDF(object):
92 | """Class to display PDFs in a Jupyter / IPython notebook.
93 |
94 | Just write this at the end of a code Cell to get in-browser PDF preview:
95 |
96 | >>> from pdf_reports import JupyterPDF
97 | >>> JupyterPDF("path_to_some.pdf")
98 |
99 | Credits to StackOverflow's Jakob: https://stackoverflow.com/a/19470377
100 | """
101 |
102 | def __init__(self, url, width=600, height=800):
103 | self.url = url
104 | self.width = width
105 | self.height = height
106 |
107 | def _repr_html_(self):
108 | return """
109 |
110 |
112 |
113 | """.format(
114 | self=self
115 | )
116 |
117 |
118 | def now(fmt="%Y-%m-%d %H:%M"):
119 | now = datetime.datetime.now()
120 | if fmt is not None:
121 | now = now.strftime(fmt)
122 | return now
123 |
124 |
125 | def figure_data(fig, size=None, fmt="png", bbox_inches="tight", **kwargs):
126 | """Return a HTML-embeddable string of the figure data.
127 |
128 | The string can be embedded in an image tag as ``.
129 |
130 | Parameters
131 | ----------
132 | fig : Matplotlib figure or axis
133 | A Matplotlib figure. A Matplotlib "ax" can also be provided, at which
134 | case the whole `ax.figure` will be displayed (i.e., all axes in the
135 | same figure).
136 | size : tuple
137 | Size or resolution (width, height) of the final figure image, in inches.
138 | fmt : str
139 | Image format, for instance "png", "svg", "jpeg". SVG is vectorial (non
140 | pixelated) but sometimes more difficult to work with inside HTML/PDF
141 | documents.
142 | bbox_inches : str
143 | Keeping this option to "tight" will ensure that your plot's delimitation
144 | is optimal.
145 | **kwargs
146 | Any other option of Matplotlib's figure.savefig() method.
147 | """
148 | if fig.__class__.__name__ == "Axes":
149 | fig = fig.figure
150 | output = BytesIO()
151 | original_size = fig.get_size_inches()
152 | if size is not None:
153 | fig.set_size_inches((int(size[0]), int(size[1])))
154 | fig.savefig(output, format=fmt, bbox_inches=bbox_inches, **kwargs)
155 | fig.set_size_inches(original_size)
156 | data = output.getvalue()
157 | # This block prevented rendering SVG in Python 3.9 / newer dependencies.
158 | # Apparently not needed anymore even for Python 3.6. In here for future reference.
159 | # if fmt == "svg":
160 | # svg_txt = data.decode()
161 | # svg_txt = "\n".join(svg_txt.split("\n")[4:])
162 | # svg_txt = "".join(svg_txt.split("\n"))
163 | # content = base64.b64encode(svg_txt.encode("utf-8"))
164 | # else:
165 | # content = base64.b64encode(data)
166 | content = base64.b64encode(data)
167 | result = b"data:image/%s+xml;base64,%s" % (fmt.encode("utf-8"), content)
168 | return result.decode("utf-8")
169 |
170 |
171 | def wrap(text, col_width):
172 | return "\n".join(textwrap.wrap(text, col_width))
173 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS = -E -a
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 | PDFBUILDDIR = /tmp
10 | PDF = manual.pdf
11 |
12 | # User-friendly check for sphinx-build
13 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
14 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
15 | endif
16 |
17 | # Internal variables.
18 | PAPEROPT_a4 = -D latex_paper_size=a4
19 | PAPEROPT_letter = -D latex_paper_size=letter
20 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
21 | # the i18n builder cannot share the environment and doctrees with the others
22 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
23 |
24 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
25 |
26 | help:
27 | @echo "Please use \`make ' where is one of"
28 | @echo " html to make standalone HTML files"
29 | @echo " dirhtml to make HTML files named index.html in directories"
30 | @echo " singlehtml to make a single large HTML file"
31 | @echo " pickle to make pickle files"
32 | @echo " json to make JSON files"
33 | @echo " htmlhelp to make HTML files and a HTML help project"
34 | @echo " qthelp to make HTML files and a qthelp project"
35 | @echo " devhelp to make HTML files and a Devhelp project"
36 | @echo " epub to make an epub"
37 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
38 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
39 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
40 | @echo " text to make text files"
41 | @echo " man to make manual pages"
42 | @echo " texinfo to make Texinfo files"
43 | @echo " info to make Texinfo files and run them through makeinfo"
44 | @echo " gettext to make PO message catalogs"
45 | @echo " changes to make an overview of all changed/added/deprecated items"
46 | @echo " xml to make Docutils-native XML files"
47 | @echo " pseudoxml to make pseudoxml-XML files for display purposes"
48 | @echo " linkcheck to check all external links for integrity"
49 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
50 |
51 | clean:
52 | rm -rf $(BUILDDIR)/*
53 |
54 | html:
55 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
56 | @echo
57 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
58 |
59 | dirhtml:
60 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
61 | @echo
62 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
63 |
64 | singlehtml:
65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
66 | @echo
67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
68 |
69 | pickle:
70 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
71 | @echo
72 | @echo "Build finished; now you can process the pickle files."
73 |
74 | json:
75 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
76 | @echo
77 | @echo "Build finished; now you can process the JSON files."
78 |
79 | htmlhelp:
80 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
81 | @echo
82 | @echo "Build finished; now you can run HTML Help Workshop with the" \
83 | ".hhp project file in $(BUILDDIR)/htmlhelp."
84 |
85 | qthelp:
86 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
87 | @echo
88 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
89 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
90 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelppdf_reports.qhcp"
91 | @echo "To view the help file:"
92 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelppdf_reports.qhc"
93 |
94 | devhelp:
95 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
96 | @echo
97 | @echo "Build finished."
98 | @echo "To view the help file:"
99 | @echo "# mkdir -p $$HOME/.local/share/devhelppdf_reports"
100 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelppdf_reports"
101 | @echo "# devhelp"
102 |
103 | epub:
104 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
105 | @echo
106 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
107 |
108 | latex:
109 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
110 | @echo
111 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
112 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
113 | "(use \`make latexpdf' here to do that automatically)."
114 |
115 | latexpdf:
116 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(PDFBUILDDIR)/latex
117 | @echo "Running LaTeX files through pdflatex..."
118 | $(MAKE) -C $(PDFBUILDDIR)/latex all-pdf
119 | cp $(PDFBUILDDIR)/latex/*.pdf $(PDF)
120 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
121 |
122 | latexpdfja:
123 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
124 | @echo "Running LaTeX files through platex and dvipdfmx..."
125 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
126 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
127 |
128 | text:
129 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
130 | @echo
131 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
132 |
133 | man:
134 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
135 | @echo
136 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
137 |
138 | texinfo:
139 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
140 | @echo
141 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
142 | @echo "Run \`make' in that directory to run these through makeinfo" \
143 | "(use \`make info' here to do that automatically)."
144 |
145 | info:
146 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
147 | @echo "Running Texinfo files through makeinfo..."
148 | make -C $(BUILDDIR)/texinfo info
149 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
150 |
151 | gettext:
152 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
153 | @echo
154 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
155 |
156 | changes:
157 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
158 | @echo
159 | @echo "The overview file is in $(BUILDDIR)/changes."
160 |
161 | linkcheck:
162 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
163 | @echo
164 | @echo "Link check complete; look for any errors in the above output " \
165 | "or in $(BUILDDIR)/linkcheck/output.txt."
166 |
167 | doctest:
168 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
169 | @echo "Testing of doctests in the sources finished, look at the " \
170 | "results in $(BUILDDIR)/doctest/output.txt."
171 |
172 | xml:
173 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
174 | @echo
175 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
176 |
177 | pseudoxml:
178 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
179 | @echo
180 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
181 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | REM Command file for Sphinx documentation
4 |
5 | if "%SPHINXBUILD%" == "" (
6 | set SPHINXBUILD=sphinx-build
7 | )
8 | set BUILDDIR=_build
9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
10 | set I18NSPHINXOPTS=%SPHINXOPTS% .
11 | if NOT "%PAPER%" == "" (
12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
14 | )
15 |
16 | if "%1" == "" goto help
17 |
18 | if "%1" == "help" (
19 | :help
20 | echo.Please use `make ^` where ^ is one of
21 | echo. html to make standalone HTML files
22 | echo. dirhtml to make HTML files named index.html in directories
23 | echo. singlehtml to make a single large HTML file
24 | echo. pickle to make pickle files
25 | echo. json to make JSON files
26 | echo. htmlhelp to make HTML files and a HTML help project
27 | echo. qthelp to make HTML files and a qthelp project
28 | echo. devhelp to make HTML files and a Devhelp project
29 | echo. epub to make an epub
30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
31 | echo. text to make text files
32 | echo. man to make manual pages
33 | echo. texinfo to make Texinfo files
34 | echo. gettext to make PO message catalogs
35 | echo. changes to make an overview over all changed/added/deprecated items
36 | echo. xml to make Docutils-native XML files
37 | echo. pseudoxml to make pseudoxml-XML files for display purposes
38 | echo. linkcheck to check all external links for integrity
39 | echo. doctest to run all doctests embedded in the documentation if enabled
40 | goto end
41 | )
42 |
43 | if "%1" == "clean" (
44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
45 | del /q /s %BUILDDIR%\*
46 | goto end
47 | )
48 |
49 |
50 | %SPHINXBUILD% 2> nul
51 | if errorlevel 9009 (
52 | echo.
53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
54 | echo.installed, then set the SPHINXBUILD environment variable to point
55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
56 | echo.may add the Sphinx directory to PATH.
57 | echo.
58 | echo.If you don't have Sphinx installed, grab it from
59 | echo.http://sphinx-doc.org/
60 | exit /b 1
61 | )
62 |
63 | if "%1" == "html" (
64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
65 | if errorlevel 1 exit /b 1
66 | echo.
67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html.
68 | goto end
69 | )
70 |
71 | if "%1" == "dirhtml" (
72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
73 | if errorlevel 1 exit /b 1
74 | echo.
75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
76 | goto end
77 | )
78 |
79 | if "%1" == "singlehtml" (
80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
81 | if errorlevel 1 exit /b 1
82 | echo.
83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
84 | goto end
85 | )
86 |
87 | if "%1" == "pickle" (
88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
89 | if errorlevel 1 exit /b 1
90 | echo.
91 | echo.Build finished; now you can process the pickle files.
92 | goto end
93 | )
94 |
95 | if "%1" == "json" (
96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
97 | if errorlevel 1 exit /b 1
98 | echo.
99 | echo.Build finished; now you can process the JSON files.
100 | goto end
101 | )
102 |
103 | if "%1" == "htmlhelp" (
104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
105 | if errorlevel 1 exit /b 1
106 | echo.
107 | echo.Build finished; now you can run HTML Help Workshop with the ^
108 | .hhp project file in %BUILDDIR%/htmlhelp.
109 | goto end
110 | )
111 |
112 | if "%1" == "qthelp" (
113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
114 | if errorlevel 1 exit /b 1
115 | echo.
116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^
117 | .qhcp project file in %BUILDDIR%/qthelp, like this:
118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\PDF Reports.qhcp
119 | echo.To view the help file:
120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\PDF Reports.ghc
121 | goto end
122 | )
123 |
124 | if "%1" == "devhelp" (
125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
126 | if errorlevel 1 exit /b 1
127 | echo.
128 | echo.Build finished.
129 | goto end
130 | )
131 |
132 | if "%1" == "epub" (
133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
134 | if errorlevel 1 exit /b 1
135 | echo.
136 | echo.Build finished. The epub file is in %BUILDDIR%/epub.
137 | goto end
138 | )
139 |
140 | if "%1" == "latex" (
141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
142 | if errorlevel 1 exit /b 1
143 | echo.
144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
145 | goto end
146 | )
147 |
148 | if "%1" == "latexpdf" (
149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
150 | cd %BUILDDIR%/latex
151 | make all-pdf
152 | cd %BUILDDIR%/..
153 | echo.
154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex.
155 | goto end
156 | )
157 |
158 | if "%1" == "latexpdfja" (
159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
160 | cd %BUILDDIR%/latex
161 | make all-pdf-ja
162 | cd %BUILDDIR%/..
163 | echo.
164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex.
165 | goto end
166 | )
167 |
168 | if "%1" == "text" (
169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
170 | if errorlevel 1 exit /b 1
171 | echo.
172 | echo.Build finished. The text files are in %BUILDDIR%/text.
173 | goto end
174 | )
175 |
176 | if "%1" == "man" (
177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
178 | if errorlevel 1 exit /b 1
179 | echo.
180 | echo.Build finished. The manual pages are in %BUILDDIR%/man.
181 | goto end
182 | )
183 |
184 | if "%1" == "texinfo" (
185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
186 | if errorlevel 1 exit /b 1
187 | echo.
188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
189 | goto end
190 | )
191 |
192 | if "%1" == "gettext" (
193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
194 | if errorlevel 1 exit /b 1
195 | echo.
196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
197 | goto end
198 | )
199 |
200 | if "%1" == "changes" (
201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
202 | if errorlevel 1 exit /b 1
203 | echo.
204 | echo.The overview file is in %BUILDDIR%/changes.
205 | goto end
206 | )
207 |
208 | if "%1" == "linkcheck" (
209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
210 | if errorlevel 1 exit /b 1
211 | echo.
212 | echo.Link check complete; look for any errors in the above output ^
213 | or in %BUILDDIR%/linkcheck/output.txt.
214 | goto end
215 | )
216 |
217 | if "%1" == "doctest" (
218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
219 | if errorlevel 1 exit /b 1
220 | echo.
221 | echo.Testing of doctests in the sources finished, look at the ^
222 | results in %BUILDDIR%/doctest/output.txt.
223 | goto end
224 | )
225 |
226 | if "%1" == "xml" (
227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
228 | if errorlevel 1 exit /b 1
229 | echo.
230 | echo.Build finished. The XML files are in %BUILDDIR%/xml.
231 | goto end
232 | )
233 |
234 | if "%1" == "pseudoxml" (
235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
236 | if errorlevel 1 exit /b 1
237 | echo.
238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
239 | goto end
240 | )
241 |
242 | :end
243 |
--------------------------------------------------------------------------------
/pdf_reports/pdf_reports.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | try:
4 | from weasyprint import HTML, CSS
5 | except (ImportError, OSError) as err:
6 | message = (
7 | "[PDF Reports] ERROR: The Weasyprint library did not load"
8 | "properly! You will not be able to generate PDF reports until"
9 | "you fix this issue.\n"
10 | )
11 |
12 | if "pango" in str(err):
13 | message += (
14 | "\nMaybe you haven't installed the Pango dependency? "
15 | "See PDF Reports install instructions in documentation.\n"
16 | )
17 | if "cairo" in str(err):
18 | message += "\nMaybe you haven't installed the Cairo dependency?\n"
19 |
20 | message += (
21 | "\nIn any other case the weasyprint docs may be able to help:\n\n"
22 | "http://weasyprint.readthedocs.io/en/stable/install.html#windows\n\n"
23 | "The original import error was %s" % (str(err))
24 | )
25 |
26 | def HTML(*args, **kwargs):
27 | """%s""" % message
28 | raise ImportError(message)
29 |
30 | CSS = HTML
31 |
32 | try:
33 | import sass
34 |
35 | LIBSASS_AVAILABLE = True
36 | except ImportError:
37 | LIBSASS_AVAILABLE = False
38 | sass = None
39 |
40 | import jinja2
41 | import tempfile
42 | import warnings
43 | from io import BytesIO
44 | from . import tools
45 |
46 |
47 | try:
48 | from functools import lru_cache
49 | except ImportError:
50 | from backports.functools_lru_cache import lru_cache
51 |
52 | THIS_PATH = os.path.dirname(os.path.realpath(__file__))
53 | SEMANTIC_UI_CSS = os.path.join(THIS_PATH, "css", "semantic.min.css")
54 | STYLESHEET = os.path.join(THIS_PATH, "css", "style.css")
55 | EGF_LOGO_URL = os.path.join(THIS_PATH, "css", "egf-logo.svg")
56 |
57 | GLOBALS = {
58 | "egf_logo_url": EGF_LOGO_URL,
59 | "list": list,
60 | "len": len,
61 | "zip": zip,
62 | "enumerate": enumerate,
63 | "pdf_tools": tools,
64 | }
65 |
66 |
67 | @lru_cache(maxsize=1)
68 | def get_semantic_ui_CSS():
69 | with warnings.catch_warnings():
70 | css = CSS(filename=SEMANTIC_UI_CSS)
71 | return css
72 |
73 |
74 | def pug_to_html(path=None, string=None, **context):
75 | """Convert a Pug template, as file or string, to html.
76 |
77 | Parameters
78 | ----------
79 | path : str, optional
80 | Path to a .pug template file. The `string` parameter can be provided instead.
81 | string : str, optional
82 | A string of a Pug template. The `path` parameter can be provided instead.
83 | **context :
84 | Keyword arguments indicating the variables to use in the Pug template
85 | (if it contains variables). For instance `title='My title'`.
86 | """
87 | default = {k: v for (k, v) in GLOBALS.items()}
88 | default.update(context)
89 | context = default
90 | if string is not None:
91 | template_path = tempfile.mktemp(suffix=".pug")
92 | with open(template_path, "w+") as f:
93 | f.write(string)
94 | if path is None:
95 | path = template_path
96 | else:
97 | template_path = path
98 | basepath, filename = os.path.split(template_path)
99 | env = jinja2.Environment(
100 | loader=jinja2.FileSystemLoader(basepath if basepath else "."),
101 | extensions=["pypugjs.ext.jinja.PyPugJSExtension"],
102 | )
103 |
104 | template = env.get_template(filename)
105 | return template.render(context)
106 |
107 |
108 | def write_report(
109 | html, target=None, base_url=None, use_default_styling=True, extra_stylesheets=()
110 | ):
111 | """Write the provided HTML in a PDF file.
112 |
113 | Parameters
114 | ----------
115 | html : str
116 | A HTML string.
117 | target : str or file-like object, optional
118 | A PDF file path or file-like object, or None for returning the raw bytes of the PDF.
119 | base_url : str
120 | The base path from which relative paths in the HTML template start.
121 | use_default_styling : bool
122 | Setting this parameter to False, your PDF will have no styling at all by default.
123 | This means no Semantic UI, which can speed up the rendering.
124 | extra_stylesheets : list of str
125 | List of paths to other ".css" files used to define new styles or overwrite default styles.
126 | """
127 | weasy_html = HTML(string=html, base_url=base_url)
128 | if use_default_styling:
129 | extra_stylesheets = tuple(extra_stylesheets)
130 | stylesheets = (
131 | get_semantic_ui_CSS(),
132 | STYLESHEET,
133 | ) + extra_stylesheets
134 | else:
135 | stylesheets = extra_stylesheets
136 | if target in [None, "@memory"]:
137 | with BytesIO() as buffer:
138 | weasy_html.write_pdf(buffer, stylesheets=stylesheets)
139 | pdf_data = buffer.getvalue()
140 | return pdf_data
141 | else:
142 | weasy_html.write_pdf(target, stylesheets=stylesheets)
143 |
144 |
145 | class ReportWriter:
146 | def __init__(
147 | self,
148 | default_stylesheets=(),
149 | default_template=None,
150 | use_default_styling=True,
151 | default_base_url=None,
152 | **default_context
153 | ):
154 |
155 | self.default_template = default_template
156 | self.default_context = default_context if default_context else {}
157 | self.default_stylesheets = default_stylesheets
158 | self.use_default_styling = use_default_styling
159 | self.default_base_url = default_base_url
160 |
161 | def pug_to_html(self, path=None, string=None, **context):
162 | """See pdf_reports.pug_to_html."""
163 | if (path is None) and (string is None):
164 | path = self.default_template
165 | for k in self.default_context:
166 | if k not in context:
167 | context[k] = self.default_context[k]
168 | return pug_to_html(path=path, string=string, **context)
169 |
170 | def write_report(self, html, target=None, extra_stylesheets=(), base_url=None):
171 | return write_report(
172 | html,
173 | target=target,
174 | extra_stylesheets=list(self.default_stylesheets) + list(extra_stylesheets),
175 | base_url=base_url if base_url else self.default_base_url,
176 | use_default_styling=self.use_default_styling,
177 | )
178 |
179 |
180 | def preload_stylesheet(path, is_scss="auto"):
181 | """Preload a stylesheet as a WeasyPrint CSS object once and for all.
182 |
183 | Returns a weasyprint.CSS object which can be provided as-is in a list of
184 | default_stylesheets or extra_stylesheets.
185 |
186 | Preloading stylesheets can save a lot of time for large CSS frameworks
187 | that are used several times. It prevents weasyprint from parsing the CSS
188 | every time.
189 |
190 | If the path ends with .scss or .sass and is_scss is set to "auto",
191 | is_scss will be set to True.
192 |
193 | If is_scss is true, the file is compiled using python-libsass (
194 | which must be installed).
195 |
196 | Note: if you already have a string, directly use ``sass.compile(s)`` to
197 | compile the string.
198 | """
199 | if is_scss == "auto" and isinstance(path, str):
200 | is_scss = path.lower().endswith((".scss", ".sass"))
201 | if hasattr(path, "read"):
202 | string = path.read()
203 | else:
204 | with open(path, "r") as f:
205 | string = f.read()
206 | if is_scss:
207 | if not LIBSASS_AVAILABLE:
208 | raise ImportError(
209 | "Cannot read scss files without python-libsass installed. "
210 | "Either install the library or provide a CSS file, or set "
211 | "is_scss to False"
212 | )
213 | string = sass.compile(string=string)
214 | return CSS(string=string)
215 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | .. raw:: html
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | .. image:: https://github.com/Edinburgh-Genome-Foundry/pdf_reports/actions/workflows/build.yml/badge.svg
10 | :target: https://github.com/Edinburgh-Genome-Foundry/pdf_reports/actions/workflows/build.yml
11 | :alt: GitHub CI build status
12 | .. image:: https://coveralls.io/repos/github/Edinburgh-Genome-Foundry/pdf_reports/badge.svg?branch=master
13 | :target: https://coveralls.io/github/Edinburgh-Genome-Foundry/pdf_reports?branch=master
14 |
15 |
16 |
17 | *PDF Reports* (complete documentation `here `_) is a Python library to create nice-looking PDF reports from HTML or `Pug `_ templates. It features modern-looking components (via the `Semantic UI `_ framework) and provides routines to embed tables or plots in the documents.
18 |
19 | Note that only Python 3.x is officially supported, although with the right version of weasyprint the library can also run on 2.x.
20 |
21 |
22 | Example of use
23 | --------------
24 |
25 | Your Pug template file ``template.pug`` may look like this (see a `full example `_):
26 |
27 | .. code:: pug
28 |
29 | #sidebar I am the text in the sidebar.
30 |
31 | h1 {{ title }}
32 |
33 | .ui.piled.segment
34 | p Oh hi there ! I am some text in a cool box.
35 |
36 | Your Python code will be as follows:
37 |
38 | .. code:: python
39 |
40 | from pdf_reports import pug_to_html, write_report
41 | html = pug_to_html("template.pug", title="My report")
42 | write_report(html, "example.pdf")
43 |
44 | And your final result may look like this (`PDF file `_):
45 |
46 | .. image:: https://github.com/Edinburgh-Genome-Foundry/pdf_reports/raw/master/screenshot.png
47 |
48 | See also `this example `_ embedding some python code in the template to
49 | create figures and tables on the flight.
50 |
51 |
52 | Other features
53 | --------------
54 |
55 |
56 | Preloading CSS and SCSS
57 | ~~~~~~~~~~~~~~~~~~~~~~~~
58 |
59 | PDF Reports provides a ``preload_stylesheet`` method which can be used to load
60 | and parse a CSS file. It also works with SCSS files (which will automatically
61 | be compiled to CSS) but this requires ``libsass`` installed (for instance via
62 | ``pip install libsass``). Here is an example:
63 |
64 | .. code:: python
65 |
66 | from pdf_reports import pug_to_html, write_report, preload_stylesheet
67 |
68 | css = preload_stylesheet('style.scss')
69 | html = pug_to_html("template.pug", title="My report", my_name='Zulko')
70 | write_report(html, "example.pdf", extra_stylesheets=[css])
71 |
72 |
73 | Using a ReportWriter
74 | ~~~~~~~~~~~~~~~~~~~~
75 |
76 | The ReportWriter class allows to define default templates, styles, and variable
77 | names. It can be used to avoid repeating yourself across your application:
78 |
79 | .. code:: python
80 |
81 | from pdf_reports import ReportWriter
82 |
83 | # DEFINE A WRITER WITH DEFAULT TEMPLATE AND VALUES
84 | report_writer = ReportWriter(
85 | default_stylesheets=["style.css"],
86 | default_template="template.pug",
87 | title="My default title",
88 | version="0.1.2"
89 | )
90 |
91 | # THEN LATER IN YOUR CODE:
92 | html = report_writer.pug_to_html(my_name="Zulko", my_organization="EGF")
93 | report_writer.write_report(html, "example_reportwriter.pdf")
94 |
95 |
96 | Markdown support
97 | ~~~~~~~~~~~~~~~~
98 |
99 | As a feature of PyPugJS, markdown is supported in the Pug templates.
100 |
101 | .. code:: pug
102 |
103 | div
104 | :markdown
105 | This is some markdown text. Here is a [link](http://example.com/).
106 |
107 | - this is a bullet point list
108 | - Second item
109 | - Etc.
110 |
111 |
112 | PDF tools
113 | ~~~~~~~~~
114 |
115 | Some useful functions for generating reports are available from inside the
116 | Pug templates under ``pdf_tools``. For instance, ``pdf_tools.figure_data()``
117 | to embed matplotlib images, or ``pdf_tools.dataframe_to_html()``
118 | to turn Pandas dataframes into HTML, and style them nicely with Semantic UI.
119 | Have a look at the docs, or this
120 | `example `_.
121 |
122 |
123 | JupyterPDF
124 | ~~~~~~~~~~
125 |
126 | The ``JupyterPDF`` class eases report templates writing by embedding PDF files
127 | in Jupyter notebooks (using the browser's interactive PDF viewer).
128 |
129 | .. code:: python
130 |
131 | from pdf_reports import JupyterPDF
132 |
133 | # Build your PDF
134 |
135 | # At the end of the notebook cell:
136 | JupyterPDF("path_to_your.pdf")
137 |
138 |
139 | Notes
140 | -----
141 |
142 | The core of the library consists of just a few lines of Python, using `pypugjs `_ to parse Pug templates, optionally including stylesheets from the Semantic UI CSS framework, and finally calling `weasyprint `_ for PDF generation. Please refer to the Weasyprint documentation for the customization of templates. For instance, to customize the page margins and numbering the Weasyprint way, add this to your SCSS code:
143 |
144 | .. code:: scss
145 |
146 | @page {
147 | margin: 1cm 0 2cm 0cm;
148 | @bottom-center {
149 | content: "Page " counter(page) " / " counter(pages);
150 | font-family: 'Lato';
151 | }
152 | }
153 |
154 |
155 | Using Semantic UI implies that (1) the Lato font family should be installed on your machine, otherwise the results will look less good, and (2) the first time that ``write_pdf`` is called in a Python session, if using the default Semantic UI style, the parsing of the CSS will add a 3-second overhead to the function calls (but there will be no overhead for the next calls in that session).
156 |
157 |
158 | Installation
159 | ------------
160 |
161 | You can install the library via PIP:
162 |
163 | .. code::
164 |
165 | pip install pdf_reports
166 |
167 | Alternatively, you can unzip the sources in a folder and type:
168 |
169 | .. code::
170 |
171 | python setup.py install
172 |
173 | **Note:** the package depends on the WeasyPrint Python package. If there are any issues,
174 | see installation instructions in the `WeasyPrint documentation `_.
175 |
176 | If Pango is not available in your conda environment (``which pango-view``), but otherwise it's installed, then install it with ``conda install anaconda::pango``
177 |
178 |
179 | PDF Reports has been tested on Ubuntu 22.04. If you have an older GNU/Linux distribution (e.g. Ubuntu 18.04) which
180 | doesn't have the latest Pango that is required by the latest WeasyPrint, then installing an older WeasyPrint (<=52) may help: ``pip install weasyprint==52``
181 |
182 | **Note: on some Debian systems** you may need to first install ``libffi-dev`` (``apt install libffi-dev``). The package name may be ``libffi-devel`` on some systems.
183 |
184 | **Note: on macOS,** you may need to first install pango with: ``brew install pango``
185 |
186 |
187 | License = MIT
188 | -------------
189 |
190 | This open-source software project was originally written at the `Edinburgh Genome Foundry `_ by `Zulko `_
191 | and `released on Github `_ under the MIT licence (Copyright 2018 Edinburgh Genome Foundry, University of Edinburgh). Everyone is welcome to contribute !
192 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # PDF Reports documentation build configuration file, created by
4 | # sphinx-quickstart on Sat Jul 13 14:47:48 2013.
5 | #
6 | # This file is execfile()d with the current directory set to its containing dir.
7 | #
8 | # Note that not all possible configuration values are present in this
9 | # autogenerated file.
10 | #
11 | # All configuration values have a default; values that are commented out
12 | # serve to show the default.
13 |
14 | import sys, os
15 | import pdf_reports
16 |
17 | sys.path.insert(0, os.path.abspath("../pdf_reports/"))
18 |
19 | # If extensions (or modules to document with autodoc) are in another directory,
20 | # add these directories to sys.path here. If the directory is relative to the
21 | # documentation root, use os.path.abspath to make it absolute, like shown here.
22 | # sys.path.insert(0, os.path.abspath('.'))
23 |
24 | # -- General configuration -----------------------------------------------------
25 |
26 | # If your documentation needs a minimal Sphinx version, state it here.
27 | # needs_sphinx = '1.0'
28 |
29 | # Add any Sphinx extension module names here, as strings. They can be extensions
30 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
31 | extensions = [
32 | "sphinx.ext.autodoc",
33 | "sphinx.ext.todo",
34 | "sphinx.ext.viewcode",
35 | "sphinx.ext.napoleon",
36 | # "numpydoc",
37 | "sphinxcontrib.mermaid",
38 | ]
39 | napoleon_numpy_docstring = True
40 | numpydoc_show_class_members = False
41 | # Add any paths that contain templates here, relative to this directory.
42 | templates_path = ["_templates"]
43 |
44 | # The suffix of source filenames.
45 | source_suffix = [".rst"]
46 |
47 | # The encoding of source files.
48 | # source_encoding = 'utf-8-sig'
49 |
50 | # The master toctree document.
51 | master_doc = "index"
52 |
53 | # General information about the project.
54 | project = "PDF Reports"
55 | copyright = "2018 Edinburgh Genome Foundry, University of Edinburgh"
56 |
57 | # The version info for the project you're documenting, acts as replacement for
58 | # |version| and |release|, also used in various other places throughout the
59 | # built documents.
60 | #
61 | # The short X.Y version.
62 | version = pdf_reports.__version__
63 | # The full version, including alpha/beta/rc tags.
64 | release = pdf_reports.__version__
65 |
66 | # The language for content autogenerated by Sphinx. Refer to documentation
67 | # for a list of supported languages.
68 | # language = None
69 |
70 | # There are two options for replacing |today|: either, you set today to some
71 | # non-false value, then it is used:
72 | # today = ''
73 | # Else, today_fmt is used as the format for a strftime call.
74 | # today_fmt = '%B %d, %Y'
75 |
76 | # List of patterns, relative to source directory, that match files and
77 | # directories to ignore when looking for source files.
78 | exclude_patterns = ["_build"]
79 |
80 | # The reST default role (used for this markup: `text`) to use for all documents.
81 | # default_role = None
82 |
83 | # If true, '()' will be appended to :func: etc. cross-reference text.
84 | # add_function_parentheses = True
85 |
86 | # If true, the current module name will be prepended to all description
87 | # unit titles (such as .. function::).
88 | # add_module_names = True
89 |
90 | # If true, sectionauthor and moduleauthor directives will be shown in the
91 | # output. They are ignored by default.
92 | # show_authors = False
93 |
94 | # A list of ignored prefixes for module index sorting.
95 | # modindex_common_prefix = []
96 |
97 | # If true, keep warnings as "system message" paragraphs in the built documents.
98 | # keep_warnings = False
99 |
100 |
101 | # -- Options for HTML output ---------------------------------------------------
102 |
103 | # The theme to use for HTML and HTML Help pages. See the documentation for
104 | # a list of builtin themes.
105 |
106 | on_rtd = os.environ.get("READTHEDOCS", None) == "True"
107 |
108 | if not on_rtd: # only import and set the theme if we're building docs locally
109 | import sphinx_rtd_theme
110 |
111 | html_theme = "sphinx_rtd_theme"
112 |
113 | def setup(app):
114 | app.add_css_file("css/main.css")
115 |
116 | else:
117 | html_context = {
118 | "css_files": [
119 | "https://media.readthedocs.org/css/sphinx_rtd_theme.css",
120 | "https://media.readthedocs.org/css/readthedocs-doc-embed.css",
121 | "_static/css/main.css",
122 | ],
123 | }
124 | # sys.path.append(os.path.abspath('_themes'))
125 | # Theme options are theme-specific and customize the look and feel of a theme
126 | # further. For a list of options available for each theme, see the
127 | # documentation.
128 | # html_theme_options = {}
129 |
130 | # Add any paths that contain custom themes here, relative to this directory.
131 | # html_theme_path = []
132 |
133 | # The name for this set of Sphinx documents. If None, it defaults to
134 | # " v documentation".
135 | # html_title = None
136 |
137 | # A shorter title for the navigation bar. Default is the same as html_title.
138 | # html_short_title = None
139 |
140 | # The name of an image file (relative to this directory) to place at the top
141 | # of the sidebar.
142 | html_logo = "_static/images/html_logo.png"
143 |
144 | # The name of an image file (within the static path) to use as favicon of the
145 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
146 | # pixels large.
147 | # html_favicon = None
148 |
149 | # Add any paths that contain custom static files (such as style sheets) here,
150 | # relative to this directory. They are copied after the builtin static files,
151 | # so a file named "default.css" will overwrite the builtin "default.css".
152 | html_static_path = ["_static"]
153 |
154 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
155 | # using the given strftime format.
156 | # html_last_updated_fmt = '%b %d, %Y'
157 |
158 | # If true, SmartyPants will be used to convert quotes and dashes to
159 | # typographically correct entities.
160 | # html_use_smartypants = True
161 |
162 | # Custom sidebar templates, maps document names to template names.
163 | # html_sidebars = {}
164 |
165 | # Additional templates that should be rendered to pages, maps page names to
166 | # template names.
167 | # html_additional_pages = {}
168 |
169 | # If false, no module index is generated.
170 | # html_domain_indices = True
171 |
172 | # If false, no index is generated.
173 | # html_use_index = True
174 |
175 | # If true, the index is split into individual pages for each letter.
176 | # html_split_index = False
177 |
178 | # If true, links to the reST sources are added to the pages.
179 | # html_show_sourcelink = True
180 |
181 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
182 | # html_show_sphinx = True
183 |
184 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
185 | # html_show_copyright = True
186 |
187 | # If true, an OpenSearch description file will be output, and all pages will
188 | # contain a tag referring to it. The value of this option must be the
189 | # base URL from which the finished HTML is served.
190 | # html_use_opensearch = ''
191 |
192 | # This is the file name suffix for HTML files (e.g. ".xhtml").
193 | # html_file_suffix = None
194 |
195 | # Output file base name for HTML help builder.
196 | htmlhelp_basename = "PDF Reportsdoc"
197 |
198 |
199 | # -- Options for LaTeX output --------------------------------------------------
200 |
201 | latex_elements = {
202 | # The paper size ('letterpaper' or 'a4paper').
203 | #'papersize': 'letterpaper',
204 | # The font size ('10pt', '11pt' or '12pt').
205 | #'pointsize': '10pt',
206 | # Additional stuff for the LaTeX preamble.
207 | #'preamble': '',
208 | }
209 |
210 | # Grouping the document tree into LaTeX files. List of tuples
211 | # (source start file, target name, title, author, documentclass [howto/manual]).
212 | latex_documents = [
213 | ("index", "PDF Reports.tex", "PDF Reports Documentation", "Zulko", "manual"),
214 | ]
215 |
216 | # The name of an image file (relative to this directory) to place at the top of
217 | # the title page.
218 | # latex_logo = None
219 |
220 | # For "manual" documents, if this is true, then toplevel headings are parts,
221 | # not chapters.
222 | # latex_use_parts = False
223 |
224 | # If true, show page references after internal links.
225 | # latex_show_pagerefs = False
226 |
227 | # If true, show URL addresses after external links.
228 | # latex_show_urls = False
229 |
230 | # Documents to append as an appendix to all manuals.
231 | # latex_appendices = []
232 |
233 | # If false, no module index is generated.
234 | # latex_domain_indices = True
235 |
236 |
237 | # -- Options for manual page output --------------------------------------------
238 |
239 | # One entry per manual page. List of tuples
240 | # (source start file, name, description, authors, manual section).
241 | man_pages = [("index", "PDF Reports", "PACKAGE_NAME Documentation", ["Zulko"], 1)]
242 |
243 | # If true, show URL addresses after external links.
244 | # man_show_urls = False
245 |
246 |
247 | # -- Options for Texinfo output ------------------------------------------------
248 |
249 | # Grouping the document tree into Texinfo files. List of tuples
250 | # (source start file, target name, title, author,
251 | # dir menu entry, description, category)
252 | texinfo_documents = [
253 | (
254 | "index",
255 | "PDF Reports",
256 | "PDF Reports Documentation",
257 | "Zulko",
258 | "PDF Reports",
259 | "One line description of project.",
260 | "Miscellaneous",
261 | ),
262 | ]
263 |
264 | # Documents to append as an appendix to all manuals.
265 | # texinfo_appendices = []
266 |
267 | # If false, no module index is generated.
268 | # texinfo_domain_indices = True
269 |
270 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
271 | # texinfo_show_urls = 'footnote'
272 |
273 | # If true, do not generate a @detailmenu in the "Top" node's menu.
274 | # texinfo_no_detailmenu = False
275 |
276 |
277 | # -- Options for Epub output ---------------------------------------------------
278 |
279 | # Bibliographic Dublin Core info.
280 | epub_title = "PDF Reports"
281 | epub_author = "Zulko"
282 | epub_publisher = "Zulko"
283 | epub_copyright = "2016, Zulko"
284 |
285 | # The language of the text. It defaults to the language option
286 | # or en if the language is not set.
287 | # epub_language = ''
288 |
289 | # The scheme of the identifier. Typical schemes are ISBN or URL.
290 | # epub_scheme = ''
291 |
292 | # The unique identifier of the text. This can be a ISBN number
293 | # or the project homepage.
294 | # epub_identifier = ''
295 |
296 | # A unique identification for the text.
297 | # epub_uid = ''
298 |
299 | # A tuple containing the cover image and cover page html template filenames.
300 | # epub_cover = ()
301 |
302 | # A sequence of (type, uri, title) tuples for the guide element of content.opf.
303 | # epub_guide = ()
304 |
305 | # HTML files that should be inserted before the pages created by sphinx.
306 | # The format is a list of tuples containing the path and title.
307 | # epub_pre_files = []
308 |
309 | # HTML files shat should be inserted after the pages created by sphinx.
310 | # The format is a list of tuples containing the path and title.
311 | # epub_post_files = []
312 |
313 | # A list of files that should not be packed into the epub file.
314 | # epub_exclude_files = []
315 |
316 | # The depth of the table of contents in toc.ncx.
317 | # epub_tocdepth = 3
318 |
319 | # Allow duplicate toc entries.
320 | # epub_tocdup = True
321 |
322 | # Fix unsupported image types using the PIL.
323 | # epub_fix_images = False
324 |
325 | # Scale large images.
326 | # epub_max_image_width = 0
327 |
328 | # If 'no', URL addresses will not be shown.
329 | # epub_show_urls = 'inline'
330 |
331 | # If false, no index is generated.
332 | # epub_use_index = True
333 |
334 | # autodoc_member_order = 'bysource'
335 |
--------------------------------------------------------------------------------
/pdf_reports/css/egf-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
184 |
--------------------------------------------------------------------------------