Skip to content

Commit

Permalink
Merge branch 'gradient' of https://github.com/andersonhc/fpdf2 into g…
Browse files Browse the repository at this point in the history
…radient
  • Loading branch information
andersonhc committed Dec 24, 2024
2 parents fc9acfd + e432f98 commit 16c3404
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 66 deletions.
185 changes: 123 additions & 62 deletions .github/workflows/continuous-integration-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,66 @@ on: # cf. https://github.community/t/how-to-trigger-an-action-on-push-or-pull-r
- master

jobs:
check-reference-pdf-files:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v4
- name: Set up Python 3.13 🔧
uses: actions/setup-python@v5
with:
python-version: 3.13
- name: Install system dependencies ⚙️
run: sudo apt-get update --allow-releaseinfo-change && sudo apt-get install qpdf
- name: Check all PDF reference files used in tests ☑
run: |
# Using qpdf
find . -name '*.pdf' | xargs -n 1 sh -c 'qpdf --check --password=fpdf2 $0 || exit 255'
export PYTHONPATH=$PWD
# Using VeraPDF:
scripts/install-verapdf.sh
scripts/verapdf.py --process-all-test-pdf-files
scripts/verapdf.py --print-aggregated-report
# Using Datalogics PDF Checker:
scripts/install-pdfchecker.sh
scripts/pdfchecker.py --process-all-test-pdf-files
scripts/pdfchecker.py --print-aggregated-report
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v4
- name: Set up Python 3.13 🔧
uses: actions/setup-python@v5
with:
python-version: 3.13
- name: Install Python dependencies ⚙️
run: |
python -m pip install --upgrade pip setuptools wheel
pip install --upgrade . -r test/linters-requirements.txt -r test/requirements.txt
- name: Run linters 🔎
run: |
black --check .
pylint fpdf test tutorial/tuto*.py
bandit -c .banditrc.yml -r contributors/ fpdf/ tutorial/
semgrep scan --config auto --error --strict --exclude-rule=python.lang.security.insecure-hash-function.insecure-hash-function fpdf
- name: Scan project with grype 🔎
uses: anchore/scan-action@v3
with:
path: "."
fail-build: true
- name: Scan project dependencies with guarddog 🐶
run: |
pip install guarddog
# Scanning direct dependencies:
guarddog pypi scan defusedxml
guarddog pypi scan Pillow
guarddog pypi scan fonttools
# Scanning dev dependencies:
guarddog pypi verify contributors/requirements.txt
guarddog pypi verify docs/requirements.txt
guarddog pypi verify test/linters-requirements.txt
guarddog pypi verify test/requirements.txt
test:
strategy:
matrix:
Expand All @@ -17,51 +77,24 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout 🛎️
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }} 🔧
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install system dependencies ⚙️
if: matrix.platform == 'ubuntu-latest'
run: sudo apt-get update --allow-releaseinfo-change && sudo apt-get install ghostscript libjpeg-dev
# Ghostscript is needed for test/table/test_table_extraction.py
run: sudo apt-get update --allow-releaseinfo-change && sudo apt-get install ghostscript
- name: Install qpdf ⚙️
if: matrix.platform == 'ubuntu-latest' && matrix.python-version != '3.9'
# We run the unit tests WITHOUT qpdf for a single parallel execution / Python version:
if: matrix.platform == 'ubuntu-latest' && matrix.python-version != '3.13'
run: sudo apt-get update --allow-releaseinfo-change && sudo apt-get install qpdf
- name: Install Python dependencies ⚙️
run: |
python -m pip install --upgrade pip setuptools wheel
pip install --upgrade . -r test/requirements.txt -r docs/requirements.txt -r contributors/requirements.txt
- name: Statically checking code 🔎
if: matrix.python-version == '3.13' && matrix.platform == 'ubuntu-latest'
run: |
pip install --upgrade . -r test/linters-requirements.txt
black --check .
pylint fpdf test tutorial/tuto*.py
bandit -c .banditrc.yml -r contributors/ fpdf/ tutorial/
semgrep scan --config auto --error --strict --exclude-rule=python.lang.security.insecure-hash-function.insecure-hash-function fpdf
- name: Scan current project
if: matrix.python-version == '3.13' && matrix.platform == 'ubuntu-latest'
uses: anchore/scan-action@v3
with:
path: "."
fail-build: true
- name: Checking all PDF samples ☑
if: matrix.python-version == '3.13' && matrix.platform == 'ubuntu-latest'
run: |
# Using qpdf
find . -name '*.pdf' | xargs -n 1 sh -c 'qpdf --check --password=fpdf2 $0 || exit 255'
export PYTHONPATH=$PWD
# Using VeraPDF:
scripts/install-verapdf.sh
scripts/verapdf.py --process-all-test-pdf-files
scripts/verapdf.py --print-aggregated-report
# Using Datalogics PDF Checker:
scripts/install-pdfchecker.sh
scripts/pdfchecker.py --process-all-test-pdf-files
scripts/pdfchecker.py --print-aggregated-report
- name: Running tests ☑
pip install --upgrade . -r test/requirements.txt
- name: Run tests ☑
env:
CHECK_EXEC_TIME: ${{ matrix.python-version == '3.9' && 'test-enabled' || '' }}
CHECK_RSS_MEMORY: ${{ matrix.python-version == '3.13' && 'test-enabled' || '' }}
Expand All @@ -70,24 +103,44 @@ jobs:
grep -IRF generate=True test/ && exit 1
# Executing all tests:
pytest -vv --trace-memory-usage
- name: Running tests with the minimal versions of fpdf2 direct dependencies ☑
if: matrix.python-version == '3.8' && matrix.platform == 'ubuntu-latest'
- name: Upload coverage report to codecov.io ☑
# We only upload coverage ONCE, for a single parallel execution / Python version:
if: matrix.platform == 'ubuntu-latest' && matrix.python-version == '3.13'
run: bash <(curl -s https://codecov.io/bash)
- name: Run tests with the minimal versions of fpdf2 direct dependencies ☑
if: matrix.platform == 'ubuntu-latest' && matrix.python-version == '3.8'
run: |
# We ensure that those minimal versions remain compatible:
# Ensuring that those minimal versions remain compatible:
sed -i '/install_requires/,/\n/s/>=/==/' setup.cfg
pip install .
# Targetting only a subset of tests because: A) it's faster and B) some tests are dependant on a specific version of fonttools or Pillow
# Targeting only a subset of tests because: A) it's faster and B) some tests are dependant on a specific version of fonttools or Pillow
pytest -vv test/barcodes test/drawing test/errors test/image/test_load_image.py test/metadata test/shapes test/signing test/text_region test/utils
- name: Uploading coverage report to codecov.io ☑
if: matrix.python-version == '3.13' && matrix.platform == 'ubuntu-latest'
run: bash <(curl -s https://codecov.io/bash)
- name: Generating HTML documentation 🏗️
# As build_contributors_html_page.py can hang due to GitHub rate-limiting,
# we only execute this on master for now. And it should always be executed for one Python version only.
if: github.ref == 'refs/heads/master' && matrix.python-version == '3.13' && matrix.platform == 'ubuntu-latest'
env:
# Needed by contributors/build_contributors_html_page.py:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
doc:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
# Security hardening because this is a sensitive job,
# where extra care should be taken NOT to leak any secret
uses: step-security/harden-runner@v2
with:
egress-policy: block
allowed-endpoints:
github.com:443
api.github.com:443
*.githubusercontent.com:443
pypi.org:443
files.pythonhosted.org:443
- name: Checkout 🛎️
uses: actions/checkout@v4
- name: Set up Python 3.13 🔧
uses: actions/setup-python@v5
with:
python-version: 3.13
- name: Install Python dependencies ⚙️
run: |
python -m pip install --upgrade pip setuptools wheel
pip install --upgrade -r docs/requirements.txt -r contributors/requirements.txt
- name: Generate HTML documentation 🏗️
run: |
mkdir -p public/
# Setting PDF manual version:
Expand All @@ -96,12 +149,17 @@ jobs:
mkdocs build
pdoc --html -o public/ fpdf --config "git_link_template='https://github.com/py-pdf/fpdf2/blob/{commit}/{path}#L{start_line}-L{end_line}'"
scripts/add_pdoc_to_search_index.py
- name: Build contributors map 🗺️
# As build_contributors_html_page.py can hang due to GitHub rate-limiting, we only execute this on master for now
if: github.ref == 'refs/heads/master'
env:
# Needed by contributors/build_contributors_html_page.py:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cd contributors/ && PYTHONUNBUFFERED=1 ./build_contributors_html_page.py py-pdf/fpdf2
cp -t ../public/ contributors.html contributors-map-small.png
- name: Deploy documentation 🚀
# GitHub Pages deployment should not be done for all Python versions,
# otherwise commits will conflict on the gh-pages branch:
if: github.ref == 'refs/heads/master' && matrix.python-version == '3.13' && matrix.platform == 'ubuntu-latest'
if: github.ref == 'refs/heads/master'
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -116,13 +174,24 @@ jobs:
# Trusted publishing configured there: https://pypi.org/manage/project/fpdf2/settings/publishing/
id-token: write
steps:
- name: Harden Runner
# Security hardening because this is a sensitive job,
# where extra care should be taken NOT to leak any secret
uses: step-security/harden-runner@v2
with:
egress-policy: block
allowed-endpoints:
github.com:443
*.githubusercontent.com:443
pypi.org:443
files.pythonhosted.org:443
- name: Checkout 🛎️
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up Python 3.13 🔧
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: Building distributions for Pypi 🏗️
- name: Build distributions for Pypi 🏗️
id: build
run: |
echo Versions already released on Pypi: $(curl -Ls 'https://pypi.org/pypi/fpdf2/json' | jq -r '.releases|keys[]')
Expand All @@ -136,11 +205,3 @@ jobs:
# Doc: https://github.com/marketplace/actions/pypi-publish
with:
print-hash: true
- name: Generate & release sigstore signatures 🔑
if: steps.build.outputs.publish == 'yes'
uses: sigstore/[email protected]
# Doc: https://github.com/marketplace/actions/gh-action-sigstore-python
with:
inputs: ./dist/*.tar.gz ./dist/*.whl
# For this setting to work, this pipeline should be triggered by a "release" event:
release-signing-artifacts: true
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ This can also be enabled programmatically with `warnings.simplefilter('default',
* documentation on how to: [render spreadsheets as PDF tables](https://py-pdf.github.io/fpdf2/RenderingSpreadsheetsAsPDFTables.html)
* support for passing `Align` values (along with string values like `'C'`, `'L'`, `'R'`) in `l_margin` of `TextStyle` to horizontally align text - [issue #1282](https://github.com/py-pdf/fpdf2/issues/1282)
### Fixed
* support for `align=` in [`FPDF.table()`](https://py-pdf.github.io/fpdf2/Tables.html#setting-table-column-widths). Due to this correction, tables are now properly horizontally aligned on the page by default. This was always specified in the documentation, but was not in effect until now. You can revert to have left-aligned tables by passing `align="LEFT"` to `FPDF.table()`.
* support for `align=` in [`FPDF.table()`](https://py-pdf.github.io/fpdf2/Tables.html#setting-table-column-widths). Due to this correction, tables are now properly horizontally aligned on the page by default. This was always specified in the documentation, but was not in effect until now. You can revert to have left-aligned tables by passing `align="LEFT"` to `FPDF.table()`. - [issue #1306](https://github.com/py-pdf/fpdf2/issues/1306)
* `FPDF.set_text_shaping(False)` was broken since version 2.7.8 and is now working properly - [issue #1287](https://github.com/py-pdf/fpdf2/issues/1287)
* fixed bug where cells with `rowspan`, `colspan` > 1 and null text were not displayed properly - [issue #1293](https://github.com/py-pdf/fpdf2/issues/1293)
* `CreationDate` metadata used a wrong timezone offset for UTC - [issue #1261](https://github.com/py-pdf/fpdf2/issues/1261)
* [`insert_toc_placeholder()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.insert_toc_placeholder) did not properly the page orientation, which caused a bug when the last page of the document was in a different orientation - [issue #1213](https://github.com/py-pdf/fpdf2/issues/1213)
* [`insert_toc_placeholder()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.insert_toc_placeholder) did not properly the page orientation, which caused a bug when the last page of the document was in a different orientation - [issue #1312](https://github.com/py-pdf/fpdf2/issues/1213)
### Changed
* improved logic for handling text substitution of the total number of pages, ensuring compatibility with text shaping - [issue #1090](https://github.com/py-pdf/fpdf2/issues/1090)
* all [`AnnotationDict`](https://py-pdf.github.io/fpdf2/fpdf/annotations.html) properties can now be passed to `FPDF.text_annotation()`, `FPDF.free_text_annotation()`, `FPDF.add_action()`, `FPDF.add_text_markup_annotation()` & `FPDF.ink_annotation()`. This includes `title`, `color`, `border_width`...
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![build status](https://github.com/py-pdf/fpdf2/workflows/build/badge.svg)](https://github.com/py-pdf/fpdf2/actions?query=branch%3Amaster)
[![codecov](https://codecov.io/gh/py-pdf/fpdf2/branch/master/graph/badge.svg)](https://codecov.io/gh/py-pdf/fpdf2)
[![Pypi Trusted Publisher: enabled](https://img.shields.io/badge/Pypi%20Trusted%20Publisher-enabled-green.svg)](https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/)
[![checks: bandit, pylint, semgrep](https://img.shields.io/badge/checks-bandit,pylint,semgrep,grype-green.svg)](https://github.com/py-pdf/fpdf2/actions/workflows/continuous-integration-workflow.yml)
[![checks: bandit, grype, guarddog, pylint, semgrep](https://img.shields.io/badge/checks-bandit,grype,guarddog,pylint,semgrep-green.svg)](https://github.com/py-pdf/fpdf2/actions/workflows/continuous-integration-workflow.yml)

[![Dependents](https://img.shields.io/librariesio/dependents/pypi/fpdf2)](https://libraries.io/pypi/fpdf2/dependents)
[![Downloads per month](https://pepy.tech/badge/fpdf2/month)](https://pepy.tech/project/fpdf2)
Expand Down
3 changes: 2 additions & 1 deletion docs/Development.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,13 @@ Ask maintainers through comments if some errors in the pipeline seem obscure to
### Release checklist
1. complete `CHANGELOG.md` and add the version & date of the new release
2. bump `FPDF_VERSION` in `fpdf/fpdf.py`.
Also (optionnal, once every year), update `contributors/contributors-map-small.png` based on <https://py-pdf.github.io/fpdf2/contributors.html>
Also (optional, once every year), update `contributors/contributors-map-small.png` based on <https://py-pdf.github.io/fpdf2/contributors.html>
3. update the `announce` block in `docs/overrides/main.html` to mention the new release
4. `git commit` & `git push` (if editing in a fork: submit and merge a PR)
5. check that [the GitHub Actions succeed](https://github.com/py-pdf/fpdf2/actions), and that [a new release appears on Pypi](https://pypi.org/project/fpdf2/#history)
6. perform a [GitHub release](https://github.com/py-pdf/fpdf2/releases), taking the description from the `CHANGELOG.md`.
It will create a new `git` tag.
7. (optional) add a comment mentioning that the feature/fix has been released in all the GitHub issues mentioned in the `CHANGELOG.md`

## Documentation
The standalone documentation is in the `docs` subfolder,
Expand Down
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
lxml
mkdocs
mkdocs-include-markdown-plugin
mkdocs-material
Expand Down
4 changes: 4 additions & 0 deletions test/image/image_types/test_insert_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ def test_insert_jpg_flatedecode(tmp_path):
assert_pdf_equal(pdf, HERE / "image_types_insert_jpg_flatedecode.pdf", tmp_path)


@pytest.mark.skipif(
sys.version_info.minor != 13,
reason="LZWDecode is currently VERY slow, so we want to only execute it ONCE among all Python versions in the test pipeline",
)
def test_insert_jpg_lzwdecode(tmp_path):
pdf = fpdf.FPDF()
pdf.compress = False
Expand Down

0 comments on commit 16c3404

Please sign in to comment.