|
14 | 14 | import os |
15 | 15 | import shutil |
16 | 16 | import sys |
| 17 | +from pathlib import Path |
17 | 18 |
|
18 | 19 | sys.path.insert(0, os.path.abspath(".")) |
19 | 20 | sys.path.insert(0, os.path.abspath("../")) |
|
53 | 54 | "sphinx.ext.mathjax", |
54 | 55 | "sphinx.ext.viewcode", |
55 | 56 | "sphinx.ext.napoleon", |
| 57 | + "sphinx.ext.doctest", |
56 | 58 | # External |
57 | 59 | "myst_parser", |
58 | 60 | ] |
|
132 | 134 | napoleon_numpy_docstring = False # Explicitly prefer Google style docstring |
133 | 135 | napoleon_use_param = True # for type hint support |
134 | 136 | napoleon_use_rtype = False # False, so the return type is inline with the description. |
| 137 | + |
| 138 | +# -- Options for Doctest ------------------------------------------------------ |
| 139 | + |
| 140 | +# Most of doc examples use hardcoded input and output file names. |
| 141 | +# To execute these examples real files need to be read and written. |
| 142 | +# |
| 143 | +# By default, documentation examples run with the working directory set to where |
| 144 | +# "sphinx-build" command was invoked. To avoid relative paths in docs and to |
| 145 | +# allow to run "sphinx-build" command from any directory, we modify the current |
| 146 | +# working directory in each tested file. Tests are executed against our |
| 147 | +# temporary directory where we have copied all nessesary resources. |
| 148 | +# |
| 149 | +# Each doc page that requires file operations must use "testsetup" directive |
| 150 | +# to call "pypdf_test_setup" function to prepare the test environment for that |
| 151 | +# page. |
| 152 | +# |
| 153 | +# def pypdf_test_setup(group: str, resources: dict[str, str] = {}) -> None |
| 154 | +# |
| 155 | +# Args: |
| 156 | +# group: A unique name for group of tests. Typically we group tests by doc page. |
| 157 | +# For each doc page we create a test folder under |
| 158 | +# "_build/doctest/pypdf_test/<group>". This allows to avoid file name conflicts |
| 159 | +# between different doc pages. |
| 160 | +# resources: A dictionary of source files to copy into the test folder. |
| 161 | +# Key is the destination file name (relative to the test folder). |
| 162 | +# Value is the source file path (relative to the root folder). |
| 163 | +# |
| 164 | +# Examples: |
| 165 | +# ```{testsetup} |
| 166 | +# pypdf_test_setup("user/add-javascript", { |
| 167 | +# "example.pdf": "../resources/example.pdf", |
| 168 | +# }) |
| 169 | +# ``` |
| 170 | + |
| 171 | +pypdf_test_src_root_dir = os.path.abspath(".") |
| 172 | +pypdf_test_dst_root_dir = os.path.abspath("_build/doctest/pypdf_test") |
| 173 | +if Path(pypdf_test_dst_root_dir).exists(): |
| 174 | + shutil.rmtree(pypdf_test_dst_root_dir) |
| 175 | +Path(pypdf_test_dst_root_dir).mkdir(parents=True) |
| 176 | + |
| 177 | +doctest_global_setup = f""" |
| 178 | +def pypdf_test_global_setup(): |
| 179 | + import os |
| 180 | + import shutil |
| 181 | + from pathlib import Path |
| 182 | +
|
| 183 | + src_root_dir = {pypdf_test_src_root_dir.__repr__()} |
| 184 | + dst_root_dir = {pypdf_test_dst_root_dir.__repr__()} |
| 185 | +
|
| 186 | + global pypdf_test_orig_dir |
| 187 | + pypdf_test_orig_dir = os.getcwd() |
| 188 | + os.chdir(dst_root_dir) |
| 189 | +
|
| 190 | + global pypdf_test_setup |
| 191 | + def pypdf_test_setup(group: str, resources: dict[str, str] = {{}}) -> None: |
| 192 | + dst_dir = os.path.join(dst_root_dir, group) |
| 193 | + Path(dst_dir).mkdir(parents=True) |
| 194 | + os.chdir(dst_dir) |
| 195 | +
|
| 196 | + for (dst_path, src_path) in resources.items(): |
| 197 | + src = os.path.normpath(os.path.join(src_root_dir, src_path)) |
| 198 | + dst = os.path.join(dst_dir, dst_path) |
| 199 | +
|
| 200 | + shutil.copyfile(src, dst) |
| 201 | +
|
| 202 | +pypdf_test_global_setup() |
| 203 | +""" |
| 204 | + |
| 205 | +doctest_global_cleanup = f""" |
| 206 | +def pypdf_test_global_cleanup(): |
| 207 | + import os |
| 208 | +
|
| 209 | + dst_root_dir = {pypdf_test_dst_root_dir.__repr__()} |
| 210 | +
|
| 211 | + os.chdir(pypdf_test_orig_dir) |
| 212 | +
|
| 213 | + has_files = False |
| 214 | + for name in os.listdir(dst_root_dir): |
| 215 | + file_name = os.path.join(dst_root_dir, name) |
| 216 | + if os.path.isfile(file_name): |
| 217 | + if not has_files: |
| 218 | + print("Docs page was not configured propery for running code examples") |
| 219 | + print("Please use 'pypdf_test_setup' function in 'testsetup' directive") |
| 220 | + print("Deleting unexpected file(s) in " + dst_root_dir) |
| 221 | + has_files = True |
| 222 | + print(f"- {{name}}") |
| 223 | + os.remove(file_name) # Avoid side effects on other tests |
| 224 | +
|
| 225 | +pypdf_test_global_cleanup() |
| 226 | +""" |
0 commit comments