weasyprint 67.0__tar.gz → 68.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {weasyprint-67.0 → weasyprint-68.0}/PKG-INFO +2 -1
- {weasyprint-67.0 → weasyprint-68.0}/docs/api_reference.rst +7 -1
- {weasyprint-67.0 → weasyprint-68.0}/docs/changelog.rst +121 -0
- {weasyprint-67.0 → weasyprint-68.0}/docs/common_use_cases.rst +63 -66
- {weasyprint-67.0 → weasyprint-68.0}/docs/conf.py +4 -2
- {weasyprint-67.0 → weasyprint-68.0}/docs/first_steps.rst +54 -31
- {weasyprint-67.0 → weasyprint-68.0}/pyproject.toml +1 -1
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_common.py +4 -5
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_target.py +21 -1
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_validation.py +24 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/__init__.py +1 -1
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_gradients.py +215 -1
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_text.py +179 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_absolute.py +1 -1
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_gradient.py +115 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_text.py +4 -2
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_grid.py +137 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_page.py +66 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_table.py +17 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/test_acid2.py +2 -2
- {weasyprint-67.0 → weasyprint-68.0}/tests/test_api.py +266 -67
- {weasyprint-67.0 → weasyprint-68.0}/tests/test_boxes.py +5 -5
- {weasyprint-67.0 → weasyprint-68.0}/tests/test_fonts.py +1 -1
- {weasyprint-67.0 → weasyprint-68.0}/tests/test_text.py +58 -14
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/__init__.py +35 -103
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/__main__.py +107 -80
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/__init__.py +4 -10
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/functions.py +5 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/html5_ua.css +1 -1
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/tokens.py +4 -1
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/validation/properties.py +4 -4
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/document.py +4 -64
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/draw/text.py +4 -2
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/formatting_structure/boxes.py +4 -1
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/formatting_structure/build.py +111 -37
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/images.py +27 -32
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/__init__.py +2 -1
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/grid.py +25 -14
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/page.py +4 -4
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/preferred.py +35 -2
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/pdf/__init__.py +12 -1
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/pdf/anchors.py +10 -16
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/pdf/fonts.py +12 -3
- weasyprint-68.0/weasyprint/pdf/metadata.py +187 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/pdf/pdfa.py +1 -3
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/pdf/pdfua.py +1 -3
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/pdf/pdfx.py +1 -3
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/pdf/stream.py +0 -2
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/svg/__init__.py +51 -30
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/svg/css.py +21 -4
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/svg/defs.py +5 -3
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/text/fonts.py +2 -3
- weasyprint-68.0/weasyprint/urls.py +480 -0
- weasyprint-67.0/weasyprint/pdf/metadata.py +0 -132
- weasyprint-67.0/weasyprint/urls.py +0 -304
- {weasyprint-67.0 → weasyprint-68.0}/LICENSE +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/README.rst +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/docs/contribute.rst +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/docs/going_further.rst +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/docs/index.rst +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/docs/manpage.rst +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/docs/support.rst +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/__init__.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/conftest.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/__init__.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_counters.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_descriptors.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_errors.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_expanders.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_fonts.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_layers.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_math.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_nesting.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_pages.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_ua.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/css/test_variables.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/__init__.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_bounding_box.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_clip.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_defs.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_images.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_markers.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_opacity.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_paths.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_patterns.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_shapes.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_transform.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_units.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/svg/test_visibility.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_background.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_before_after.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_box.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_cmyk_color_profiles.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_column.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_current_color.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_float.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_footnote.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_footnote_column.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_image.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_leader.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_list.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_opacity.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_overflow.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_page.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_table.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_transform.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_visibility.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/draw/test_whitespace.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/__init__.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_block.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_column.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_flex.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_float.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_footnotes.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_image.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_inline.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_inline_block.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_list.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_position.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/layout/test_preferred.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/acid2-reference.html +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/acid2-test.html +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/blue.jpg +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/border.svg +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/border2.svg +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/cmyk.icc +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/cmyk_with_icc.jpg +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/cmyk_without_icc.jpg +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/doc1.html +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/doc1_UTF-16BE.html +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/icon.png +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/latin1-test.css +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/logo_small.png +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/mask.svg +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/mini_ua.css +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/not-optimized-exif.jpg +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/not-optimized.jpg +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/pattern-transparent.svg +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/pattern.gif +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/pattern.palette.png +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/pattern.png +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/pattern.svg +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/really-a-png.svg +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/really-a-svg.png +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/sheet2.css +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/sub_directory/sheet1.css +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/tests_ua.css +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/user.css +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/utf8-test.css +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/weasyprint.otb +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/weasyprint.otf +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/resources/weasyprint.woff +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/test_pdf.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/test_presentational_hints.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/test_stacking.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/test_unicode.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/test_url.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/tests/testing_utils.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/anchors.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/computed_values.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/counters.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/html5_ph.css +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/html5_ua_form.css +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/media_queries.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/properties.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/targets.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/units.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/validation/__init__.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/validation/descriptors.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/css/validation/expanders.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/draw/__init__.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/draw/border.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/draw/color.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/html.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/absolute.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/background.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/block.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/column.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/flex.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/float.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/inline.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/leader.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/min_max.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/percent.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/replaced.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/layout/table.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/logger.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/matrix.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/pdf/debug.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/pdf/sRGB2014.icc +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/pdf/tags.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/stacking.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/svg/bounding_box.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/svg/images.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/svg/path.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/svg/shapes.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/svg/text.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/svg/utils.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/text/constants.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/text/ffi.py +0 -0
- {weasyprint-67.0 → weasyprint-68.0}/weasyprint/text/line_break.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: weasyprint
|
|
3
|
-
Version:
|
|
3
|
+
Version: 68.0
|
|
4
4
|
Summary: The Awesome Document Factory
|
|
5
5
|
Keywords: html,css,pdf,converter
|
|
6
6
|
Author-email: Simon Sapin <simon.sapin@exyr.org>
|
|
@@ -37,6 +37,7 @@ Requires-Dist: sphinx ; extra == "doc"
|
|
|
37
37
|
Requires-Dist: furo ; extra == "doc"
|
|
38
38
|
Requires-Dist: pytest ; extra == "test"
|
|
39
39
|
Requires-Dist: ruff ; extra == "test"
|
|
40
|
+
Requires-Dist: Pillow >=12.1.0 ; extra == "test"
|
|
40
41
|
Project-URL: Changelog, https://github.com/Kozea/WeasyPrint/releases
|
|
41
42
|
Project-URL: Code, https://github.com/Kozea/WeasyPrint
|
|
42
43
|
Project-URL: Documentation, https://doc.courtbouillon.org/weasyprint/
|
|
@@ -56,7 +56,6 @@ Python API
|
|
|
56
56
|
:members:
|
|
57
57
|
.. autoclass:: CSS(input, **kwargs)
|
|
58
58
|
.. autoclass:: Attachment(input, **kwargs)
|
|
59
|
-
.. autofunction:: default_url_fetcher
|
|
60
59
|
.. autodata:: DEFAULT_OPTIONS
|
|
61
60
|
|
|
62
61
|
.. module:: weasyprint.document
|
|
@@ -68,6 +67,13 @@ Python API
|
|
|
68
67
|
:members:
|
|
69
68
|
:exclude-members: paint
|
|
70
69
|
|
|
70
|
+
.. module:: weasyprint.urls
|
|
71
|
+
.. autoclass:: URLFetcher
|
|
72
|
+
:members:
|
|
73
|
+
:member-order: bysource
|
|
74
|
+
.. autoclass:: URLFetcherResponse
|
|
75
|
+
.. autoclass:: FatalURLFetchingError
|
|
76
|
+
|
|
71
77
|
.. module:: weasyprint.text.fonts
|
|
72
78
|
.. autoclass:: FontConfiguration()
|
|
73
79
|
|
|
@@ -2,6 +2,127 @@ Changelog
|
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
Version 68.0
|
|
6
|
+
------------
|
|
7
|
+
|
|
8
|
+
Released on 2026-01-19.
|
|
9
|
+
|
|
10
|
+
**This is a security update (CVE-2025-68616).**
|
|
11
|
+
|
|
12
|
+
We strongly recommend to upgrade WeasyPrint to the latest version if you use the
|
|
13
|
+
``default_url_fetcher`` function in your custom URL fetcher, or if you use the
|
|
14
|
+
``allowed_protocols`` parameter of the ``default_url_fetcher`` function.
|
|
15
|
+
|
|
16
|
+
Security:
|
|
17
|
+
|
|
18
|
+
* Always use URL fetcher for HTTP redirects
|
|
19
|
+
|
|
20
|
+
Python API:
|
|
21
|
+
|
|
22
|
+
* ``default_url_fetcher()`` is deprecated, use the new ``URLFetcher`` class instead, see
|
|
23
|
+
:ref:`URL Fetchers` for more information about URL fetchers
|
|
24
|
+
* ``DocumentMetadata.generate_rdf_metadata`` is now a method that can be overridden
|
|
25
|
+
instead of a parameter, see :ref:`Factur-X / ZUGFeRD (Electronic Invoices)` for
|
|
26
|
+
examples to create e-invoices
|
|
27
|
+
|
|
28
|
+
Features:
|
|
29
|
+
|
|
30
|
+
* `#2609 <https://github.com/Kozea/WeasyPrint/pull/2609>`_,
|
|
31
|
+
`#2603 <https://github.com/Kozea/WeasyPrint/issues/2603>`_,
|
|
32
|
+
`#351 <https://github.com/Kozea/WeasyPrint/issues/351>`_:
|
|
33
|
+
Refactor URL fetcher API
|
|
34
|
+
* `#2632 <https://github.com/Kozea/WeasyPrint/pull/2632>`_:
|
|
35
|
+
Support legacy 0 value for angles
|
|
36
|
+
* `#2627 <https://github.com/Kozea/WeasyPrint/pull/2627>`_:
|
|
37
|
+
Add font-face support to SVG
|
|
38
|
+
* `#2646 <https://github.com/Kozea/WeasyPrint/pull/2646>`_,
|
|
39
|
+
`#2255 <https://github.com/Kozea/WeasyPrint/issues/2255>`_:
|
|
40
|
+
Add font shorthand support for SVG text elements
|
|
41
|
+
* `#2590 <https://github.com/Kozea/WeasyPrint/pull/2590>`_,
|
|
42
|
+
`#1749 <https://github.com/Kozea/WeasyPrint/issues/1749>`_:
|
|
43
|
+
Honor language-specific rules for text-transform
|
|
44
|
+
* `#2645 <https://github.com/Kozea/WeasyPrint/pull/2645>`_,
|
|
45
|
+
`#2613 <https://github.com/Kozea/WeasyPrint/issues/2613>`_:
|
|
46
|
+
Improve SVG and SVG emojis rendering
|
|
47
|
+
* `#2658 <https://github.com/Kozea/WeasyPrint/pull/2658>`_,
|
|
48
|
+
`#2583 <https://github.com/Kozea/WeasyPrint/issues/2583>`_:
|
|
49
|
+
Add CLI for Factur-X / ZUGFeRD e-invoices
|
|
50
|
+
|
|
51
|
+
Bug fixes:
|
|
52
|
+
|
|
53
|
+
* `#2649 <https://github.com/Kozea/WeasyPrint/issues/2649>`_:
|
|
54
|
+
Refactor URL fetcher API
|
|
55
|
+
* `#2643 <https://github.com/Kozea/WeasyPrint/pull/2643>`_,
|
|
56
|
+
`#2628 <https://github.com/Kozea/WeasyPrint/issues/2628>`_:
|
|
57
|
+
Handle box-sizing: border-box in grid layout
|
|
58
|
+
* `#2641 <https://github.com/Kozea/WeasyPrint/pull/2641>`_,
|
|
59
|
+
`#1875 <https://github.com/Kozea/WeasyPrint/issues/1875>`_:
|
|
60
|
+
Process whitespace after checking all pending targets
|
|
61
|
+
* `#2488 <https://github.com/Kozea/WeasyPrint/pull/2488>`_,
|
|
62
|
+
`#2485 <https://github.com/Kozea/WeasyPrint/issues/2485>`_:
|
|
63
|
+
Preserve page groups during layout repagination
|
|
64
|
+
* `#2642 <https://github.com/Kozea/WeasyPrint/pull/2642>`_,
|
|
65
|
+
`#2631 <https://github.com/Kozea/WeasyPrint/issues/2631>`_:
|
|
66
|
+
Don’t use isolated transparency groups
|
|
67
|
+
* `#2637 <https://github.com/Kozea/WeasyPrint/issues/2637>`_:
|
|
68
|
+
Fix repeating radial gradients rendering
|
|
69
|
+
* `#2622 <https://github.com/Kozea/WeasyPrint/issues/2622>`_:
|
|
70
|
+
Fix validation of colors
|
|
71
|
+
* `#2626 <https://github.com/Kozea/WeasyPrint/issues/2626>`_:
|
|
72
|
+
Share grid items rendering advancement between a box and its copies
|
|
73
|
+
* `#2621 <https://github.com/Kozea/WeasyPrint/issues/2621>`_:
|
|
74
|
+
Correctly handle fallback values of attr()
|
|
75
|
+
* `#2619 <https://github.com/Kozea/WeasyPrint/issues/2619>`_:
|
|
76
|
+
Fix SVG fonts
|
|
77
|
+
* `#2629 <https://github.com/Kozea/WeasyPrint/issues/2629>`_:
|
|
78
|
+
Always define extra skip height that may be used after
|
|
79
|
+
* `#2648 <https://github.com/Kozea/WeasyPrint/issues/2648>`_:
|
|
80
|
+
Fix numbers validation in font-feature-settings
|
|
81
|
+
* `#2648 <https://github.com/Kozea/WeasyPrint/issues/2660>`_:
|
|
82
|
+
Fix keyword values for text-decoration-thickness
|
|
83
|
+
* `#2661 <https://github.com/Kozea/WeasyPrint/issues/2661>`_:
|
|
84
|
+
Respect inline images when defining minimum table width
|
|
85
|
+
|
|
86
|
+
Documentation:
|
|
87
|
+
|
|
88
|
+
* `#2638 <https://github.com/Kozea/WeasyPrint/pull/2638>`_:
|
|
89
|
+
Update Python command for Windows installation steps
|
|
90
|
+
|
|
91
|
+
Contributors:
|
|
92
|
+
|
|
93
|
+
* Guillaume Ayoub
|
|
94
|
+
* Jurriaan Pruis
|
|
95
|
+
* Mohamed Hamed
|
|
96
|
+
* Alexandra Usatenko
|
|
97
|
+
* Andrea Corna
|
|
98
|
+
* Aoishik Khan
|
|
99
|
+
* Joe
|
|
100
|
+
|
|
101
|
+
Backers and sponsors:
|
|
102
|
+
|
|
103
|
+
* Spacinov
|
|
104
|
+
* Syslifters
|
|
105
|
+
* Kobalt
|
|
106
|
+
* Simon Sapin
|
|
107
|
+
* Grip Angebotssoftware
|
|
108
|
+
* Manuel Barkhau
|
|
109
|
+
* Simonsoft
|
|
110
|
+
* KontextWork
|
|
111
|
+
* Menutech
|
|
112
|
+
* TrainingSparkle
|
|
113
|
+
* Healthchecks.io
|
|
114
|
+
* Method B
|
|
115
|
+
* FieldHub
|
|
116
|
+
* Hammerbacher
|
|
117
|
+
* Yanal-Yves Fargialla
|
|
118
|
+
* Morntag
|
|
119
|
+
* Piloterr
|
|
120
|
+
* Xavid
|
|
121
|
+
* Charlie S.
|
|
122
|
+
* Prothesis Dental Solutions
|
|
123
|
+
* Kai DeLorenzo
|
|
124
|
+
|
|
125
|
+
|
|
5
126
|
Version 67.0
|
|
6
127
|
------------
|
|
7
128
|
|
|
@@ -208,63 +208,58 @@ Here is an example of Factur-X document generation.
|
|
|
208
208
|
|
|
209
209
|
.. code-block:: xml
|
|
210
210
|
|
|
211
|
-
<
|
|
212
|
-
xmlns:x="adobe:ns:meta/"
|
|
211
|
+
<rdf:RDF
|
|
213
212
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
214
|
-
xmlns:pdf="http://ns.adobe.com/pdf/1.3/"
|
|
215
213
|
xmlns:fx="urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#"
|
|
216
214
|
xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/"
|
|
217
215
|
xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema#"
|
|
218
216
|
xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property#">
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
<
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
<
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
<
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
<
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
</
|
|
242
|
-
<
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
</
|
|
248
|
-
<
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
</
|
|
254
|
-
<
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
</rdf:Description>
|
|
266
|
-
</rdf:RDF>
|
|
267
|
-
</x:xmpmeta>
|
|
217
|
+
<rdf:Description rdf:about="">
|
|
218
|
+
<fx:ConformanceLevel>MINIMUM</fx:ConformanceLevel>
|
|
219
|
+
<fx:DocumentFileName>factur-x.xml</fx:DocumentFileName>
|
|
220
|
+
<fx:DocumentType>INVOICE</fx:DocumentType>
|
|
221
|
+
<fx:Version>1.0</fx:Version>
|
|
222
|
+
</rdf:Description>
|
|
223
|
+
<rdf:Description rdf:about="">
|
|
224
|
+
<pdfaExtension:schemas>
|
|
225
|
+
<rdf:Bag>
|
|
226
|
+
<rdf:li rdf:parseType="Resource">
|
|
227
|
+
<pdfaSchema:schema>Factur-X PDFA Extension Schema</pdfaSchema:schema>
|
|
228
|
+
<pdfaSchema:namespaceURI>urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#</pdfaSchema:namespaceURI>
|
|
229
|
+
<pdfaSchema:prefix>fx</pdfaSchema:prefix>
|
|
230
|
+
<pdfaSchema:property>
|
|
231
|
+
<rdf:Seq>
|
|
232
|
+
<rdf:li rdf:parseType="Resource">
|
|
233
|
+
<pdfaProperty:name>DocumentFileName</pdfaProperty:name>
|
|
234
|
+
<pdfaProperty:valueType>Text</pdfaProperty:valueType>
|
|
235
|
+
<pdfaProperty:category>external</pdfaProperty:category>
|
|
236
|
+
<pdfaProperty:description>name of the embedded XML invoice file</pdfaProperty:description>
|
|
237
|
+
</rdf:li>
|
|
238
|
+
<rdf:li rdf:parseType="Resource">
|
|
239
|
+
<pdfaProperty:name>DocumentType</pdfaProperty:name>
|
|
240
|
+
<pdfaProperty:valueType>Text</pdfaProperty:valueType>
|
|
241
|
+
<pdfaProperty:category>external</pdfaProperty:category>
|
|
242
|
+
<pdfaProperty:description>INVOICE</pdfaProperty:description>
|
|
243
|
+
</rdf:li>
|
|
244
|
+
<rdf:li rdf:parseType="Resource">
|
|
245
|
+
<pdfaProperty:name>Version</pdfaProperty:name>
|
|
246
|
+
<pdfaProperty:valueType>Text</pdfaProperty:valueType>
|
|
247
|
+
<pdfaProperty:category>external</pdfaProperty:category>
|
|
248
|
+
<pdfaProperty:description>The actual version of the Factur-X XML schema</pdfaProperty:description>
|
|
249
|
+
</rdf:li>
|
|
250
|
+
<rdf:li rdf:parseType="Resource">
|
|
251
|
+
<pdfaProperty:name>ConformanceLevel</pdfaProperty:name>
|
|
252
|
+
<pdfaProperty:valueType>Text</pdfaProperty:valueType>
|
|
253
|
+
<pdfaProperty:category>external</pdfaProperty:category>
|
|
254
|
+
<pdfaProperty:description>The conformance level of the embedded Factur-X data</pdfaProperty:description>
|
|
255
|
+
</rdf:li>
|
|
256
|
+
</rdf:Seq>
|
|
257
|
+
</pdfaSchema:property>
|
|
258
|
+
</rdf:li>
|
|
259
|
+
</rdf:Bag>
|
|
260
|
+
</pdfaExtension:schemas>
|
|
261
|
+
</rdf:Description>
|
|
262
|
+
</rdf:RDF>
|
|
268
263
|
|
|
269
264
|
``factur-x.xml``:
|
|
270
265
|
|
|
@@ -329,33 +324,35 @@ Here is an example of Factur-X document generation.
|
|
|
329
324
|
</rsm:SupplyChainTradeTransaction>
|
|
330
325
|
</rsm:CrossIndustryInvoice>
|
|
331
326
|
|
|
332
|
-
``invoice.
|
|
327
|
+
``invoice.html``:
|
|
328
|
+
|
|
329
|
+
.. code-block:: html
|
|
330
|
+
|
|
331
|
+
<h1>Invoice</h1>
|
|
332
|
+
|
|
333
|
+
Command-line::
|
|
334
|
+
|
|
335
|
+
weasyprint invoice.html invoice.pdf --attachment=factur-x.xml --attachment-relationship=Data --xmp-metadata=rdf.xml --pdf-variant=pdf/a-3a
|
|
336
|
+
|
|
337
|
+
Or Python API:
|
|
333
338
|
|
|
334
339
|
.. code-block:: python
|
|
335
340
|
|
|
336
|
-
from pathlib import Path
|
|
337
341
|
from weasyprint import Attachment, HTML
|
|
338
342
|
|
|
339
|
-
|
|
340
|
-
original_rdf = generate_original_rdf_metadata(metadata, variant, version, conformance)
|
|
341
|
-
return Path("rdf.xml").read_bytes().replace(b"<!-- placeholder -->", original_rdf)
|
|
342
|
-
|
|
343
|
-
document = HTML(string="<h1>Invoice</h1>").render()
|
|
344
|
-
generate_original_rdf_metadata = document.metadata.generate_rdf_metadata
|
|
343
|
+
document = HTML("invoice.html").render()
|
|
345
344
|
|
|
346
345
|
factur_x_xml = Path("factur-x.xml").read_text()
|
|
347
346
|
attachment = Attachment(string=factur_x_xml, name="factur-x.xml", relationship="Data")
|
|
348
347
|
document.metadata.attachments = [attachment]
|
|
349
348
|
|
|
350
|
-
|
|
349
|
+
xmp_metadata = Path("rdf.xml").read_text().encode()
|
|
350
|
+
document.metadata.xmp_metadata = [xmp_metadata]
|
|
351
|
+
|
|
351
352
|
document.write_pdf("invoice.pdf", pdf_variant="pdf/a-3b")
|
|
352
353
|
|
|
353
354
|
Of course, the content of these files has to be adapted to the content of real
|
|
354
|
-
invoices.
|
|
355
|
-
highly recommended.
|
|
356
|
-
|
|
357
|
-
A more detailed blog article is available on `Binary Butterfly’s website
|
|
358
|
-
<https://binary-butterfly.de/artikel/factur-x-zugferd-e-invoices-with-python/>`_.
|
|
355
|
+
invoices.
|
|
359
356
|
|
|
360
357
|
|
|
361
358
|
Include PDF Forms
|
|
@@ -72,9 +72,11 @@ man_pages = [
|
|
|
72
72
|
['Simon Sapin and contributors'], 1)
|
|
73
73
|
]
|
|
74
74
|
|
|
75
|
+
# Don’t autolabel man page titles.
|
|
76
|
+
autosectionlabel_maxdepth = 4
|
|
77
|
+
|
|
75
78
|
# Grouping the document tree into Texinfo files. List of tuples
|
|
76
|
-
# (source start file, target name, title, author,
|
|
77
|
-
# dir menu entry, description, category)
|
|
79
|
+
# (source start file, target name, title, author, dir menu entry, description, category)
|
|
78
80
|
texinfo_documents = [(
|
|
79
81
|
'index', 'WeasyPrint', 'WeasyPrint Documentation',
|
|
80
82
|
'Simon Sapin and contributors', 'WeasyPrint',
|
|
@@ -187,8 +187,8 @@ the latest release.
|
|
|
187
187
|
If you want to use WeasyPrint as a Python library, you’ll have to follow a few
|
|
188
188
|
extra steps. Please read this chapter carefully.
|
|
189
189
|
|
|
190
|
-
The first step is to install the
|
|
191
|
-
Store
|
|
190
|
+
The first step is to install the `Python Install Manager`_ from the Microsoft
|
|
191
|
+
Store.
|
|
192
192
|
|
|
193
193
|
When Python is installed, you have to install Pango and its dependencies. The
|
|
194
194
|
easiest way to install these libraries is to use MSYS2. Here are the steps you
|
|
@@ -202,15 +202,15 @@ You can then launch a Windows command prompt by clicking on the Start menu,
|
|
|
202
202
|
typing ``cmd`` and clicking the "Command Prompt" icon. Install WeasyPrint in a
|
|
203
203
|
`virtual environment`_ using `pip`_::
|
|
204
204
|
|
|
205
|
-
|
|
205
|
+
python -m venv venv
|
|
206
206
|
venv\Scripts\activate.bat
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
python -m pip install weasyprint
|
|
208
|
+
python -m weasyprint --info
|
|
209
209
|
|
|
210
210
|
.. _executable: https://github.com/Kozea/WeasyPrint/releases
|
|
211
211
|
.. _#2081: https://github.com/Kozea/WeasyPrint/issues/2081
|
|
212
212
|
.. _#2092: https://github.com/Kozea/WeasyPrint/issues/2092
|
|
213
|
-
..
|
|
213
|
+
.. _Python Install Manager: https://apps.microsoft.com/detail/9nq7512cxl7t
|
|
214
214
|
.. _MSYS2: https://www.msys2.org/#installation
|
|
215
215
|
|
|
216
216
|
|
|
@@ -482,43 +482,66 @@ WeasyPrint goes through a *URL fetcher* to fetch external resources such as
|
|
|
482
482
|
images or CSS stylesheets. The default fetcher can natively open file and
|
|
483
483
|
HTTP URLs, but the HTTP client does not support advanced features like cookies
|
|
484
484
|
or authentication. This can be worked-around by passing a custom
|
|
485
|
-
|
|
486
|
-
|
|
485
|
+
:class:`URLFetcher <urls.URLFetcher>` to the :class:`HTML` or :class:`CSS`
|
|
486
|
+
classes.
|
|
487
487
|
|
|
488
|
-
|
|
489
|
-
to the default fetcher:
|
|
488
|
+
Some features, such as the timeout delay, can be configured as parameters:
|
|
490
489
|
|
|
491
490
|
.. code-block:: python
|
|
492
491
|
|
|
493
|
-
from weasyprint import
|
|
492
|
+
from weasyprint import HTML
|
|
493
|
+
from weasyprint.urls import URLFetcher
|
|
494
|
+
|
|
495
|
+
HTML(string='<html>', url_fetcher=URLFetcher(timeout=20)).write_pdf('out.pdf')
|
|
496
|
+
|
|
497
|
+
Custom fetchers can also choose to handle some URLs and defer others to the default
|
|
498
|
+
fetcher:
|
|
494
499
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
500
|
+
.. code-block:: python
|
|
501
|
+
|
|
502
|
+
from weasyprint import HTML
|
|
503
|
+
from weasyprint.urls import URLFetcher, URLFetcherResponse
|
|
504
|
+
|
|
505
|
+
class MyFetcher(URLFetcher):
|
|
506
|
+
def fetch(self, url, headers=None):
|
|
507
|
+
if url.startswith('graph:'):
|
|
508
|
+
graph_data = [float(value) for value in url[6:].split(',')]
|
|
509
|
+
string = generate_graph(graph_data)
|
|
510
|
+
return URLFetcherResponse(url, string, {'Content-Type': 'image/png'})
|
|
511
|
+
return super().fetch(url, headers)
|
|
501
512
|
|
|
502
513
|
source = '<img src="graph:42,10.3,87">'
|
|
503
|
-
HTML(string=source, url_fetcher=
|
|
514
|
+
HTML(string=source, url_fetcher=MyFetcher()).write_pdf('out.pdf')
|
|
515
|
+
|
|
516
|
+
By default, all errors raised by the fetcher are caught by WeasyPrint and emit a
|
|
517
|
+
warning. If you want some errors to be fatal and stop the rendering, you can raise a
|
|
518
|
+
:class:`urls.FatalURLFetchingError`.
|
|
519
|
+
|
|
520
|
+
.. code-block:: python
|
|
521
|
+
|
|
522
|
+
from weasyprint import HTML
|
|
523
|
+
from weasyprint.urls import URLFetcher, FatalURLFetchingError
|
|
524
|
+
|
|
525
|
+
class MyFetcher(URLFetcher):
|
|
526
|
+
def fetch(self, url, headers=None):
|
|
527
|
+
try:
|
|
528
|
+
return super().fetch(url, headers)
|
|
529
|
+
except Exception as exception:
|
|
530
|
+
if url.endswith('.css'):
|
|
531
|
+
# Stop the rendering if a problem happens with a stylesheet.
|
|
532
|
+
message = f'Problem with stylesheet at {url}'
|
|
533
|
+
raise FatalURLFetchingError(message) from exception
|
|
534
|
+
else:
|
|
535
|
+
# Raise original error that will be caught by WeasyPrint.
|
|
536
|
+
raise exception
|
|
537
|
+
|
|
538
|
+
HTML(string='<html>', url_fetcher=MyFetcher()).write_pdf('out.pdf')
|
|
504
539
|
|
|
505
540
|
Flask-WeasyPrint_ for Flask_ and Django-Weasyprint_ for Django_ both make
|
|
506
541
|
use of a custom URL fetcher to integrate WeasyPrint and use the filesystem
|
|
507
542
|
instead of a network call for static and media files.
|
|
508
543
|
|
|
509
|
-
A custom fetcher should be returning a :
|
|
510
|
-
|
|
511
|
-
* One of ``string`` (a :obj:`bytestring <bytes>`) or ``file_obj`` (a
|
|
512
|
-
:term:`file object`).
|
|
513
|
-
* Optionally: ``mime_type``, a MIME type extracted e.g. from a *Content-Type*
|
|
514
|
-
header. If not provided, the type is guessed from the file extension in the
|
|
515
|
-
URL.
|
|
516
|
-
* Optionally: ``encoding``, a character encoding extracted e.g. from a
|
|
517
|
-
*charset* parameter in a *Content-Type* header
|
|
518
|
-
* Optionally: ``redirected_url``, the actual URL of the resource if there were
|
|
519
|
-
e.g. HTTP redirects.
|
|
520
|
-
* Optionally: ``filename``, the filename of the resource. Usually derived from
|
|
521
|
-
the *filename* parameter in a *Content-Disposition* header
|
|
544
|
+
A custom fetcher should be returning a :class:`urls.URLFetcherResponse`.
|
|
522
545
|
|
|
523
546
|
If a ``file_obj`` is given, the resource will be closed automatically by
|
|
524
547
|
the function internally used by WeasyPrint to retrieve data.
|
|
@@ -52,7 +52,7 @@ Donation = 'https://opencollective.com/courtbouillon'
|
|
|
52
52
|
|
|
53
53
|
[project.optional-dependencies]
|
|
54
54
|
doc = ['sphinx', 'furo']
|
|
55
|
-
test = ['pytest', 'ruff']
|
|
55
|
+
test = ['pytest', 'ruff', 'Pillow >=12.1.0']
|
|
56
56
|
|
|
57
57
|
[project.scripts]
|
|
58
58
|
weasyprint = 'weasyprint.__main__:main'
|
|
@@ -4,9 +4,9 @@ from math import isclose
|
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
6
|
|
|
7
|
-
from weasyprint import CSS
|
|
7
|
+
from weasyprint import CSS
|
|
8
8
|
from weasyprint.css import find_stylesheets, get_all_computed_styles
|
|
9
|
-
from weasyprint.urls import path2url
|
|
9
|
+
from weasyprint.urls import URLFetcher, path2url
|
|
10
10
|
|
|
11
11
|
from ..testing_utils import ( # isort:skip
|
|
12
12
|
BASE_URL, FakeHTML, assert_no_logs, capture_logs, resource_path)
|
|
@@ -17,9 +17,8 @@ def test_find_stylesheets():
|
|
|
17
17
|
html = FakeHTML(resource_path('doc1.html'))
|
|
18
18
|
|
|
19
19
|
sheets = list(find_stylesheets(
|
|
20
|
-
html.wrapper_element, 'print',
|
|
21
|
-
|
|
22
|
-
layers=None))
|
|
20
|
+
html.wrapper_element, 'print', URLFetcher(), html.base_url, font_config=None,
|
|
21
|
+
counter_style=None, color_profiles=None, page_rules=None, layers=None))
|
|
23
22
|
assert len(sheets) == 2
|
|
24
23
|
# Also test that stylesheets are in tree order.
|
|
25
24
|
sheet_names = [
|
|
@@ -40,7 +40,7 @@ def test_target_counter_attr():
|
|
|
40
40
|
div:first-child { counter-reset: div }
|
|
41
41
|
div { counter-increment: div }
|
|
42
42
|
div::before { content: target-counter(attr(data-count), div) }
|
|
43
|
-
#id2::before { content: target-counter(attr(data-count
|
|
43
|
+
#id2::before { content: target-counter(attr(data-count url), div) }
|
|
44
44
|
#id4::before {
|
|
45
45
|
content: target-counter(attr(data-count), div, lower-alpha) }
|
|
46
46
|
</style>
|
|
@@ -132,6 +132,26 @@ def test_target_text():
|
|
|
132
132
|
assert before.text == '1'
|
|
133
133
|
|
|
134
134
|
|
|
135
|
+
@assert_no_logs
|
|
136
|
+
def test_target_text_whitespace_around_target():
|
|
137
|
+
# Regression test for #1875.
|
|
138
|
+
page, = render_pages('''
|
|
139
|
+
<style>
|
|
140
|
+
a::before { content: target-text(attr(href)) }
|
|
141
|
+
</style>
|
|
142
|
+
<p>before <a href="#ref"></a> after</p>
|
|
143
|
+
<h2 id="ref">text</h2>
|
|
144
|
+
''')
|
|
145
|
+
html, = page.children
|
|
146
|
+
body, = html.children
|
|
147
|
+
p, h2 = body.children
|
|
148
|
+
line, = p.children
|
|
149
|
+
before, a, after = line.children
|
|
150
|
+
assert before.text == 'before '
|
|
151
|
+
assert after.text == ' after'
|
|
152
|
+
assert a.children[0].children[0].text == 'text'
|
|
153
|
+
|
|
154
|
+
|
|
135
155
|
@assert_no_logs
|
|
136
156
|
def test_target_float():
|
|
137
157
|
page, = render_pages('''
|
|
@@ -196,6 +196,7 @@ def test_size_invalid(rule):
|
|
|
196
196
|
('none', ()),
|
|
197
197
|
('translate(6px) rotate(90deg)', (
|
|
198
198
|
('translate', ((6, 'px'), (0, 'px'))), ('rotate', pi / 2))),
|
|
199
|
+
('rotate(0)', (('rotate', 0),)),
|
|
199
200
|
('translate(-4px, 0)', (('translate', ((-4, 'px'), (0, None))),)),
|
|
200
201
|
('translate(6px, 20%)', (('translate', ((6, 'px'), (20, '%'))),)),
|
|
201
202
|
('scale(2)', (('scale', (2, 2)),)),
|
|
@@ -612,6 +613,11 @@ def test_mask_border_mode_invalid(rule):
|
|
|
612
613
|
('test1', (('string', 'string'),)),
|
|
613
614
|
('test2', (('string', 'string'),)))),
|
|
614
615
|
('test attr(class)', (('test', (('attr()', ('class', 'string', '')),)),)),
|
|
616
|
+
('test attr(class url)', (('test', (('attr()', ('class', 'url', '')),)),)),
|
|
617
|
+
('test attr(class, "test")', (
|
|
618
|
+
('test', (('attr()', ('class', 'string', 'test')),)),)),
|
|
619
|
+
('test attr(class string, "test")', (
|
|
620
|
+
('test', (('attr()', ('class', 'string', 'test')),)),)),
|
|
615
621
|
('test counter(count)', (
|
|
616
622
|
('test', (('counter()', ('count', 'decimal')),)),)),
|
|
617
623
|
('test counter(count, upper-roman)', (
|
|
@@ -1267,6 +1273,24 @@ def test_justify_self_invalid(rule):
|
|
|
1267
1273
|
assert_invalid(f'justify-self: {rule}')
|
|
1268
1274
|
|
|
1269
1275
|
|
|
1276
|
+
@assert_no_logs
|
|
1277
|
+
@pytest.mark.parametrize('rule', [
|
|
1278
|
+
'color',
|
|
1279
|
+
'background',
|
|
1280
|
+
'background-color',
|
|
1281
|
+
'border-color',
|
|
1282
|
+
'border-left-color',
|
|
1283
|
+
'outline-color',
|
|
1284
|
+
])
|
|
1285
|
+
@pytest.mark.parametrize('value', [
|
|
1286
|
+
'rgb()',
|
|
1287
|
+
'device-cmyk(0%, 0%, 0%, 30%)',
|
|
1288
|
+
'#abcde',
|
|
1289
|
+
])
|
|
1290
|
+
def test_colors_invalid(rule, value):
|
|
1291
|
+
assert_invalid(f'{rule}: {value}')
|
|
1292
|
+
|
|
1293
|
+
|
|
1270
1294
|
@assert_no_logs
|
|
1271
1295
|
@pytest.mark.parametrize(('rule', 'value'), [
|
|
1272
1296
|
('normal', 'normal'),
|
|
@@ -134,4 +134,4 @@ def html_to_pixels(html):
|
|
|
134
134
|
def document_to_pixels(document):
|
|
135
135
|
"""Render an HTML document to PNG, check its size and return pixel data."""
|
|
136
136
|
image = Image.open(io.BytesIO(document.write_png()))
|
|
137
|
-
return image.width, image.height, image.
|
|
137
|
+
return image.width, image.height, image.get_flattened_data()
|