weasyprint 68.0__py3-none-any.whl → 68.1__py3-none-any.whl
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/__init__.py +1 -1
- weasyprint/css/__init__.py +3 -4
- weasyprint/draw/text.py +8 -8
- weasyprint/layout/block.py +22 -16
- weasyprint/layout/preferred.py +29 -23
- weasyprint/pdf/stream.py +2 -0
- weasyprint/svg/__init__.py +1 -2
- weasyprint/svg/defs.py +0 -6
- weasyprint/svg/text.py +4 -3
- weasyprint/text/line_break.py +4 -5
- weasyprint/urls.py +24 -7
- {weasyprint-68.0.dist-info → weasyprint-68.1.dist-info}/METADATA +1 -1
- {weasyprint-68.0.dist-info → weasyprint-68.1.dist-info}/RECORD +16 -16
- {weasyprint-68.0.dist-info → weasyprint-68.1.dist-info}/WHEEL +0 -0
- {weasyprint-68.0.dist-info → weasyprint-68.1.dist-info}/entry_points.txt +0 -0
- {weasyprint-68.0.dist-info → weasyprint-68.1.dist-info}/licenses/LICENSE +0 -0
weasyprint/__init__.py
CHANGED
|
@@ -14,7 +14,7 @@ import cssselect2
|
|
|
14
14
|
import tinycss2
|
|
15
15
|
import tinyhtml5
|
|
16
16
|
|
|
17
|
-
VERSION = __version__ = '68.
|
|
17
|
+
VERSION = __version__ = '68.1'
|
|
18
18
|
|
|
19
19
|
#: Default values for command-line and Python API rendering options. See
|
|
20
20
|
#: :func:`__main__.main` to learn more about specific options for
|
weasyprint/css/__init__.py
CHANGED
|
@@ -779,7 +779,6 @@ def resolve_math(token, computed=None, property_name=None, refer_to=None):
|
|
|
779
779
|
return
|
|
780
780
|
|
|
781
781
|
args = []
|
|
782
|
-
original_token = token
|
|
783
782
|
function = Function(token)
|
|
784
783
|
if function.name is None:
|
|
785
784
|
return
|
|
@@ -795,7 +794,7 @@ def resolve_math(token, computed=None, property_name=None, refer_to=None):
|
|
|
795
794
|
if function.name == 'calc':
|
|
796
795
|
result = _resolve_calc_sum(computed, args[0], property_name, refer_to)
|
|
797
796
|
if result is None:
|
|
798
|
-
return
|
|
797
|
+
return
|
|
799
798
|
else:
|
|
800
799
|
return tokenize(result)
|
|
801
800
|
|
|
@@ -1194,10 +1193,10 @@ class ComputedStyle(dict):
|
|
|
1194
1193
|
try:
|
|
1195
1194
|
token = resolve_math(function, self, key)
|
|
1196
1195
|
except PercentageInMath:
|
|
1197
|
-
token = None
|
|
1198
|
-
if token is None:
|
|
1199
1196
|
solved_tokens.append(function)
|
|
1200
1197
|
else:
|
|
1198
|
+
if token is None:
|
|
1199
|
+
raise Exception
|
|
1201
1200
|
solved_tokens.append(token)
|
|
1202
1201
|
original_key = key.replace('_', '-')
|
|
1203
1202
|
value = validate_non_shorthand(solved_tokens, original_key)[0][1]
|
weasyprint/draw/text.py
CHANGED
|
@@ -17,6 +17,8 @@ from .color import get_color
|
|
|
17
17
|
|
|
18
18
|
def draw_text(stream, textbox, offset_x, text_overflow, block_ellipsis):
|
|
19
19
|
"""Draw a textbox to a pydyf stream."""
|
|
20
|
+
from ..layout.percent import percentage
|
|
21
|
+
|
|
20
22
|
# Pango crashes with font-size: 0.
|
|
21
23
|
assert textbox.style['font_size']
|
|
22
24
|
|
|
@@ -30,11 +32,10 @@ def draw_text(stream, textbox, offset_x, text_overflow, block_ellipsis):
|
|
|
30
32
|
if 'underline' in text_decoration_values or 'overline' in text_decoration_values:
|
|
31
33
|
if textbox.style['text_decoration_thickness'] in ('auto', 'from-font'):
|
|
32
34
|
thickness = textbox.pango_layout.underline_thickness
|
|
33
|
-
elif textbox.style['text_decoration_thickness'].unit == '%':
|
|
34
|
-
ratio = textbox.style['text_decoration_thickness'].value / 100
|
|
35
|
-
thickness = textbox.style['font_size'] * ratio
|
|
36
35
|
else:
|
|
37
|
-
thickness =
|
|
36
|
+
thickness = percentage(
|
|
37
|
+
textbox.style['text_decoration_thickness'], textbox.style,
|
|
38
|
+
textbox.style['font_size'])
|
|
38
39
|
if 'overline' in text_decoration_values:
|
|
39
40
|
offset_y = (
|
|
40
41
|
textbox.baseline - textbox.pango_layout.ascent + thickness / 2)
|
|
@@ -44,11 +45,10 @@ def draw_text(stream, textbox, offset_x, text_overflow, block_ellipsis):
|
|
|
44
45
|
if 'underline' in text_decoration_values:
|
|
45
46
|
if textbox.style['text_underline_offset'] == 'auto':
|
|
46
47
|
underline_offset = - textbox.pango_layout.underline_position
|
|
47
|
-
elif textbox.style['text_underline_offset'].unit == '%':
|
|
48
|
-
ratio = textbox.style['text_underline_offset'].value / 100
|
|
49
|
-
underline_offset = textbox.style['font_size'] * ratio
|
|
50
48
|
else:
|
|
51
|
-
underline_offset =
|
|
49
|
+
underline_offset = percentage(
|
|
50
|
+
textbox.style['text_underline_offset'], textbox.style,
|
|
51
|
+
textbox.style['font_size'])
|
|
52
52
|
offset_y = textbox.baseline + underline_offset + thickness / 2
|
|
53
53
|
draw_text_decoration(
|
|
54
54
|
stream, textbox, offset_x, offset_y, thickness,
|
weasyprint/layout/block.py
CHANGED
|
@@ -301,7 +301,7 @@ def _out_of_flow_layout(context, box, index, child, new_children,
|
|
|
301
301
|
return stop, resume_at, new_child, out_of_flow_resume_at
|
|
302
302
|
|
|
303
303
|
|
|
304
|
-
def _break_line(context, box, line, new_children,
|
|
304
|
+
def _break_line(context, box, line, new_children, needed, page_is_empty, index,
|
|
305
305
|
skip_stack, resume_at, absolute_boxes, fixed_boxes):
|
|
306
306
|
"""Break line where allowed by orphans and widows.
|
|
307
307
|
|
|
@@ -316,7 +316,6 @@ def _break_line(context, box, line, new_children, next_lines, page_is_empty, ind
|
|
|
316
316
|
return True, False, resume_at
|
|
317
317
|
# How many lines we need on the next page to satisfy widows
|
|
318
318
|
# -1 for the current line.
|
|
319
|
-
needed = max(box.style['widows'] - 1 - next_lines, 0)
|
|
320
319
|
if needed > over_orphans and not page_is_empty:
|
|
321
320
|
# Total number of lines < orphans + widows
|
|
322
321
|
remove_placeholders(context, line.children, absolute_boxes, fixed_boxes)
|
|
@@ -377,15 +376,21 @@ def _linebox_layout(context, box, index, child, new_children, page_is_empty,
|
|
|
377
376
|
# If we couldn’t break the line before but can break now, first try to
|
|
378
377
|
# report footnotes and see if we don’t overflow.
|
|
379
378
|
could_break_before = can_break_now = True
|
|
380
|
-
|
|
379
|
+
needed = box.style['widows'] - 1
|
|
380
|
+
for _ in lines_iterator:
|
|
381
|
+
needed -= 1
|
|
382
|
+
# Don’t iterate over all lines as it can be long.
|
|
383
|
+
if needed == -1:
|
|
384
|
+
break
|
|
381
385
|
if len(new_children) + 1 < box.style['orphans']:
|
|
382
386
|
can_break_now = False
|
|
383
|
-
elif
|
|
387
|
+
elif needed >= 0:
|
|
384
388
|
can_break_now = False
|
|
385
389
|
if len(new_children) < box.style['orphans']:
|
|
386
390
|
could_break_before = False
|
|
387
|
-
elif
|
|
391
|
+
elif needed > 0:
|
|
388
392
|
could_break_before = False
|
|
393
|
+
needed = max(0, needed)
|
|
389
394
|
report = not context.in_column and can_break_now and not could_break_before
|
|
390
395
|
reported_footnotes = 0
|
|
391
396
|
while report and context.current_page_footnotes:
|
|
@@ -397,9 +402,8 @@ def _linebox_layout(context, box, index, child, new_children, page_is_empty,
|
|
|
397
402
|
break
|
|
398
403
|
else:
|
|
399
404
|
abort, stop, resume_at = _break_line(
|
|
400
|
-
context, box, line, new_children,
|
|
401
|
-
|
|
402
|
-
fixed_boxes)
|
|
405
|
+
context, box, line, new_children, needed, page_is_empty, index,
|
|
406
|
+
skip_stack, resume_at, absolute_boxes, fixed_boxes)
|
|
403
407
|
|
|
404
408
|
# Revert reported footnotes, as they’ve been reported starting from the last
|
|
405
409
|
# one.
|
|
@@ -414,8 +418,7 @@ def _linebox_layout(context, box, index, child, new_children, page_is_empty,
|
|
|
414
418
|
# "When an unforced page break occurs here, both the adjoining
|
|
415
419
|
# ‘margin-top’ and ‘margin-bottom’ are set to zero."
|
|
416
420
|
# See issue #115.
|
|
417
|
-
elif page_is_empty and context.overflows_page(
|
|
418
|
-
bottom_space, new_position_y):
|
|
421
|
+
elif page_is_empty and context.overflows_page(bottom_space, new_position_y):
|
|
419
422
|
# Remove the top border when a page is empty and the box is
|
|
420
423
|
# too high to be drawn in one page
|
|
421
424
|
new_position_y -= box.margin_top
|
|
@@ -433,8 +436,7 @@ def _linebox_layout(context, box, index, child, new_children, page_is_empty,
|
|
|
433
436
|
overflow = (
|
|
434
437
|
overflow or
|
|
435
438
|
context.reported_footnotes or
|
|
436
|
-
context.overflows_page(
|
|
437
|
-
bottom_space, new_position_y + offset_y))
|
|
439
|
+
context.overflows_page(bottom_space, new_position_y + offset_y))
|
|
438
440
|
if overflow:
|
|
439
441
|
context.report_footnote(footnote)
|
|
440
442
|
# If we've put other content on this page, then we may want
|
|
@@ -443,11 +445,15 @@ def _linebox_layout(context, box, index, child, new_children, page_is_empty,
|
|
|
443
445
|
# even try.
|
|
444
446
|
if new_children or not page_is_empty:
|
|
445
447
|
if footnote.style['footnote_policy'] == 'line':
|
|
446
|
-
|
|
448
|
+
if needed := box.style['widows'] - 1:
|
|
449
|
+
for _ in lines_iterator:
|
|
450
|
+
needed -= 1
|
|
451
|
+
# Don’t iterate over all lines as it can be long.
|
|
452
|
+
if needed == 0:
|
|
453
|
+
break
|
|
447
454
|
abort, stop, resume_at = _break_line(
|
|
448
|
-
context, box, line, new_children,
|
|
449
|
-
|
|
450
|
-
skip_stack, resume_at, absolute_boxes,
|
|
455
|
+
context, box, line, new_children, needed, page_is_empty,
|
|
456
|
+
index, skip_stack, resume_at, absolute_boxes,
|
|
451
457
|
fixed_boxes)
|
|
452
458
|
break_linebox = True
|
|
453
459
|
break
|
weasyprint/layout/preferred.py
CHANGED
|
@@ -109,7 +109,7 @@ def _block_content_width(context, box, function, outer):
|
|
|
109
109
|
|
|
110
110
|
for value in ('padding_left', 'padding_right'):
|
|
111
111
|
style_value = box.style[value]
|
|
112
|
-
if style_value != 'auto':
|
|
112
|
+
if style_value != 'auto' and not check_math(style_value):
|
|
113
113
|
if style_value.unit.lower() == 'px':
|
|
114
114
|
width -= style_value.value
|
|
115
115
|
else:
|
|
@@ -175,7 +175,7 @@ def margin_width(box, width, left=True, right=True):
|
|
|
175
175
|
(['margin_right', 'padding_right'] if right else [])
|
|
176
176
|
):
|
|
177
177
|
style_value = box.style[value]
|
|
178
|
-
if style_value != 'auto':
|
|
178
|
+
if style_value != 'auto' and not check_math(style_value):
|
|
179
179
|
if style_value.unit.lower() == 'px':
|
|
180
180
|
width += style_value.value
|
|
181
181
|
else:
|
|
@@ -263,7 +263,7 @@ def inline_max_content_width(context, box, outer=True, is_line_start=False):
|
|
|
263
263
|
def column_group_content_width(context, box):
|
|
264
264
|
"""Return the *-content width for a ``TableColumnGroupBox``."""
|
|
265
265
|
width = box.style['width']
|
|
266
|
-
if width == 'auto' or width.unit == '%':
|
|
266
|
+
if width == 'auto' or check_math(width) or width.unit == '%':
|
|
267
267
|
width = 0
|
|
268
268
|
else:
|
|
269
269
|
assert width.unit.lower() == 'px'
|
|
@@ -597,21 +597,22 @@ def table_and_columns_preferred_widths(context, box, outer=True):
|
|
|
597
597
|
# Define constrainedness
|
|
598
598
|
constrainedness = [False for i in range(grid_width)]
|
|
599
599
|
for i in range(grid_width):
|
|
600
|
-
if
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
continue
|
|
604
|
-
if (columns[i] and columns[i].style['width'] != 'auto' and
|
|
605
|
-
columns[i].style['width'].unit != '%'):
|
|
606
|
-
constrainedness[i] = True
|
|
607
|
-
continue
|
|
608
|
-
for cell in zipped_grid[i]:
|
|
609
|
-
if (cell and cell.colspan == 1 and
|
|
610
|
-
cell.style['width'] != 'auto' and
|
|
611
|
-
not check_math(cell.style['width']) and
|
|
612
|
-
cell.style['width'].unit != '%'):
|
|
600
|
+
if column_groups[i]:
|
|
601
|
+
width = column_groups[i].style['width']
|
|
602
|
+
if width != 'auto' and not check_math(width) and width.unit != '%':
|
|
613
603
|
constrainedness[i] = True
|
|
614
|
-
|
|
604
|
+
continue
|
|
605
|
+
if columns[i]:
|
|
606
|
+
width = columns[i].style['width']
|
|
607
|
+
if width != 'auto' and not check_math(width) and width.unit != '%':
|
|
608
|
+
constrainedness[i] = True
|
|
609
|
+
continue
|
|
610
|
+
for cell in zipped_grid[i]:
|
|
611
|
+
if cell and cell.colspan == 1:
|
|
612
|
+
width = cell.style['width']
|
|
613
|
+
if width != 'auto' and not check_math(width) and width.unit != '%':
|
|
614
|
+
constrainedness[i] = True
|
|
615
|
+
break
|
|
615
616
|
|
|
616
617
|
intrinsic_percentages = [
|
|
617
618
|
min(percentage, 100 - sum(intrinsic_percentages[:i]))
|
|
@@ -679,7 +680,8 @@ def table_and_columns_preferred_widths(context, box, outer=True):
|
|
|
679
680
|
sum(max_content_widths), large_percentage_contribution,
|
|
680
681
|
*small_percentage_contributions]))
|
|
681
682
|
|
|
682
|
-
|
|
683
|
+
width = table.style['width']
|
|
684
|
+
if width != 'auto' and not check_math(width) and width.unit.lower() == 'px':
|
|
683
685
|
# "percentages on the following properties are treated instead as
|
|
684
686
|
# though they were the following: width: auto"
|
|
685
687
|
# https://dbaron.org/css/intrinsic/#outer-intrinsic
|
|
@@ -714,12 +716,16 @@ def replaced_min_content_width(box, outer=True):
|
|
|
714
716
|
width = box.style['width']
|
|
715
717
|
if width == 'auto':
|
|
716
718
|
height = box.style['height']
|
|
717
|
-
if height == 'auto' or height.unit == '%':
|
|
719
|
+
if height == 'auto' or check_math(height) or height.unit == '%':
|
|
718
720
|
height = 'auto'
|
|
719
721
|
else:
|
|
720
722
|
assert height.unit.lower() == 'px'
|
|
721
723
|
height = height.value
|
|
722
|
-
|
|
724
|
+
unknown_max_width = (
|
|
725
|
+
box.style['max_width'] != 'auto' and
|
|
726
|
+
not check_math(box.style['max_width']) and
|
|
727
|
+
box.style['max_width'].unit == '%')
|
|
728
|
+
if unknown_max_width:
|
|
723
729
|
# See https://drafts.csswg.org/css-sizing/#intrinsic-contribution
|
|
724
730
|
width = 0
|
|
725
731
|
else:
|
|
@@ -730,7 +736,7 @@ def replaced_min_content_width(box, outer=True):
|
|
|
730
736
|
width, _ = default_image_sizing(
|
|
731
737
|
intrinsic_width, intrinsic_height, intrinsic_ratio, 'auto',
|
|
732
738
|
height, default_width=0, default_height=0)
|
|
733
|
-
elif box.style['width'].unit == '%':
|
|
739
|
+
elif check_math(box.style['width']) or box.style['width'].unit == '%':
|
|
734
740
|
# See https://drafts.csswg.org/css-sizing/#intrinsic-contribution
|
|
735
741
|
width = 0
|
|
736
742
|
else:
|
|
@@ -744,7 +750,7 @@ def replaced_max_content_width(box, outer=True):
|
|
|
744
750
|
width = box.style['width']
|
|
745
751
|
if width == 'auto':
|
|
746
752
|
height = box.style['height']
|
|
747
|
-
if height == 'auto' or height.unit == '%':
|
|
753
|
+
if height == 'auto' or check_math(height) or height.unit == '%':
|
|
748
754
|
height = 'auto'
|
|
749
755
|
else:
|
|
750
756
|
assert height.unit.lower() == 'px'
|
|
@@ -756,7 +762,7 @@ def replaced_max_content_width(box, outer=True):
|
|
|
756
762
|
width, _ = default_image_sizing(
|
|
757
763
|
intrinsic_width, intrinsic_height, intrinsic_ratio, 'auto', height,
|
|
758
764
|
default_width=300, default_height=150)
|
|
759
|
-
elif box.style['width'].unit == '%':
|
|
765
|
+
elif check_math(box.style['width']) or box.style['width'].unit == '%':
|
|
760
766
|
# See https://drafts.csswg.org/css-sizing/#intrinsic-contribution
|
|
761
767
|
width = 0
|
|
762
768
|
else:
|
weasyprint/pdf/stream.py
CHANGED
weasyprint/svg/__init__.py
CHANGED
|
@@ -9,7 +9,7 @@ from cssselect2 import ElementWrapper
|
|
|
9
9
|
|
|
10
10
|
from ..urls import get_url_attribute
|
|
11
11
|
from .css import parse_declarations, parse_stylesheets
|
|
12
|
-
from .defs import apply_filters,
|
|
12
|
+
from .defs import apply_filters, draw_gradient_or_pattern, paint_mask, use
|
|
13
13
|
from .images import image, svg
|
|
14
14
|
from .path import path
|
|
15
15
|
from .shapes import circle, ellipse, line, polygon, polyline, rect
|
|
@@ -24,7 +24,6 @@ from .utils import ( # isort:skip
|
|
|
24
24
|
TAGS = {
|
|
25
25
|
'a': text,
|
|
26
26
|
'circle': circle,
|
|
27
|
-
'clipPath': clip_path,
|
|
28
27
|
'ellipse': ellipse,
|
|
29
28
|
'image': image,
|
|
30
29
|
'line': line,
|
weasyprint/svg/defs.py
CHANGED
|
@@ -517,9 +517,3 @@ def paint_mask(svg, node, mask, font_size):
|
|
|
517
517
|
svg.stream = svg.stream.set_alpha_state(x, y, width, height)
|
|
518
518
|
svg.draw_node(mask, font_size)
|
|
519
519
|
svg.stream = svg_stream
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
def clip_path(svg, node, font_size):
|
|
523
|
-
"""Store a clip path definition."""
|
|
524
|
-
if 'id' in node.attrib:
|
|
525
|
-
svg.paths[node.attrib['id']] = node
|
weasyprint/svg/text.py
CHANGED
|
@@ -141,7 +141,7 @@ def text(svg, node, font_size):
|
|
|
141
141
|
svg.cursor_d_position[1] = 0
|
|
142
142
|
svg.cursor_d_position[0] += dx or 0
|
|
143
143
|
svg.cursor_d_position[1] += dy or 0
|
|
144
|
-
layout, _, _, width, height,
|
|
144
|
+
layout, _, _, width, height, baseline = split_first_line(
|
|
145
145
|
letter, style, svg.context, inf, 0)
|
|
146
146
|
x = svg.cursor_position[0] if x is None else x
|
|
147
147
|
y = svg.cursor_position[1] if y is None else y
|
|
@@ -154,8 +154,9 @@ def text(svg, node, font_size):
|
|
|
154
154
|
y_position = y + svg.cursor_d_position[1] + y_align
|
|
155
155
|
angle = last_r if r is None else r
|
|
156
156
|
points = (
|
|
157
|
-
(x_position, y_position),
|
|
158
|
-
(x_position + width, y_position - height))
|
|
157
|
+
(x_position, y_position - baseline),
|
|
158
|
+
(x_position + width, y_position - baseline + height))
|
|
159
|
+
# TODO: Use ink extents instead of logical from line_break.line_size().
|
|
159
160
|
node.text_bounding_box = extend_bounding_box(
|
|
160
161
|
node.text_bounding_box, points)
|
|
161
162
|
|
weasyprint/text/line_break.py
CHANGED
|
@@ -256,6 +256,8 @@ def split_first_line(text, style, context, max_width, justification_spacing,
|
|
|
256
256
|
``baseline``: baseline in pixels of the first line
|
|
257
257
|
|
|
258
258
|
"""
|
|
259
|
+
from ..layout.percent import percentage
|
|
260
|
+
|
|
259
261
|
# See https://www.w3.org/TR/css-text-3/#white-space-property
|
|
260
262
|
text_wrap = style['white_space'] in ('normal', 'pre-wrap', 'pre-line')
|
|
261
263
|
space_collapse = style['white_space'] in ('normal', 'nowrap', 'pre-line')
|
|
@@ -392,11 +394,8 @@ def split_first_line(text, style, context, max_width, justification_spacing,
|
|
|
392
394
|
# This word is long enough.
|
|
393
395
|
first_line_width, _ = line_size(first_line, style)
|
|
394
396
|
space = max_width - first_line_width
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
max_width * style['hyphenate_limit_zone'].value / 100)
|
|
398
|
-
else:
|
|
399
|
-
limit_zone = style['hyphenate_limit_zone'].value
|
|
397
|
+
limit_zone = percentage(
|
|
398
|
+
style['hyphenate_limit_zone'], style, max_width)
|
|
400
399
|
if space > limit_zone or space < 0:
|
|
401
400
|
# Available space is worth the try, or the line is even too long
|
|
402
401
|
# to fit: try to hyphenate.
|
weasyprint/urls.py
CHANGED
|
@@ -330,17 +330,18 @@ class URLFetcher(request.OpenerDirector):
|
|
|
330
330
|
|
|
331
331
|
"""
|
|
332
332
|
# Discard URLs with no or invalid protocol.
|
|
333
|
-
if not UNICODE_SCHEME_RE.match(url): # pragma: no cover
|
|
333
|
+
if not (match := UNICODE_SCHEME_RE.match(url)): # pragma: no cover
|
|
334
334
|
raise ValueError(f'Not an absolute URI: {url}')
|
|
335
|
+
scheme = match[1].lower()
|
|
335
336
|
|
|
336
337
|
# Discard URLs with forbidden protocol.
|
|
337
338
|
if self._allowed_protocols is not None:
|
|
338
|
-
if
|
|
339
|
+
if scheme not in self._allowed_protocols:
|
|
339
340
|
raise ValueError(f'URI uses disallowed protocol: {url}')
|
|
340
341
|
|
|
341
342
|
# Remove query and fragment parts from file URLs.
|
|
342
343
|
# See https://bugs.python.org/issue34702.
|
|
343
|
-
if
|
|
344
|
+
if scheme == 'file':
|
|
344
345
|
url = url.split('?')[0]
|
|
345
346
|
|
|
346
347
|
# Transform Unicode IRI to ASCII URI.
|
|
@@ -385,7 +386,7 @@ class URLFetcherResponse:
|
|
|
385
386
|
:param body: The body of the HTTP response.
|
|
386
387
|
:type headers: dict or email.message.EmailMessage
|
|
387
388
|
:param headers: The headers of the HTTP response.
|
|
388
|
-
:param
|
|
389
|
+
:param int status: The status of the HTTP response.
|
|
389
390
|
|
|
390
391
|
Has the same interface as :class:`urllib.response.addinfourl`.
|
|
391
392
|
|
|
@@ -395,7 +396,7 @@ class URLFetcherResponse:
|
|
|
395
396
|
is used elsewhere, the file object has to be closed manually.
|
|
396
397
|
|
|
397
398
|
"""
|
|
398
|
-
def __init__(self, url, body=None, headers=None, status=
|
|
399
|
+
def __init__(self, url, body=None, headers=None, status=200, **kwargs):
|
|
399
400
|
self.url = url
|
|
400
401
|
self.status = status
|
|
401
402
|
|
|
@@ -404,7 +405,10 @@ class URLFetcherResponse:
|
|
|
404
405
|
else:
|
|
405
406
|
self.headers = EmailMessage()
|
|
406
407
|
for key, value in (headers or {}).items():
|
|
407
|
-
|
|
408
|
+
try:
|
|
409
|
+
self.headers[key] = value
|
|
410
|
+
except ValueError:
|
|
411
|
+
pass # Ignore forbidden duplicated headers.
|
|
408
412
|
|
|
409
413
|
if hasattr(body, 'read'):
|
|
410
414
|
self._file_obj = body
|
|
@@ -440,6 +444,19 @@ class URLFetcherResponse:
|
|
|
440
444
|
def charset(self):
|
|
441
445
|
return self.headers.get_param('charset')
|
|
442
446
|
|
|
447
|
+
def geturl(self):
|
|
448
|
+
return self.url
|
|
449
|
+
|
|
450
|
+
def info(self):
|
|
451
|
+
return self.headers
|
|
452
|
+
|
|
453
|
+
@property
|
|
454
|
+
def code(self):
|
|
455
|
+
return self.status
|
|
456
|
+
|
|
457
|
+
def getcode(self):
|
|
458
|
+
return self.status
|
|
459
|
+
|
|
443
460
|
|
|
444
461
|
@contextlib.contextmanager
|
|
445
462
|
def fetch(url_fetcher, url):
|
|
@@ -467,7 +484,7 @@ def fetch(url_fetcher, url):
|
|
|
467
484
|
resource['body'] = resource.get('file_obj', resource.get('string'))
|
|
468
485
|
content_type = resource.get('mime_type', 'application/octet-stream')
|
|
469
486
|
if charset := resource.get('encoding'):
|
|
470
|
-
content_type += f';{charset}'
|
|
487
|
+
content_type += f'; charset={charset}'
|
|
471
488
|
resource['headers'] = {'Content-Type': content_type}
|
|
472
489
|
resource = URLFetcherResponse(**resource)
|
|
473
490
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
weasyprint/__init__.py,sha256=
|
|
1
|
+
weasyprint/__init__.py,sha256=Z8RQi3arBn0J5Wlpm56inGnfXYuen9NRT2WyNqxS5q8,14949
|
|
2
2
|
weasyprint/__main__.py,sha256=L6pqmXo68pHGPkXth8obc9DlUHYdc3YXwDG5bCky4Pc,9374
|
|
3
3
|
weasyprint/anchors.py,sha256=fytc05l3TO4AWuyPJx532RBEbZe8L7UlnbYYJpB-bGA,6472
|
|
4
4
|
weasyprint/document.py,sha256=W_pmP05WT_bucoU7eTwkYuYMGG6h-19ZpdVZZcbxpAc,13681
|
|
@@ -7,8 +7,8 @@ weasyprint/images.py,sha256=nh1RXq7-8M2dzuOX7gLRwmHDm7LVwulTGcgOsgB_Fr8,36372
|
|
|
7
7
|
weasyprint/logger.py,sha256=z1q548fX5shfAyLoMLeM9ozWGKgoBTKQsdlTtfRE_9U,1824
|
|
8
8
|
weasyprint/matrix.py,sha256=v1BPtyn_-S_4TrAUgzOOR-viUXgdqsABKRndCEprkPc,1909
|
|
9
9
|
weasyprint/stacking.py,sha256=6c6eZ_BxtcYvlEbH6JQdqaKwYBkuaqUwGGSs3OfkpS8,5697
|
|
10
|
-
weasyprint/urls.py,sha256=
|
|
11
|
-
weasyprint/css/__init__.py,sha256=
|
|
10
|
+
weasyprint/urls.py,sha256=6ZsVvV5TKHH1lyXvAkeV0qIgMavWKWKVjLvS7aMagRE,18287
|
|
11
|
+
weasyprint/css/__init__.py,sha256=rCwc157BawGI6j1z_ymYmjT-_-0jEUDVw1DYdJPW9OM,77514
|
|
12
12
|
weasyprint/css/computed_values.py,sha256=WPySY5DFXusCxa7wC5mUv4uzwBi2c7ACMLI3_iHqDnI,24187
|
|
13
13
|
weasyprint/css/counters.py,sha256=RAUuZGOLZj5oKrZexbkDUYPncTFWzwtT870xTKYkQmI,11374
|
|
14
14
|
weasyprint/css/functions.py,sha256=PXPZX0EJKI1FL_ydPGLueICMTHPxwiZwQr74vWpEaMY,6779
|
|
@@ -27,13 +27,13 @@ weasyprint/css/validation/properties.py,sha256=DYjW8TZl_y_cedVkleY6kTVw6G3nUlDsp
|
|
|
27
27
|
weasyprint/draw/__init__.py,sha256=l4q_L6k93tIobB8hHui_PSElstO5MI5FTHCBTISb_ew,22715
|
|
28
28
|
weasyprint/draw/border.py,sha256=5s-FZyw3MN085cmmAJHp8Yms5gM90j-XzInpwldgPFs,30373
|
|
29
29
|
weasyprint/draw/color.py,sha256=xoqq6LmkyN1xdubX0Qm-MKy7xijzT3Zd7kF2MSaqZiQ,1449
|
|
30
|
-
weasyprint/draw/text.py,sha256=
|
|
30
|
+
weasyprint/draw/text.py,sha256=vHzgHNGiTB8TGJw1GOOAVCzj4ZOnREQ2enbRJL0kVzM,12444
|
|
31
31
|
weasyprint/formatting_structure/boxes.py,sha256=QDX3FRmSY7pG6QjWTuhANlSMrePNRPm1iX5-CJ8tU98,27199
|
|
32
32
|
weasyprint/formatting_structure/build.py,sha256=j_pKsHxsNt-ErNj-TT12QczQa6RszPOWjDztqzH5yMo,58491
|
|
33
33
|
weasyprint/layout/__init__.py,sha256=mUlsoqBIamjdIqtINS9W0njkrgn8guyYORu3UCedon0,16767
|
|
34
34
|
weasyprint/layout/absolute.py,sha256=JA4mjOweZt2h-Hrsa91nHnvzZDnF-gneMpZfcXiTugc,14005
|
|
35
35
|
weasyprint/layout/background.py,sha256=IfcmSZ-E4_NES-RSeKi5DGbmrloGdu9zVz5zZ87m9gU,10023
|
|
36
|
-
weasyprint/layout/block.py,sha256=
|
|
36
|
+
weasyprint/layout/block.py,sha256=I5E7-aTPbkEqIHLcm8PJNXCfq32XbDmu6a9jv8czUBA,48990
|
|
37
37
|
weasyprint/layout/column.py,sha256=g64aPoNZYpPlrma4F1nyrW7_ji5DBYoamA92YrbFHZM,17209
|
|
38
38
|
weasyprint/layout/flex.py,sha256=KZNFElr2QDT5FYI6JlZGpXxJHYFvMMN8QGylLx98PUs,44148
|
|
39
39
|
weasyprint/layout/float.py,sha256=5iBDHg1KSexArW1SfbnMShuILzkkEH8DW7n1bdk5OU4,9488
|
|
@@ -43,7 +43,7 @@ weasyprint/layout/leader.py,sha256=wklI0aLyTx0VJhqU7D_FxtJpfe7dXswcN-VApAusM-Q,2
|
|
|
43
43
|
weasyprint/layout/min_max.py,sha256=JdXJG9ISO_RsfeHua_-3g477a16I-NrnYuwH_tQwq4o,1527
|
|
44
44
|
weasyprint/layout/page.py,sha256=m4z24NqI6bc08j1GwXsRCpyMkKxC93XE6--QMHUaKxM,41565
|
|
45
45
|
weasyprint/layout/percent.py,sha256=F2kNcNz7b6to70GwiFFu-oWWpYs011TM021COH7feEc,5829
|
|
46
|
-
weasyprint/layout/preferred.py,sha256=
|
|
46
|
+
weasyprint/layout/preferred.py,sha256=ZZAc7tbn5Rdl9DjgXgnT4J9sBBljNXvY5qj47HjUXGM,35288
|
|
47
47
|
weasyprint/layout/replaced.py,sha256=7-foaAPIAVC329QEnUN_1u2U6VTrEbQ0Qx254BlrLCo,11357
|
|
48
48
|
weasyprint/layout/table.py,sha256=KyFOg9aiMl_wO31_0kQ7WrCVeHtGJY0Ir-hdub2qSSg,47778
|
|
49
49
|
weasyprint/pdf/__init__.py,sha256=5OG1Tgdyk1XPhcren50OY2S9ZLT4SseIajlEhDl7PSw,14303
|
|
@@ -55,23 +55,23 @@ weasyprint/pdf/pdfa.py,sha256=JDKtJ3-v-i2CMWScTbesZi3YQ8C-5PYOheYAYM5Y1iw,4239
|
|
|
55
55
|
weasyprint/pdf/pdfua.py,sha256=RrV7qky5Djc_tP5ipdDUDC5BqOi6T_LDZpVy8cyXRGc,486
|
|
56
56
|
weasyprint/pdf/pdfx.py,sha256=1DB9afper1oZpmoktSxBvRTpUuxHj7TBy3dhXdD2qGc,2629
|
|
57
57
|
weasyprint/pdf/sRGB2014.icc,sha256=OEuDLeNBIGZ0O1KnXukGtvufuNngnpNvwsQyI4Fcbgo,3024
|
|
58
|
-
weasyprint/pdf/stream.py,sha256=
|
|
58
|
+
weasyprint/pdf/stream.py,sha256=7L7EcGhxwDp06VSqgVWVP2ZgpIdJ35LPLE6IAN4sQzQ,11615
|
|
59
59
|
weasyprint/pdf/tags.py,sha256=914AozTYgFOMpFSP2UtEZCVzsPIKueHWjI9DA77w28M,11789
|
|
60
|
-
weasyprint/svg/__init__.py,sha256=
|
|
60
|
+
weasyprint/svg/__init__.py,sha256=96DOr-LUCMiEOL81QbgpnPL96Bw9ItPDMb9AUvxygJU,32181
|
|
61
61
|
weasyprint/svg/bounding_box.py,sha256=auXs-vD2nvOx3cplHLGXFzy7X_f_IY4hg_IzKlUTXjM,13129
|
|
62
62
|
weasyprint/svg/css.py,sha256=MohmaDCX6oDIIxJPrn6bn1fKq4la0oPfxvMYrfL5vbI,4871
|
|
63
|
-
weasyprint/svg/defs.py,sha256=
|
|
63
|
+
weasyprint/svg/defs.py,sha256=kkuNKYp9ymb1hK-w45_ClV9iGWULyEGmXhazmAUnXF8,20774
|
|
64
64
|
weasyprint/svg/images.py,sha256=msVOn7_DgKFVB6Pz25SDLXU22-p7H5y0fJGKBpFDjrc,3333
|
|
65
65
|
weasyprint/svg/path.py,sha256=Z-T6kbUU3pyHhzVV0JSBgO--XaCGXLsH-cS9iAsITMM,10064
|
|
66
66
|
weasyprint/svg/shapes.py,sha256=NDo0KMnwrm0hj3BOmfrKjRZo4iJF9o-MeUhZ5avANco,3845
|
|
67
|
-
weasyprint/svg/text.py,sha256=
|
|
67
|
+
weasyprint/svg/text.py,sha256=RST3ss4HEGxrq87lX6z67T9K55nL5qBntz0dDqH0bfs,6772
|
|
68
68
|
weasyprint/svg/utils.py,sha256=BEJvyOtxo4tAgLL-RORaEMIBAgmIZzwBNp2YuN1u3NM,7289
|
|
69
69
|
weasyprint/text/constants.py,sha256=gtC92Hbzci0976gVTct3roVKLcQjNWIQM43zuEBqIuY,14189
|
|
70
70
|
weasyprint/text/ffi.py,sha256=13hLmV19RiTspKHna_RlZMar6CpTIHwPDPSGV1FmhNc,18418
|
|
71
71
|
weasyprint/text/fonts.py,sha256=P2Zi7cHwoR4WZsOfm3Ki0lQ3aRYu6YWyFsKvvd0DEqE,17568
|
|
72
|
-
weasyprint/text/line_break.py,sha256=
|
|
73
|
-
weasyprint-68.
|
|
74
|
-
weasyprint-68.
|
|
75
|
-
weasyprint-68.
|
|
76
|
-
weasyprint-68.
|
|
77
|
-
weasyprint-68.
|
|
72
|
+
weasyprint/text/line_break.py,sha256=02vHDXwy_yuWSlG19CxDi-sC3rnh8wj6SBY63sskuTM,28091
|
|
73
|
+
weasyprint-68.1.dist-info/entry_points.txt,sha256=wgDp3XXzFywdYgI5vUWMp1zAwx1sZXXH0FTUQbFOq6A,55
|
|
74
|
+
weasyprint-68.1.dist-info/licenses/LICENSE,sha256=v9FOzPphAFdUYOaFVWsYM5nUvTNZBOPJUhsBFtIcVNo,1534
|
|
75
|
+
weasyprint-68.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
76
|
+
weasyprint-68.1.dist-info/METADATA,sha256=QsG5YIcitase__6kIbSxKZ2KsJYdm-LaIxguuOv9BVE,3709
|
|
77
|
+
weasyprint-68.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|