1
0
Fork 0

Adding upstream version 0.2.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-08 07:40:15 +01:00
parent d372080b5f
commit fb81c4a897
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
13 changed files with 159 additions and 116 deletions

1
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1 @@
open_collective: courtbouillon

29
.github/workflows/doconfly.yml vendored Normal file
View file

@ -0,0 +1,29 @@
name: doconfly
on:
push:
branches:
- master
tags:
- "*"
jobs:
doconfly:
name: doconfly job
runs-on: ubuntu-latest
env:
PORT: ${{ secrets.PORT }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
TAKOYAKI: ${{ secrets.TAKOYAKI }}
USER: ${{ secrets.USER }}
DOCUMENTATION_PATH: ${{ secrets.DOCUMENTATION_PATH }}
DOCUMENTATION_URL: ${{ secrets.DOCUMENTATION_URL }}
steps:
- run: |
which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )
eval $(ssh-agent -s)
echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keyscan -p $PORT $TAKOYAKI >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
ssh $USER@$TAKOYAKI -p $PORT "doconfly/doconfly.sh $GITHUB_REPOSITORY $GITHUB_REF $DOCUMENTATION_PATH $DOCUMENTATION_URL"

35
.github/workflows/tests.yml vendored Normal file
View file

@ -0,0 +1,35 @@
name: pydyf's tests
on: [push, pull_request]
jobs:
tests:
name: ${{ matrix.os }} - ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.7', '3.8', '3.9', '3.10', 'pypy-3.8']
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install Ghostscript (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: sudo apt-get update -y && sudo apt-get install ghostscript -y
- name: Install Ghostscript (macOS)
if: matrix.os == 'macos-latest'
run: brew install ghostscript
- name: Install Ghostscript (Windows)
if: matrix.os == 'windows-latest'
run: |
C:\msys64\usr\bin\bash -lc 'pacman -S mingw-w64-x86_64-ghostscript --noconfirm'
echo "C:\msys64\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH
rm C:\msys64\mingw64\bin\python.exe
- name: Upgrade pip and setuptools
run: python -m pip install --upgrade pip setuptools
- name: Install tests requirements
run: python -m pip install .[test]
- name: Launch tests
run: python -m pytest

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/docs/_build
/tests/results
__pycache__
.coverage

View file

@ -1,57 +0,0 @@
Metadata-Version: 2.1
Name: pydyf
Version: 0.1.2
Summary: A low-level PDF generator.
Keywords: pdf,generator
Author-email: CourtBouillon <contact@courtbouillon.org>
Maintainer-email: CourtBouillon <contact@courtbouillon.org>
Requires-Python: >=3.6
Description-Content-Type: text/x-rst
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Requires-Dist: sphinx ; extra == "doc"
Requires-Dist: sphinx_rtd_theme ; extra == "doc"
Requires-Dist: pytest ; extra == "test"
Requires-Dist: pytest-cov ; extra == "test"
Requires-Dist: pytest-flake8 ; extra == "test"
Requires-Dist: pytest-isort ; extra == "test"
Requires-Dist: coverage[toml] ; extra == "test"
Requires-Dist: pillow ; extra == "test"
Project-URL: Changelog, https://github.com/CourtBouillon/pydyf/releases
Project-URL: Code, https://github.com/CourtBouillon/pydyf
Project-URL: Documentation, https://doc.courtbouillon.org/pydyf/
Project-URL: Donation, https://opencollective.com/courtbouillon
Project-URL: Homepage, https://www.courtbouillon.org/pydyf
Project-URL: Issues, https://github.com/CourtBouillon/pydyf/issues
Provides-Extra: doc
Provides-Extra: test
pydyf is a low-level PDF generator written in Python and based on PDF
specification 1.7.
* Free software: BSD license
* For Python 3.6+, tested on CPython and PyPy
* Documentation: https://doc.courtbouillon.org/pydyf
* Changelog: https://github.com/CourtBouillon/pydyf/releases
* Code, issues, tests: https://github.com/CourtBouillon/pydyf
* Code of conduct: https://www.courtbouillon.org/code-of-conduct
* Professional support: https://www.courtbouillon.org
* Donation: https://opencollective.com/courtbouillon
Copyrights are retained by their contributors, no copyright assignment is
required to contribute to pydyf. Unless explicitly stated otherwise, any
contribution intentionally submitted for inclusion is licensed under the BSD
3-clause license, without any additional terms or conditions. For full
authorship information, see the version control history.

View file

@ -2,7 +2,7 @@ pydyf is a low-level PDF generator written in Python and based on PDF
specification 1.7.
* Free software: BSD license
* For Python 3.6+, tested on CPython and PyPy
* For Python 3.7+, tested on CPython and PyPy
* Documentation: https://doc.courtbouillon.org/pydyf
* Changelog: https://github.com/CourtBouillon/pydyf/releases
* Code, issues, tests: https://github.com/CourtBouillon/pydyf

View file

@ -2,6 +2,49 @@ Changelog
=========
Version 0.2.0
-------------
Released on 2022-05-23.
Dependencies:
* Python 3.7+ is now needed, Python 3.6 is not supported anymore
New features:
* `d0be36b <https://github.com/CourtBouillon/pydyf/commit/d0be36b>`_:
Allow to set PDF version
* `879261c <https://github.com/CourtBouillon/pydyf/commit/879261c>`_:
Allow to set PDF identifier
Contributors:
* Guillaume Ayoub
Backers and sponsors:
* Grip Angebotssoftware
* Manuel Barkhau
* Crisp BV
* SimonSoft
* Menutech
* Spacinov
* KontextWork
* René Fritz
* Kobalt
* NCC Group
* Des images et des mots
* Nathalie Gutton
* Andreas Zettl
* Tom Pohl
* Moritz Mahringer
* Florian Demmer
* Yanal-Yvez Fargialla
* Gábor
* Piotr Horzycki
Version 0.1.2
-------------

View file

@ -1,13 +1,7 @@
# pydyf documentation build configuration file.
import sys
from pathlib import Path
import pydyf
# Add current path for css_diagram_role
sys.path.append(str(Path(__file__).parent))
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [

View file

@ -5,12 +5,11 @@ Going Further
Why pydyf?
-------------
pydyf has been created to replace Cairo PDF generation in WeasyPrint_.
pydyf has been created to replace Cairo_ PDF generation in WeasyPrint_.
Indeed, there are some bugs in WeasyPrint caused by Cairo_ and Cairo has some
difficulties to make releases.
Also there are features which will be easier to implement while having more
control on the PDF generation.
Indeed, there were some bugs in WeasyPrint caused by Cairo, and new versions of
Cairo can take a long time to be released. There are also many features that
are easier to implement with more control on the PDF generation.
So we created pydyf.
@ -20,13 +19,13 @@ So we created pydyf.
Why Python?
-----------
Python is a really good language to design a small, OS-agnostic parser. As it
is object-oriented, it gives the possibility to follow the specification with
high-level classes and a small amount of very simple code.
Python is a really good language to design a small, OS-agnostic library. As it
is object-oriented, it gives the possibility to follow the PDF specification
with high-level classes and a small amount of very simple code.
And of course, WeasyPrint is written in Python too, giving an obvious reason
for this choice.
Speed is not pydyfs main goal. Code simplicity, maintainability and
flexibility are more important goals for this library, as they give the
ability to stay really close to the specification and to fix bugs easily.
flexibility are more important goals for this library, as they give the ability
to stay really close to the specification and to fix bugs easily.

View file

@ -6,8 +6,9 @@ A low-level PDF generator.
import re
import zlib
from codecs import BOM_UTF16_BE
from hashlib import md5
VERSION = __version__ = '0.1.2'
VERSION = __version__ = '0.2.0'
def _to_bytes(item):
@ -425,7 +426,7 @@ class PDF:
})
self.add_object(self.pages)
#: PDF:class:`Dictionary` containing the PDFs metadata.
#: PDF :class:`Dictionary` containing the PDFs metadata.
self.info = Dictionary({})
self.add_object(self.info)
@ -469,15 +470,17 @@ class PDF:
self.current_position += len(content) + 1
output.write(content + b'\n')
def write(self, output):
def write(self, output, version=b'1.7', identifier=None):
"""Write PDF to output.
:param output: Output stream.
:type output: binary :term:`file object`
:param bytes version: PDF version.
:param bytes identifier: PDF file identifier.
"""
# Write header
self.write_line(b'%PDF-1.7', output)
self.write_line(b'%PDF-' + version, output)
self.write_line(b'%\xf0\x9f\x96\xa4', output)
# Write all non-free PDF objects
@ -502,6 +505,13 @@ class PDF:
self.write_line(f'/Size {len(self.objects)}'.encode(), output)
self.write_line(b'/Root ' + self.catalog.reference, output)
self.write_line(b'/Info ' + self.info.reference, output)
if identifier is not None:
data = b''.join(
obj.data for obj in self.objects if obj.free != 'f')
data_hash = md5(data).hexdigest().encode()
self.write_line(
b'/ID [' + String(identifier).data + b' ' +
String(data_hash).data + b']', output)
self.write_line(b'>>', output)
self.write_line(b'startxref', output)
self.write_line(f'{self.xref_position}'.encode(), output)

View file

@ -8,7 +8,7 @@ description = 'A low-level PDF generator.'
keywords = ['pdf', 'generator']
authors = [{name = 'CourtBouillon', email = 'contact@courtbouillon.org'}]
maintainers = [{name = 'CourtBouillon', email = 'contact@courtbouillon.org'}]
requires-python = '>=3.6'
requires-python = '>=3.7'
readme = {file = 'README.rst', content-type = 'text/x-rst'}
license = {file = 'LICENSE'}
classifiers = [
@ -19,10 +19,10 @@ classifiers = [
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
]
@ -38,13 +38,13 @@ Donation = 'https://opencollective.com/courtbouillon'
[project.optional-dependencies]
doc = ['sphinx', 'sphinx_rtd_theme']
test = ['pytest', 'pytest-cov', 'pytest-flake8', 'pytest-isort', 'coverage[toml]', 'pillow']
test = ['pytest', 'pytest-xdist', 'pytest-flake8', 'pytest-isort', 'pytest-cov', 'coverage[toml]', 'pillow']
[tool.flit.sdist]
exclude = ['.*']
[tool.pytest.ini_options]
addopts = '--isort --flake8 --cov --no-cov-on-fail'
addopts = '--isort --flake8 --numprocesses=auto'
[tool.coverage.run]
branch = true

View file

@ -1,31 +0,0 @@
#!/usr/bin/env python
# setup.py generated by flit for tools that don't yet use PEP 517
from distutils.core import setup
packages = \
['pydyf']
package_data = \
{'': ['*']}
extras_require = \
{'doc': ['sphinx', 'sphinx_rtd_theme'],
'test': ['pytest',
'pytest-cov',
'pytest-flake8',
'pytest-isort',
'coverage[toml]',
'pillow']}
setup(name='pydyf',
version='0.1.2',
description='A low-level PDF generator.',
author=None,
author_email='CourtBouillon <contact@courtbouillon.org>',
url=None,
packages=packages,
package_data=package_data,
extras_require=extras_require,
python_requires='>=3.6',
)

View file

@ -1,3 +1,5 @@
import io
import pydyf
from . import assert_pixels
@ -283,10 +285,10 @@ def test_transform():
document = pydyf.PDF()
draw = pydyf.Stream()
draw.transform(1, 0, 0, 1, 1, 1)
draw.move_to(2, 2)
draw.set_line_width(2)
draw.line_to(2, 5)
draw.transform(1, 0, 0, 1, 1, 1)
draw.stroke()
document.add_object(draw)
@ -694,7 +696,7 @@ def test_text():
KKKKKKKKKK
KKKKKKKKKK
KKKKKKKKKK
__________
zzzzzzzzzz
__________
__________
__________
@ -702,6 +704,20 @@ def test_text():
''')
def test_identifier():
document = pydyf.PDF()
pdf = io.BytesIO()
document.write(pdf, identifier=b'abc')
assert b'abc' in pdf.getvalue()
def test_version():
document = pydyf.PDF()
pdf = io.BytesIO()
document.write(pdf, version=b'2.0')
assert b'2.0' in pdf.getvalue()
def test_string_encoding():
assert pydyf.String('abc').data == b'(abc)'
assert pydyf.String('déf').data == b'<feff006400e90066>'