1
1
mirror of https://github.com/Kozea/WeasyPrint.git synced 2024-10-05 16:37:47 +03:00

Use ruff to replace flake8 and isort

This commit is contained in:
Guillaume Ayoub 2024-03-17 11:34:03 +01:00
parent f59974298d
commit 29597ab893
53 changed files with 191 additions and 186 deletions

View File

@ -44,6 +44,4 @@ jobs:
env:
DYLD_FALLBACK_LIBRARY_PATH: /opt/homebrew/lib
- name: Check coding style
run: python -m flake8
- name: Check imports order
run: python -m isort . --check --diff
run: python -m ruff check

View File

@ -51,17 +51,14 @@ You can launch tests using the following command::
venv/bin/python -m pytest
WeasyPrint also uses isort_ to check imports and flake8_ to check the coding
style::
WeasyPrint also uses ruff_ to check the coding style::
venv/bin/python -m isort . --check --diff
venv/bin/python -m flake8
venv/bin/python -m ruff check
.. _pytest: https://docs.pytest.org/
.. _Ghostscript: https://www.ghostscript.com/
.. _DejaVu fonts: https://dejavu-fonts.github.io/
.. _isort: https://pycqa.github.io/isort/
.. _flake8: https://flake8.pycqa.org/
.. _ruff: https://docs.astral.sh/ruff/
Documentation

View File

@ -52,7 +52,7 @@ Donation = 'https://opencollective.com/courtbouillon'
[project.optional-dependencies]
doc = ['sphinx', 'sphinx_rtd_theme']
test = ['pytest', 'isort', 'flake8']
test = ['pytest', 'ruff']
[project.scripts]
weasyprint = 'weasyprint.__main__:main'
@ -68,6 +68,6 @@ include = ['tests/*', 'weasyprint/*']
exclude_lines = ['pragma: no cover', 'def __repr__', 'raise NotImplementedError']
omit = ['.*']
[tool.isort]
default_section = 'FIRSTPARTY'
multi_line_output = 4
[tool.ruff.lint]
select = ['E', 'W', 'F', 'I', 'N', 'RUF']
ignore = ['RUF001', 'RUF002', 'RUF003']

View File

@ -14,6 +14,7 @@ from tempfile import NamedTemporaryFile
import pytest
from PIL import Image
from weasyprint import HTML
from weasyprint.document import Document

View File

@ -1,12 +1,12 @@
"""Test the CSS parsing, cascade, inherited and computed values."""
import pytest
from weasyprint import CSS, default_url_fetcher
from weasyprint.css import find_stylesheets, get_all_computed_styles
from weasyprint.urls import path2url
from ..testing_utils import (
from ..testing_utils import ( # isort:skip
BASE_URL, FakeHTML, assert_no_logs, capture_logs, resource_path)

View File

@ -2,7 +2,7 @@
import pytest
from ..testing_utils import (
from ..testing_utils import ( # isort:skip
FakeHTML, assert_no_logs, assert_tree, parse_all, render_pages)
RENDER = FakeHTML(string='')._ua_counter_style()[0].render_value

View File

@ -2,6 +2,7 @@
import pytest
import tinycss2
from weasyprint.css import preprocess_stylesheet
from weasyprint.css.validation.descriptors import preprocess_descriptors

View File

@ -1,6 +1,7 @@
"""Test CSS errors and warnings."""
import pytest
from weasyprint import CSS
from ..testing_utils import assert_no_logs, capture_logs, render_pages

View File

@ -3,6 +3,7 @@
import pytest
import tinycss2
from tinycss2.color3 import parse_color
from weasyprint.css import preprocess_declarations
from weasyprint.css.properties import INITIAL_VALUES, ZERO_PIXELS
from weasyprint.css.validation.expanders import EXPANDERS

View File

@ -3,6 +3,7 @@
from math import isclose
import pytest
from weasyprint import CSS
from weasyprint.css import get_all_computed_styles
from weasyprint.css.computed_values import strut_layout

View File

@ -2,13 +2,12 @@
import pytest
import tinycss2
from weasyprint import CSS
from weasyprint.css import (
PageType, get_all_computed_styles, parse_page_selectors)
from weasyprint.css import PageType, get_all_computed_styles, parse_page_selectors
from weasyprint.layout.page import set_page_type_computed_styles
from ..testing_utils import (
FakeHTML, assert_no_logs, render_pages, resource_path)
from ..testing_utils import FakeHTML, assert_no_logs, render_pages, resource_path
@assert_no_logs

View File

@ -4,6 +4,7 @@ from math import pi
import pytest
import tinycss2
from weasyprint.css import preprocess_declarations
from weasyprint.css.validation.properties import PROPERTIES
from weasyprint.images import LinearGradient, RadialGradient
@ -249,19 +250,21 @@ def test_background_image_invalid(rule):
('bottom 3px left 10%', (('left', (10, '%'), 'bottom', (3, 'px')),)),
('right 10% top 3px', (('right', (10, '%'), 'top', (3, 'px')),)),
('top 3px right 10%', (('right', (10, '%'), 'top', (3, 'px')),)),
) + tuple(
(css_x, (('left', val_x, 'top', (50, '%')),))
for css_x, val_x in (
('left', (0, '%')), ('center', (50, '%')), ('right', (100, '%')),
('4.5%', (4.5, '%')), ('12px', (12, 'px')))
) + tuple(
(f'{css_x} {css_y}', (('left', val_x, 'top', val_y),))
for css_x, val_x in (
('left', (0, '%')), ('center', (50, '%')), ('right', (100, '%')),
('4.5%', (4.5, '%')), ('12px', (12, 'px')))
for css_y, val_y in (
('top', (0, '%')), ('center', (50, '%')), ('bottom', (100, '%')),
('7%', (7, '%')), ('1.5px', (1.5, 'px')))
*tuple(
(css_x, (('left', val_x, 'top', (50, '%')),))
for css_x, val_x in (
('left', (0, '%')), ('center', (50, '%')), ('right', (100, '%')),
('4.5%', (4.5, '%')), ('12px', (12, 'px')))
),
*tuple(
(f'{css_x} {css_y}', (('left', val_x, 'top', val_y),))
for css_x, val_x in (
('left', (0, '%')), ('center', (50, '%')), ('right', (100, '%')),
('4.5%', (4.5, '%')), ('12px', (12, 'px')))
for css_y, val_y in (
('top', (0, '%')), ('center', (50, '%')), ('bottom', (100, '%')),
('7%', (7, '%')), ('1.5px', (1.5, 'px')))
),
))
def test_background_position(rule, value):
assert get_value(f'background-position: {rule}') == value

View File

@ -1,6 +1,7 @@
"""Test CSS custom properties, also known as CSS variables."""
import pytest
from weasyprint.css.properties import KNOWN_PROPERTIES
from ..testing_utils import assert_no_logs, capture_logs, render_pages

View File

@ -1,6 +1,7 @@
"""Test how images are drawn in SVG."""
import pytest
from weasyprint.urls import path2url
from ...testing_utils import assert_no_logs, resource_path

View File

@ -4,7 +4,7 @@ from ...testing_utils import assert_no_logs
@assert_no_logs
def test_path_Hh(assert_pixels):
def test_path_h(assert_pixels):
assert_pixels('''
BBBBBBBB__
BBBBBBBB__
@ -35,7 +35,7 @@ def test_path_Hh(assert_pixels):
@assert_no_logs
def test_path_Vv(assert_pixels):
def test_path_v(assert_pixels):
assert_pixels('''
BB____GG__
BB____GG__
@ -66,7 +66,7 @@ def test_path_Vv(assert_pixels):
@assert_no_logs
def test_path_Ll(assert_pixels):
def test_path_l(assert_pixels):
assert_pixels('''
______RR__
______RR__
@ -93,7 +93,7 @@ def test_path_Ll(assert_pixels):
@assert_no_logs
def test_path_Zz(assert_pixels):
def test_path_z(assert_pixels):
assert_pixels('''
BBBBBBB___
BBBBBBB___
@ -120,7 +120,7 @@ def test_path_Zz(assert_pixels):
@assert_no_logs
def test_path_Zz_fill(assert_pixels):
def test_path_z_fill(assert_pixels):
assert_pixels('''
BBBBBBB___
BBBBBBB___
@ -147,7 +147,7 @@ def test_path_Zz_fill(assert_pixels):
@assert_no_logs
def test_path_Cc(assert_pixels):
def test_path_c(assert_pixels):
assert_pixels('''
__________
__________
@ -174,7 +174,7 @@ def test_path_Cc(assert_pixels):
@assert_no_logs
def test_path_Ss(assert_pixels):
def test_path_s(assert_pixels):
assert_pixels('''
__________
__________
@ -201,7 +201,7 @@ def test_path_Ss(assert_pixels):
@assert_no_logs
def test_path_CcSs(assert_pixels):
def test_path_cs(assert_pixels):
assert_pixels('''
__BBBBBB__
__BBBBBBB_
@ -234,7 +234,7 @@ def test_path_CcSs(assert_pixels):
@assert_no_logs
def test_path_Qq(assert_pixels):
def test_path_q(assert_pixels):
assert_pixels('''
__________
__________
@ -261,7 +261,7 @@ def test_path_Qq(assert_pixels):
@assert_no_logs
def test_path_Tt(assert_pixels):
def test_path_t(assert_pixels):
assert_pixels('''
__________
__________
@ -288,7 +288,7 @@ def test_path_Tt(assert_pixels):
@assert_no_logs
def test_path_QqTt(assert_pixels):
def test_path_qt(assert_pixels):
assert_pixels('''
_BBBB_______
BBBBBBB_____
@ -317,7 +317,7 @@ def test_path_QqTt(assert_pixels):
@assert_no_logs
def test_path_QqTt2(assert_pixels):
def test_path_qt2(assert_pixels):
assert_pixels('''
_BBBB_______
BBBBBBB_____
@ -346,7 +346,7 @@ def test_path_QqTt2(assert_pixels):
@assert_no_logs
def test_path_Aa(assert_pixels):
def test_path_a(assert_pixels):
assert_pixels('''
__BBBB______
_BBBBB______
@ -375,7 +375,7 @@ def test_path_Aa(assert_pixels):
@assert_no_logs
def test_path_Aa2(assert_pixels):
def test_path_a2(assert_pixels):
assert_pixels('''
______GGGG__
______GGGGG_
@ -402,7 +402,7 @@ def test_path_Aa2(assert_pixels):
@assert_no_logs
def test_path_Aa3(assert_pixels):
def test_path_a3(assert_pixels):
assert_pixels('''
______GGGG__
______GGGGG_
@ -429,7 +429,7 @@ def test_path_Aa3(assert_pixels):
@assert_no_logs
def test_path_Aa4(assert_pixels):
def test_path_a4(assert_pixels):
assert_pixels('''
____________
____BBB_____
@ -458,7 +458,7 @@ def test_path_Aa4(assert_pixels):
@assert_no_logs
def test_path_Aa5(assert_pixels):
def test_path_a5(assert_pixels):
assert_pixels('''
__BBBBBBBB__
_BBBBBBBBBB_
@ -485,7 +485,7 @@ def test_path_Aa5(assert_pixels):
@assert_no_logs
def test_path_Aa6(assert_pixels):
def test_path_a6(assert_pixels):
assert_pixels('''
__BBBBBBBB__
_BBBBBBBBBB_
@ -512,7 +512,7 @@ def test_path_Aa6(assert_pixels):
@assert_no_logs
def test_path_Aa7(assert_pixels):
def test_path_a7(assert_pixels):
assert_pixels('''
____________
____________

View File

@ -3,6 +3,7 @@
import itertools
import pytest
from weasyprint import HTML
from ..testing_utils import assert_no_logs

View File

@ -2,8 +2,7 @@
import pytest
from ..testing_utils import (
FakeHTML, assert_no_logs, capture_logs, resource_path)
from ..testing_utils import FakeHTML, assert_no_logs, capture_logs, resource_path
centered_image = '''
________

View File

@ -1,6 +1,7 @@
"""Tests for blocks layout."""
import pytest
from weasyprint.formatting_structure import boxes
from ..testing_utils import assert_no_logs, render_pages

View File

@ -1,6 +1,7 @@
"""Tests for floating boxes layout."""
import pytest
from weasyprint.formatting_structure import boxes
from ..testing_utils import assert_no_logs, render_pages

View File

@ -1,6 +1,7 @@
"""Tests for images layout."""
import pytest
from weasyprint.formatting_structure import boxes
from ..testing_utils import assert_no_logs, capture_logs, render_pages

View File

@ -1,6 +1,7 @@
"""Tests for inlines layout."""
import pytest
from weasyprint.formatting_structure import boxes
from ..testing_utils import SANS_FONTS, assert_no_logs, render_pages

View File

@ -1,6 +1,7 @@
"""Tests for pages layout."""
import pytest
from weasyprint.formatting_structure import boxes
from ..testing_utils import assert_no_logs, render_pages

View File

@ -1,11 +1,11 @@
"""Tests for layout of tables."""
import pytest
from weasyprint.formatting_structure import boxes
from weasyprint.layout.table import collapse_table_borders
from ..testing_utils import (
assert_no_logs, capture_logs, parse_all, render_pages)
from ..testing_utils import assert_no_logs, capture_logs, parse_all, render_pages
def _get_grid(html, grid_width, grid_height):
@ -1961,7 +1961,7 @@ def test_table_vertical_align(assert_pixels):
</td>
</tr>
</table>
''') # noqa
''')
@assert_no_logs

View File

@ -3,6 +3,7 @@
import io
from PIL import Image
from weasyprint import CSS, HTML
from .testing_utils import assert_no_logs, capture_logs, resource_path

View File

@ -1,10 +1,13 @@
"""Test the public API."""
import contextlib
import gzip
import io
import os
import sys
import threading
import unicodedata
import wsgiref.simple_server
import zlib
from functools import partial
from pathlib import Path
@ -12,13 +15,13 @@ from urllib.parse import urljoin, uses_relative
import pytest
from PIL import Image
from weasyprint import CSS, HTML, __main__, default_url_fetcher
from weasyprint.pdf.anchors import resolve_links
from weasyprint.urls import path2url
from .draw import parse_pixels
from .testing_utils import (
FakeHTML, assert_no_logs, capture_logs, http_server, resource_path)
from .testing_utils import FakeHTML, assert_no_logs, capture_logs, resource_path
try:
# Available in Python 3.11+
@ -27,7 +30,7 @@ except ImportError:
# Backported from Python 3.11
from contextlib import AbstractContextManager
class chdir(AbstractContextManager):
class chdir(AbstractContextManager): # noqa: N801
def __init__(self, path):
self.path = path
self._old_cwd = []
@ -99,12 +102,12 @@ def _check_doc1(html, has_base_url=True):
def _run(args, stdin=b''):
stdin = io.BytesIO(stdin)
stdout = io.BytesIO()
HTML = partial(FakeHTML, force_uncompressed_pdf=False)
HTML = partial(FakeHTML, force_uncompressed_pdf=False) # noqa: N806
__main__.main(args.split(), stdin=stdin, stdout=stdout, HTML=HTML)
return stdout.getvalue()
class _fake_file:
class FakeFile:
def __init__(self):
self.chunks = []
@ -261,10 +264,10 @@ def test_python_render(assert_pixels_equal, tmp_path):
assert pdf_bytes.startswith(b'%PDF')
check_png_pattern(assert_pixels_equal, png_bytes)
png_file = _fake_file()
png_file = FakeFile()
html.write_png(png_file, stylesheets=[css])
assert png_file.getvalue() == png_bytes
pdf_file = _fake_file()
pdf_file = FakeFile()
html.write_pdf(pdf_file, stylesheets=[css])
assert pdf_file.getvalue().startswith(b'%PDF')
@ -1185,6 +1188,33 @@ def test_http():
gzip_file.close()
return file_obj.getvalue()
@contextlib.contextmanager
def http_server(handlers):
def wsgi_app(environ, start_response):
handler = handlers.get(environ['PATH_INFO'])
if handler:
status = str('200 OK')
response, headers = handler(environ)
headers = [(str(name), str(value)) for name, value in headers]
else: # pragma: no cover
status = str('404 Not Found')
response = b''
headers = []
start_response(status, headers)
return [response]
# Port 0: let the OS pick an available port number
# https://stackoverflow.com/a/1365284/1162888
server = wsgiref.simple_server.make_server('127.0.0.1', 0, wsgi_app)
_host, port = server.socket.getsockname()
thread = threading.Thread(target=server.serve_forever)
thread.start()
try:
yield f'http://127.0.0.1:{port}'
finally:
server.shutdown()
thread.join()
with http_server({
'/gzip': lambda env: (
(gzip_compress(b'<html test=ok>'), [('Content-Encoding', 'gzip')])

View File

@ -1,11 +1,12 @@
"""Test that the "before layout" box tree is correctly constructed."""
import pytest
from weasyprint.css import PageType, get_all_computed_styles
from weasyprint.formatting_structure import boxes, build
from weasyprint.layout.page import set_page_type_computed_styles
from .testing_utils import (
from .testing_utils import ( # isort:skip
FakeHTML, assert_no_logs, assert_tree, capture_logs, parse, parse_all,
render_pages)

View File

@ -6,13 +6,13 @@ import re
from codecs import BOM_UTF16_BE
import pytest
from weasyprint import Attachment
from weasyprint.document import Document, DocumentMetadata
from weasyprint.text.fonts import FontConfiguration
from weasyprint.urls import path2url
from .testing_utils import (
FakeHTML, assert_no_logs, capture_logs, resource_path)
from .testing_utils import FakeHTML, assert_no_logs, capture_logs, resource_path
# Top and right positions in points, rounded to the default float precision of
# 6 digits, a rendered by pydyf

View File

@ -1,6 +1,7 @@
"""Test CSS stacking contexts."""
import pytest
from weasyprint.stacking import StackingContext
from .testing_utils import assert_no_logs, render_pages, serialize

View File

@ -1,6 +1,7 @@
"""Test the text layout."""
import pytest
from weasyprint.css.properties import INITIAL_VALUES
from weasyprint.formatting_structure.build import capitalize
from weasyprint.text.line_break import split_first_line
@ -946,8 +947,8 @@ def test_overflow_wrap(wrap, text, test, full_text):
lines = []
for line in body.children:
box, = line.children
textBox, = box.children
lines.append(textBox.text)
text_box, = box.children
lines.append(text_box.text)
lines_full_text = ''.join(line for line in lines)
assert test(len(lines))
assert full_text == lines_full_text

View File

@ -4,8 +4,6 @@ import contextlib
import functools
import logging
import sys
import threading
import wsgiref.simple_server
from pathlib import Path
from weasyprint import CSS, DEFAULT_OPTIONS, HTML, images
@ -123,34 +121,6 @@ def assert_no_logs(function):
return wrapper
@contextlib.contextmanager
def http_server(handlers):
def wsgi_app(environ, start_response):
handler = handlers.get(environ['PATH_INFO'])
if handler:
status = str('200 OK')
response, headers = handler(environ)
headers = [(str(name), str(value)) for name, value in headers]
else: # pragma: no cover
status = str('404 Not Found')
response = b''
headers = []
start_response(status, headers)
return [response]
# Port 0: let the OS pick an available port number
# https://stackoverflow.com/a/1365284/1162888
server = wsgiref.simple_server.make_server('127.0.0.1', 0, wsgi_app)
_host, port = server.socket.getsockname()
thread = threading.Thread(target=server.serve_forever)
thread.start()
try:
yield f'http://127.0.0.1:{port}'
finally:
server.shutdown()
thread.join()
def serialize(box_list):
"""Transform a box list into a structure easier to compare for testing."""
return [(
@ -182,7 +152,7 @@ def tree_position(box_list, matcher):
elif hasattr(box, 'children'):
position = tree_position(box.children, matcher)
if position:
return [i] + position
return [i, *position]
def _parse_base(html_content, base_url=BASE_URL):

View File

@ -85,9 +85,9 @@ __all__ = [
# Import after setting the version, as the version is used in other modules
from .urls import ( # noqa isort:skip
from .urls import ( # noqa: I001, E402
fetch, default_url_fetcher, path2url, ensure_url, url_is_absolute)
from .logger import LOGGER, PROGRESS_LOGGER # noqa isort:skip
from .logger import LOGGER, PROGRESS_LOGGER # noqa: E402
# Some imports are at the end of the file (after the CSS class)
# to work around circular imports.
@ -416,8 +416,8 @@ def _select_source(guess=None, filename=None, url=None, file_obj=None,
yield 'string', string, base_url, None
# Work around circular imports.
from .css import preprocess_stylesheet # noqa isort:skip
from .html import ( # noqa isort:skip
from .css import preprocess_stylesheet # noqa: I001, E402
from .html import ( # noqa: E402
HTML5_UA_COUNTER_STYLE, HTML5_UA_STYLESHEET, HTML5_UA_FORM_STYLESHEET,
HTML5_PH_STYLESHEET)
from .document import Document, Page # noqa isort:skip
from .document import Document, Page # noqa: E402

View File

@ -137,7 +137,7 @@ PARSER.add_argument(
PARSER.set_defaults(**DEFAULT_OPTIONS)
def main(argv=None, stdout=None, stdin=None, HTML=HTML):
def main(argv=None, stdout=None, stdin=None, HTML=HTML): # noqa: N803
"""The ``weasyprint`` program takes at least two arguments:
.. code-block:: sh

View File

@ -26,14 +26,14 @@ from ..logger import LOGGER, PROGRESS_LOGGER
from ..urls import URLFetchingError, get_url_attribute, url_join
from . import counters, media_queries
from .computed_values import COMPUTER_FUNCTIONS
from .properties import (
INHERITED, INITIAL_NOT_COMPUTED, INITIAL_VALUES, ZERO_PIXELS)
from .utils import (
InvalidValues, Pending, check_var_function, get_url, parse_function,
remove_whitespace)
from .properties import INHERITED, INITIAL_NOT_COMPUTED, INITIAL_VALUES, ZERO_PIXELS
from .validation import preprocess_declarations
from .validation.descriptors import preprocess_descriptors
from .utils import ( # isort:skip
InvalidValues, Pending, check_var_function, get_url, parse_function,
remove_whitespace)
# Reject anything not in here:
PSEUDO_ELEMENTS = (
None, 'before', 'after', 'marker', 'first-line', 'first-letter',

View File

@ -10,8 +10,7 @@ from ..text.ffi import ffi, pango, units_to_double
from ..text.line_break import Layout, first_line_metrics
from ..urls import get_link_attribute
from .properties import INITIAL_VALUES, ZERO_PIXELS, Dimension
from .utils import (
ANGLE_TO_RADIANS, LENGTH_UNITS, LENGTHS_TO_PIXELS, safe_urljoin)
from .utils import ANGLE_TO_RADIANS, LENGTH_UNITS, LENGTHS_TO_PIXELS, safe_urljoin
# Value in pixels of font-size for <absolute-size> keywords: 12pt (16px) for
# medium, and scaling factors given in CSS3 for others:

View File

@ -87,7 +87,7 @@ for unit in ANGLE_TO_RADIANS:
ATTR_FALLBACKS[unit] = ('angle', Dimension('0', unit))
class InvalidValues(ValueError):
class InvalidValues(ValueError): # noqa: N818
"""Invalid or unsupported values for a known CSS property."""

View File

@ -1,10 +1,8 @@
"""Validate properties, expanders and descriptors."""
from cssselect2 import SelectorError, compile_selector_list
from tinycss2 import parse_blocks_contents, serialize
from tinycss2.ast import (
FunctionBlock, IdentToken, LiteralToken, WhitespaceToken)
from tinycss2.ast import FunctionBlock, IdentToken, LiteralToken, WhitespaceToken
from ... import LOGGER
from ..utils import InvalidValues, remove_whitespace

View File

@ -5,11 +5,12 @@ from math import inf
import tinycss2
from ...logger import LOGGER
from ..utils import (
from . import properties
from ..utils import ( # isort:skip
InvalidValues, comma_separated_list, get_custom_ident, get_keyword,
get_single_keyword, get_url, remove_whitespace, single_keyword,
single_token, split_on_comma)
from . import properties
DESCRIPTORS = {
'font-face': {},

View File

@ -6,11 +6,12 @@ from tinycss2.ast import DimensionToken, IdentToken, NumberToken
from tinycss2.color3 import parse_color
from ..properties import INITIAL_VALUES
from ..utils import (
InvalidValues, Pending, check_var_function, get_keyword,
get_single_keyword, split_on_comma)
from .descriptors import expand_font_variant
from .properties import (
from ..utils import ( # isort:skip
InvalidValues, Pending, check_var_function, get_keyword, get_single_keyword,
split_on_comma)
from .properties import ( # isort:skip
background_attachment, background_image, background_position,
background_repeat, background_size, block_ellipsis, border_style,
border_width, box, column_count, column_width, flex_basis, flex_direction,

View File

@ -10,7 +10,8 @@ from tinycss2.color3 import parse_color
from .. import computed_values
from ..properties import KNOWN_PROPERTIES, ZERO_PIXELS, Dimension
from ..utils import (
from ..utils import ( # isort:skip
InvalidValues, Pending, check_var_function, comma_separated_list,
get_angle, get_content_list, get_content_list_token, get_custom_ident,
get_image, get_keyword, get_length, get_resolution, get_single_keyword,
@ -712,8 +713,8 @@ def font_variant_ligatures(tokens):
if token.type != 'ident':
return None
if token.value in all_values:
concurrent_values = [
couple for couple in couples if token.value in couple][0]
concurrent_values = next(
couple for couple in couples if token.value in couple)
if any(value in values for value in concurrent_values):
return None
else:
@ -757,8 +758,8 @@ def font_variant_numeric(tokens):
if token.type != 'ident':
return None
if token.value in all_values:
concurrent_values = [
couple for couple in couples if token.value in couple][0]
concurrent_values = next(
couple for couple in couples if token.value in couple)
if any(value in values for value in concurrent_values):
return None
else:
@ -827,8 +828,8 @@ def font_variant_east_asian(tokens):
if token.type != 'ident':
return None
if token.value in all_values:
concurrent_values = [
couple for couple in couples if token.value in couple][0]
concurrent_values = next(
couple for couple in couples if token.value in couple)
if any(value in values for value in concurrent_values):
return None
else:

View File

@ -41,7 +41,7 @@ def darken(color):
hue, saturation, value = rgb_to_hsv(color.red, color.green, color.blue)
value /= 1.5
saturation /= 1.25
return hsv_to_rgb(hue, saturation, value) + (color.alpha,)
return (*hsv_to_rgb(hue, saturation, value), color.alpha)
def lighten(color):
@ -50,7 +50,7 @@ def lighten(color):
value = 1 - (1 - value) / 1.5
if saturation:
saturation = 1 - (1 - saturation) / 1.25
return hsv_to_rgb(hue, saturation, value) + (color.alpha,)
return (*hsv_to_rgb(hue, saturation, value), color.alpha)
def draw_page(page, stream):
@ -150,7 +150,7 @@ def draw_stacking_context(stream, stacking_context):
draw_inline_level(stream, stacking_context.page, box)
# Point 7
for block in [box] + stacking_context.blocks_and_cells:
for block in (box, *stacking_context.blocks_and_cells):
if isinstance(block, boxes.ReplacedBox):
draw_replacedbox(stream, block)
elif block.children:

View File

@ -619,9 +619,9 @@ class LinearGradient(Gradient):
for i in range(len(positions) - 1)]
# Create cycles used to add colors
next_steps = cycle([0] + position_steps)
next_steps = cycle((0, *position_steps))
next_colors = cycle(colors)
previous_steps = cycle([0] + position_steps[::-1])
previous_steps = cycle((0, *position_steps[::-1]))
previous_colors = cycle(colors[::-1])
# Add colors after last step
@ -820,8 +820,7 @@ class RadialGradient(Gradient):
new_positions = [
position - 1 - full_repeat for position
in original_positions[-(i - 1):]]
positions = (
[ratio - 1 - full_repeat] + new_positions + positions)
positions = (ratio - 1 - full_repeat, *new_positions, *positions)
return points, positions, colors
def _resolve_size(self, width, height, center_x, center_y):

View File

@ -48,8 +48,7 @@ def block_level_layout(context, box, bottom_space, skip_stack,
if not context.forced_break:
box.margin_top = 0
collapsed_margin = collapse_margin(
adjoining_margins + [box.margin_top])
collapsed_margin = collapse_margin([*adjoining_margins, box.margin_top])
box.clearance = get_clearance(context, box, collapsed_margin)
if box.clearance is not None:
top_border_edge = box.position_y + collapsed_margin + box.clearance
@ -84,7 +83,7 @@ def block_level_layout_switch(context, box, bottom_space, skip_stack,
page_is_empty, absolute_boxes, fixed_boxes)
else: # pragma: no cover
raise TypeError(f'Layout for {type(box).__name__} not handled yet')
return result + (None,)
return (*result, None)
def block_box_layout(context, box, bottom_space, skip_stack,
@ -111,7 +110,7 @@ def block_box_layout(context, box, bottom_space, skip_stack,
context, box, bottom_space, skip_stack,
containing_block, page_is_empty, absolute_boxes,
fixed_boxes, adjoining_margins)
return result + (None,)
return (*result, None)
elif box.is_table_wrapper:
table_wrapper_width(
context, box, (containing_block.width, containing_block.height))
@ -469,7 +468,7 @@ def _in_flow_layout(context, box, index, child, new_children, page_is_empty,
if not context.forced_break:
child_margin_top = 0
new_collapsed_margin = collapse_margin(
adjoining_margins + [child_margin_top])
[*adjoining_margins, child_margin_top])
collapsed_margin_difference = (
new_collapsed_margin - old_collapsed_margin)
for previous_new_child in new_children:
@ -1013,7 +1012,7 @@ def find_earlier_page_break(context, children, absolute_boxes, fixed_boxes):
if result:
new_grand_children, resume_at = result
new_child = child.copy_with_children(new_grand_children)
new_children = list(children[:index]) + [new_child]
new_children = [*children[:index], new_child]
# Re-add footer at the end of split table
# TODO: fix table height and footer position

View File

@ -10,7 +10,7 @@ def columns_layout(context, box, bottom_space, skip_stack, containing_block,
page_is_empty, absolute_boxes, fixed_boxes,
adjoining_margins):
"""Lay out a multi-column ``box``."""
from .block import (
from .block import ( # isort:skip
block_box_layout, block_level_layout, block_level_width,
collapse_margin, remove_placeholders)

View File

@ -13,8 +13,7 @@ from .float import avoid_collisions, float_layout
from .leader import handle_leader
from .min_max import handle_min_max_width
from .percent import resolve_one_percentage, resolve_percentages
from .preferred import (
inline_min_content_width, shrink_to_fit, trailing_whitespace_size)
from .preferred import inline_min_content_width, shrink_to_fit, trailing_whitespace_size
from .replaced import inline_replaced_box_layout
from .table import find_in_flow_baseline, table_wrapper_width
@ -294,8 +293,7 @@ def first_letter_to_box(box, skip_stack, first_letter_style):
letter_box = boxes.InlineBox(
f'{box.element_tag}::first-letter', letter_style,
box.element, [child])
box.children = (
(letter_box,) + tuple(box.children[1:]))
box.children = ((letter_box, *box.children[1:]))
elif child.text:
character_found = False
if skip_stack:
@ -325,7 +323,7 @@ def first_letter_to_box(box, skip_stack, first_letter_style):
f'{box.element_tag}::first-letter', letter_style,
box.element, first_letter)
letter_box.children = (text_box,)
box.children = (letter_box,) + tuple(box.children)
box.children = (letter_box, *box.children)
else:
letter_box = boxes.BlockBox(
f'{box.element_tag}::first-letter',
@ -339,7 +337,7 @@ def first_letter_to_box(box, skip_stack, first_letter_style):
f'{box.element_tag}::first-letter', letter_style,
box.element, first_letter)
line_box.children = (text_box,)
box.children = (letter_box,) + tuple(box.children)
box.children = (letter_box, *box.children)
build.process_text_transform(text_box)
if skip_stack and child_skip_stack:
index, = skip_stack
@ -847,7 +845,7 @@ def split_inline_box(context, box, position_x, max_x, bottom_space, skip_stack,
skip_stack=None)
if resume_at is not None:
index = tuple(resume_at)[0]
index = next(iter(resume_at))
if index < float_resume_index:
resume_at = {float_resume_index: None}

View File

@ -431,8 +431,8 @@ def table_and_columns_preferred_widths(context, box, outer=True):
box, outer=True, width=block_max_content_width(context, table))
result = ([], [], [], [], total_horizontal_border_spacing, [])
context.tables[table] = result = {
False: (min_width, max_width) + result,
True: (outer_min_width, outer_max_width) + result,
False: (min_width, max_width, *result),
True: (outer_min_width, outer_max_width, *result),
}
return result[outer]
@ -616,9 +616,9 @@ def table_and_columns_preferred_widths(context, box, outer=True):
table_min_content_width = (
total_horizontal_border_spacing + sum(min_content_widths))
table_max_content_width = (
total_horizontal_border_spacing + max(
[sum(max_content_widths), large_percentage_contribution] +
small_percentage_contributions))
total_horizontal_border_spacing + max([
sum(max_content_widths), large_percentage_contribution,
*small_percentage_contributions]))
if table.style['width'] != 'auto' and table.style['width'].unit == 'px':
# "percentages on the following properties are treated instead as
@ -644,10 +644,8 @@ def table_and_columns_preferred_widths(context, box, outer=True):
min_content_widths, max_content_widths, intrinsic_percentages,
constrainedness, total_horizontal_border_spacing, zipped_grid)
context.tables[table] = result = {
False: (table_min_content_width, table_max_content_width) + result,
True: (
(table_outer_min_content_width, table_outer_max_content_width) +
result),
False: (table_min_content_width, table_max_content_width, *result),
True: (table_outer_min_content_width, table_outer_max_content_width, *result),
}
return result[outer]

View File

@ -13,7 +13,7 @@ from .preferred import max_content_width, table_and_columns_preferred_widths
def table_layout(context, table, bottom_space, skip_stack, containing_block,
page_is_empty, absolute_boxes, fixed_boxes):
"""Layout for a table box."""
from .block import (
from .block import ( # isort:skip
avoid_page_break, block_container_layout, block_level_page_break,
find_earlier_page_break, force_page_break)

View File

@ -7,12 +7,13 @@ from ..html import W3C_DATE_RE
from ..logger import LOGGER, PROGRESS_LOGGER
from ..matrix import Matrix
from . import pdfa, pdfua
from .anchors import (
add_annotations, add_inputs, add_links, add_outlines, resolve_links,
write_pdf_attachment)
from .fonts import build_fonts_dictionary
from .stream import Stream
from .anchors import ( # isort:skip
add_annotations, add_inputs, add_links, add_outlines, resolve_links,
write_pdf_attachment)
VARIANTS = {
name: data for variants in (pdfa.VARIANTS, pdfua.VARIANTS)
for (name, data) in variants.items()}

View File

@ -1,7 +1,6 @@
"""PDF metadata stream generation."""
from xml.etree.ElementTree import (
Element, SubElement, register_namespace, tostring)
from xml.etree.ElementTree import Element, SubElement, register_namespace, tostring
import pydyf

View File

@ -8,17 +8,16 @@ from xml.etree import ElementTree
from cssselect2 import ElementWrapper
from ..urls import get_url_attribute
from .bounding_box import (
EMPTY_BOUNDING_BOX, bounding_box, extend_bounding_box,
is_valid_bounding_box)
from .css import parse_declarations, parse_stylesheets
from .defs import (
apply_filters, clip_path, draw_gradient_or_pattern, paint_mask, use)
from .defs import apply_filters, clip_path, draw_gradient_or_pattern, paint_mask, use
from .images import image, svg
from .path import path
from .shapes import circle, ellipse, line, polygon, polyline, rect
from .text import text
from .utils import (
from .bounding_box import ( # isort:skip
EMPTY_BOUNDING_BOX, bounding_box, extend_bounding_box, is_valid_bounding_box)
from .utils import ( # isort:skip
PointError, alpha_value, color, normalize, parse_url, preserve_ratio, size,
transform)

View File

@ -249,17 +249,15 @@ def spread_linear_gradient(spread, positions, colors, x1, y1, x2, y2,
# Create cycles used to add colors
if spread == 'repeat':
next_steps = cycle([0] + position_steps)
next_steps = cycle((0, *position_steps))
next_colors = cycle(colors)
previous_steps = cycle([0] + position_steps[::-1])
previous_steps = cycle((0, *position_steps[::-1]))
previous_colors = cycle(colors[::-1])
else:
assert spread == 'reflect'
next_steps = cycle(
[0] + position_steps[::-1] + [0] + position_steps)
next_steps = cycle((0, *position_steps[::-1], 0, *position_steps))
next_colors = cycle(colors[::-1] + colors)
previous_steps = cycle(
[0] + position_steps + [0] + position_steps[::-1])
previous_steps = cycle((0, *position_steps, 0, *position_steps[::-1]))
previous_colors = cycle(colors + colors[::-1])
# Normalize bounding box
@ -402,8 +400,7 @@ def spread_radial_gradient(spread, positions, colors, fx, fy, fr, cx, cy, r,
new_positions = [
position - 1 - full_repeat for position
in original_positions[-(i - 1):]]
positions = (
[ratio - 1 - full_repeat] + new_positions + positions)
positions = [ratio - 1 - full_repeat, *new_positions, *positions]
break
coords = (fx, fy, fr, cx, cy, r)

View File

@ -69,8 +69,8 @@ def rect(svg, node, font_size):
# Inspired by Cairo Cookbook
# https://cairographics.org/cookbook/roundedrectangles/
ARC_TO_BEZIER = 4 * (2 ** .5 - 1) / 3
c1, c2 = ARC_TO_BEZIER * rx, ARC_TO_BEZIER * ry
arc_to_bezier = 4 * (2 ** .5 - 1) / 3
c1, c2 = arc_to_bezier * rx, arc_to_bezier * ry
svg.stream.move_to(x + rx, y)
svg.stream.line_to(x + width - rx, y)

View File

@ -11,10 +11,11 @@ from fontTools.ttLib import TTFont, woff2
from ..logger import LOGGER
from ..urls import FILESYSTEM_ENCODING, fetch
from .constants import (
from .constants import ( # isort:skip
CAPS_KEYS, EAST_ASIAN_KEYS, FONTCONFIG_STRETCH, FONTCONFIG_STYLE,
FONTCONFIG_WEIGHT, LIGATURE_KEYS, NUMERIC_KEYS, PANGO_STRETCH, PANGO_STYLE)
from .ffi import (
from .ffi import ( # isort:skip
ffi, fontconfig, gobject, pango, pangoft2, unicode_to_char_p,
units_from_double)

View File

@ -6,10 +6,11 @@ from math import inf
import pyphen
from .constants import LST_TO_ISO, PANGO_WRAP_MODE
from .ffi import (
from .fonts import font_features, get_font_description
from .ffi import ( # isort:skip
ffi, gobject, pango, pangoft2, unicode_to_char_p, units_from_double,
units_to_double)
from .fonts import font_features, get_font_description
def line_size(line, style):