Skip to content
Open
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
40c08bd
Enable sphinx.ext.doctest extension
ievgen-kapinos Oct 27, 2025
0a8e021
Replace python basic blocks with testcode directive in *.md files
ievgen-kapinos Oct 27, 2025
6d16058
Add new CI step
ievgen-kapinos Oct 27, 2025
063950f
Fix typo
ievgen-kapinos Oct 27, 2025
a8a2a18
removed unnesessary arguments form new CI step
ievgen-kapinos Oct 27, 2025
4b42e33
Fixed first 30 tests
ievgen-kapinos Oct 29, 2025
5d46e69
Fix CI
ievgen-kapinos Oct 29, 2025
497c6e2
Fix CI #2
ievgen-kapinos Oct 29, 2025
50aa2ab
Removed garbage
ievgen-kapinos Oct 29, 2025
a2d191b
run doctest from root
ievgen-kapinos Oct 29, 2025
485d6d3
Remove garbage
ievgen-kapinos Oct 29, 2025
5885cbd
Fix in path
ievgen-kapinos Oct 29, 2025
8dbfc4a
Remove garbage again
ievgen-kapinos Oct 29, 2025
36c97d0
re-fix
ievgen-kapinos Oct 29, 2025
5c1ba4d
Run Sphinx in docs directory
ievgen-kapinos Oct 30, 2025
748b2cd
Added comments above skipped test
ievgen-kapinos Oct 30, 2025
24409ba
Remove garbage
ievgen-kapinos Oct 30, 2025
4799520
Remove garbage
ievgen-kapinos Oct 30, 2025
bee4ca7
Replaced ../resources/side-by-side-subfig.pdf with self created exam…
ievgen-kapinos Oct 30, 2025
2f67992
Fixed 7 test in user/merging-pdfs
ievgen-kapinos Oct 30, 2025
01ff206
Fix 2 tests in docs\user\handle-attachments.md
ievgen-kapinos Oct 30, 2025
c816752
Fix more errors in docs\user\extract-text.md
ievgen-kapinos Oct 30, 2025
53975f1
Normalize
ievgen-kapinos Oct 30, 2025
f4f680d
less spaces
ievgen-kapinos Oct 30, 2025
bd09de3
Fix errors in docs\user\extract-images.md
ievgen-kapinos Oct 30, 2025
00a7f11
Fix tests in docs\user\cropping-and-transforming.md
ievgen-kapinos Oct 30, 2025
f2884d8
Fix user/adding-pdf-annotations
ievgen-kapinos Oct 30, 2025
b81f29d
Fix errors in docs\user\add-watermark.md
ievgen-kapinos Oct 30, 2025
a94a2b2
Fix last tests
ievgen-kapinos Oct 30, 2025
996366c
Polishing
ievgen-kapinos Oct 30, 2025
e8afc04
Polising
ievgen-kapinos Oct 30, 2025
cb7f018
Polishing
ievgen-kapinos Oct 30, 2025
f7a4337
Polishing
ievgen-kapinos Oct 30, 2025
eea1223
Polishing
ievgen-kapinos Oct 30, 2025
e4afcc3
Merge remote-tracking branch 'origin/main' into iss-2610-doctest-via-…
ievgen-kapinos Oct 30, 2025
65ce130
Move output files to directory ignored by git
ievgen-kapinos Oct 31, 2025
1ec3d7f
Simplified writer.write(...) call
ievgen-kapinos Oct 31, 2025
75ca54f
Added unique output file names
ievgen-kapinos Oct 31, 2025
1546a14
Polishing
ievgen-kapinos Oct 31, 2025
a530f11
Removed revative filenames
ievgen-kapinos Oct 31, 2025
9e7083e
Added new docs
ievgen-kapinos Nov 1, 2025
62792f2
Polishing
ievgen-kapinos Nov 1, 2025
2c58519
polishing
ievgen-kapinos Nov 1, 2025
cd9a5eb
polishing
ievgen-kapinos Nov 1, 2025
5d11a51
Pilishing
ievgen-kapinos Nov 1, 2025
6bac8c3
Polishing
ievgen-kapinos Nov 1, 2025
2035c50
polishing
ievgen-kapinos Nov 1, 2025
691ba58
Deleted garbage
ievgen-kapinos Nov 1, 2025
7d5d9e5
Fix formatting in docs\user\merging-pdfs.md
ievgen-kapinos Nov 1, 2025
79185c4
Corrections after PR review
ievgen-kapinos Nov 3, 2025
48f9833
Corrections after PR review
ievgen-kapinos Nov 4, 2025
e586c79
Moved each tested file in own sub-folder
ievgen-kapinos Nov 4, 2025
7ebf235
droppped nup-source.pdf
ievgen-kapinos Nov 4, 2025
2a69f06
Removed file prefix. Applied common
ievgen-kapinos Nov 4, 2025
97bd980
removed index from out prefix
ievgen-kapinos Nov 4, 2025
540c13b
Polishing
ievgen-kapinos Nov 4, 2025
4bd5a14
Added description for pypdf_test_setup function
ievgen-kapinos Nov 5, 2025
a41917e
Code review fixes
ievgen-kapinos Nov 5, 2025
9cefe93
Merge branch 'main' into iss-2610-doctest-via-sphinx
ievgen-kapinos Nov 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .github/workflows/github-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,17 @@ jobs:
- name: Test with mypy
run : |
mypy pypdf
- name: Test docs build
- name: Install docs requirements
run: |
pip install -r requirements/docs.txt
sphinx-build --nitpicky --fail-on-warning --keep-going --show-traceback --builder html docs build/sphinx/html
- name: Test docs build
working-directory: ./docs
run: |
sphinx-build --nitpicky --fail-on-warning --keep-going --show-traceback -d _build/doctrees --builder html . _build/html
- name: Test docs examples
working-directory: ./docs
run: |
sphinx-build -d _build/doctrees --builder doctest . _build/doctest
- name: Check with pre-commit
run: |
pip install -r requirements/dev.txt
Expand Down
29 changes: 29 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# documentation root, use os.path.abspath to make it absolute, like shown here.
import datetime
import os
import pathlib
import shutil
import sys

Expand Down Expand Up @@ -53,6 +54,7 @@
"sphinx.ext.mathjax",
"sphinx.ext.viewcode",
"sphinx.ext.napoleon",
"sphinx.ext.doctest",
# External
"myst_parser",
]
Expand Down Expand Up @@ -132,3 +134,30 @@
napoleon_numpy_docstring = False # Explicitly prefer Google style docstring
napoleon_use_param = True # for type hint support
napoleon_use_rtype = False # False, so the return type is inline with the description.

# -- Options for Doctest ------------------------------------------------------

# Most of doc examples use hardcoded input and output file names.
# To execute these examples real files need to be read and written.
#
# By default, documentation examples run with the working directory set to where
# "sphinx-build" command was invoked. To avoid relative paths in docs and to
# allow to run "sphinx-build" command from any directory, we modify the current
# working directory in each tested file. Tests are executed against our
# temporary directory where we have copied all nessesary resources.

pypdf_test_dir = os.path.abspath("_build/doctest/pypdf_test")
if pathlib.Path(pypdf_test_dir).exists():
shutil.rmtree(pypdf_test_dir)
shutil.copytree("../resources", pypdf_test_dir)
shutil.copy("user/nup-source.png", pypdf_test_dir)

doctest_global_setup = f"""
import os as pypdf_test_os
pypdf_orig_dir = pypdf_test_os.getcwd()
pypdf_test_os.chdir({pypdf_test_dir.__repr__()})
"""

doctest_global_cleanup = """
pypdf_test_os.chdir(pypdf_orig_dir)
"""
37 changes: 37 additions & 0 deletions docs/dev/documentation.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,42 @@
# Documentation

This documentation is build with [Sphinx](https://www.sphinx-doc.org/) and
hosted by [Read the Docs](https://about.readthedocs.com/)

## Testing code snippets

Almost all python code snippets in documentation tested using Sphinx's extension
[sphinx.ext.doctest](https://www.sphinx-doc.org/en/master/usage/extensions/doctest.html).
This allows to make sure that we have no typos, missed imports and other problems in:
- code snippets marked with `testcode` directive in `*.md` files
- code snippets from python's docstrings imported via `autoclass` directive in `*.rst` files

CI pipeline is configured run Sphinx's `doctest` build automatically for each PR.
It is also possible to run it locally:

1. First you need to install docs requirements

```bash
pip install -r requirements/docs.txt
```

2. Change current directory

```bash
cd docs
```

3. Run `doctest` build. It uses indirectly `sphinx-build` command line tool
installed with docs requrements. See
[Sphinx's docs](https://www.sphinx-doc.org/en/master/usage/quickstart.html#running-the-build)
for details.

```bash
make doctest
```

4. If everything is okay you should see in output `Doctest summary` without failures

## API Reference

### Method / Function Docstrings
Expand Down
6 changes: 2 additions & 4 deletions docs/modules/PaperSize.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ Add blank page with PaperSize

writer = PdfWriter(clone_from="sample.pdf")
writer.add_blank_page(PaperSize.A8.width, PaperSize.A8.height)
with open("output.pdf", "wb") as output_stream:
writer.write(output_stream)
writer.write("paper-size-add-page.pdf")

Insert blank page with PaperSize
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -27,5 +26,4 @@ Insert blank page with PaperSize

writer = PdfWriter(clone_from="sample.pdf")
writer.insert_blank_page(PaperSize.A8.width, PaperSize.A8.height, 1)
with open("output.pdf", "wb") as output_stream:
writer.write(output_stream)
writer.write("paper-size-insert-size.pdf")
6 changes: 2 additions & 4 deletions docs/user/add-javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@ Adobe has documentation on its support here:

## Launch print window on opening

```python
```{testcode}
from pypdf import PdfWriter

writer = PdfWriter(clone_from="example.pdf")

# Add JavaScript to launch the print window on opening this PDF.
writer.add_js("this.print({bUI:true,bSilent:false,bShrinkToFit:true});")

# Write to pypdf-output.pdf.
with open("pypdf-output.pdf", "wb") as fp:
writer.write(fp)
writer.write("add-javascript.pdf")
```
19 changes: 9 additions & 10 deletions docs/user/add-watermark.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ The process of stamping and watermarking is the same, you just need to set `over

You can use {func}`~pypdf._page.PageObject.merge_page` if you don't need to transform the stamp:

```python
```{testcode}
from pypdf import PdfReader, PdfWriter

stamp = PdfReader("bg.pdf").pages[0]
writer = PdfWriter(clone_from="source.pdf")
stamp = PdfReader("jpeg.pdf").pages[0]
writer = PdfWriter(clone_from="crazyones.pdf")
for page in writer.pages:
page.merge_page(stamp, over=False) # here set to False for watermarking

writer.write("out.pdf")
writer.write("add-watermark-underlay.pdf")
```

Otherwise use {func}`~pypdf._page.PageObject.merge_transformed_page` with {class}`~pypdf.Transformation` if you need to translate, rotate, scale, etc. the stamp before merging it to the content page.

```python
```{testcode}
from pathlib import Path
from typing import List, Union

Expand Down Expand Up @@ -52,7 +52,7 @@ def stamp(
writer.write(pdf_result)


stamp("example.pdf", "stamp.pdf", "out.pdf")
stamp("crazyones.pdf", "jpeg.pdf", "add-watermark-transform.pdf")
```

If you are experiencing wrongly rotated watermarks/stamps, try to use
Expand All @@ -73,7 +73,7 @@ However, you can easily convert an image to PDF image using
[Pillow](https://pypi.org/project/Pillow/).


```python
```{testcode}
from io import BytesIO
from pathlib import Path
from typing import List, Union
Expand Down Expand Up @@ -111,9 +111,8 @@ def stamp_img(
Transformation(),
)

with open(pdf_result, "wb") as fp:
writer.write(fp)
writer.write(pdf_result)


stamp_img("example.pdf", "example.png", "out.pdf")
stamp_img("crazyones.pdf", "nup-source.png", "add-watermark-direct.pdf")
```
Loading
Loading