diff --git a/borb/license/version.py b/borb/license/version.py index 3235c59a5..6f35f191d 100644 --- a/borb/license/version.py +++ b/borb/license/version.py @@ -46,4 +46,4 @@ def get_version() -> str: This function returns the current borb version :return: the current borb version """ - return "2.1.23" + return "2.1.24" diff --git a/borb/pdf/__init__.py b/borb/pdf/__init__.py index 9920ce5c7..f3d41d409 100644 --- a/borb/pdf/__init__.py +++ b/borb/pdf/__init__.py @@ -52,6 +52,9 @@ from .canvas.color.color import X11Color from .canvas.color.farrow_and_ball import FarrowAndBall from .canvas.color.pantone import Pantone +from .canvas.font.google_true_type_font import GoogleTrueTypeFont +from .canvas.font.simple_font.font_type_1 import StandardType1Font +from .canvas.font.simple_font.true_type_font import TrueTypeFont from .canvas.layout.annotation.annotation import Annotation from .canvas.layout.annotation.caret_annotation import CaretAnnotation from .canvas.layout.annotation.circle_annotation import CircleAnnotation diff --git a/borb/pdf/canvas/font/google_true_type_font.py b/borb/pdf/canvas/font/google_true_type_font.py new file mode 100644 index 000000000..9599b913d --- /dev/null +++ b/borb/pdf/canvas/font/google_true_type_font.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +The TrueType font format was developed by Apple Computer, Inc., and has been adopted as a standard font +format for the Microsoft Windows operating system. Specifications for the TrueType font file format are +available in Apple’s TrueType Reference Manual and Microsoft’s TrueType 1.0 Font Files Technical +Specification (see Bibliography). +""" +import json +import os +import tempfile +import typing +import pathlib + +import requests + +from borb.pdf.canvas.font.simple_font.true_type_font import TrueTypeFont + + +class GoogleTrueTypeFont(TrueTypeFont): + """ + A TrueType font dictionary may contain the same entries as a Type 1 font dictionary (see Table 111), with these + differences: + • The value of Subtype shall be TrueType. + • The value of Encoding is subject to limitations that are described in 9.6.6, "Character Encoding". + • The value of BaseFont is derived differently. The PostScript name for the value of BaseFont may be determined in one of two ways: + • If the TrueType font program's “name” table contains a PostScript name, it shall be used. + • In the absence of such an entry in the “name” table, a PostScript name shall be derived from the name by + which the font is known in the host operating system. On a Windows system, the name shall be based on + the lfFaceName field in a LOGFONT structure; in the Mac OS, it shall be based on the name of the FOND + resource. If the name contains any SPACEs, the SPACEs shall be removed. + """ + + # + # CONSTRUCTOR + # + + # + # PRIVATE + # + + @staticmethod + def _download_google_font(font_name: str) -> pathlib.Path: + + # get GOOGLE_FONTS_API_KEY + google_fonts_api_key: typing.Optional[str] = os.environ.get( + "GOOGLE_FONTS_API_KEY" + ) + assert ( + google_fonts_api_key is not None + ), "GOOGLE_FONTS_API_KEY not found in os.environ" + + # download overview + try: + + # list all items + items: typing.List[typing.Dict] = json.loads( + requests.get( + f"https://www.googleapis.com/webfonts/v1/webfonts?key={google_fonts_api_key}" + ).content + ).get("items", []) + + # find matching font_info_dictionary + font_info_dictionary: typing.Dict[str, typing.Any] = next( + iter([x for x in items if x.get("family", None) == font_name]), None + ) + assert font_info_dictionary is not None, f"Unable to find font {font_name}" + + # get URL + true_type_font_file_url: typing.Optional[str] = font_info_dictionary.get( + "files", {} + ).get("regular", None) + assert ( + true_type_font_file_url is not None + ), f"Unable to find URL for font {font_name}" + + # download to temporary file + temp_font_file: pathlib.Path = pathlib.Path(tempfile.NamedTemporaryFile(suffix=".ttf").name) + with open(temp_font_file, "wb") as fh: + fh.write(requests.get(true_type_font_file_url).content) + + # return + return temp_font_file + except: + assert False, f"Unable to process font {font_name}" + + # + # PUBLIC + # + + @staticmethod + def true_type_font_from_google( + font_name: str, + ) -> typing.Union["TrueTypeFont", "Type0Font"]: + """ + This function returns the PDF TrueTypeFont object for a given font name. + It does so by looking up the font using the Google Fonts API, + downloading the font to a temporary file, + and subsequently loading that temporary file using TrueTypeFont.true_type_font_from_file + :param font_name: the font name + :return: a TrueTypeFont or Type0Font + """ + return TrueTypeFont.true_type_font_from_file( + GoogleTrueTypeFont._download_google_font(font_name) + ) diff --git a/borb/pdf/canvas/layout/image/unsplash.py b/borb/pdf/canvas/layout/image/unsplash.py index 064c6dd5e..f98ad813a 100644 --- a/borb/pdf/canvas/layout/image/unsplash.py +++ b/borb/pdf/canvas/layout/image/unsplash.py @@ -7,6 +7,7 @@ """ import json +import os import typing import urllib.request from decimal import Decimal @@ -52,14 +53,11 @@ def get_image( # build keyword str keyword_str: str = "".join([(k + "+") for k in keywords])[:-1] - # get access_key - import keyring # type: ignore[import] - - keyring.get_keyring() - unsplash_access_key: typing.Optional[str] = keyring.get_password( - "unsplash", "access_key" - ) - assert unsplash_access_key is not None + # get UNSPLASH_API_KEY + unsplash_access_key: typing.Optional[str] = os.environ.get("UNSPLASH_API_KEY") + assert ( + unsplash_access_key is not None + ), "UNSPLASH_API_KEY not found in os.environ" # fetch json min_delta: typing.Optional[Decimal] = None diff --git a/release_notes.md b/release_notes.md index d1cf10d82..18dd0333c 100644 --- a/release_notes.md +++ b/release_notes.md @@ -1,13 +1,18 @@ # :mega: borb release notes -This release features `A4PortraitResumeTemplate` which offers a convenient way of making a resume. +This release features `GoogleTrueTypeFont` which enables users to access the Google Font API, +to directly use a `TrueTypeFont` in `borb` by specifying its name. + +Tests have been added for this feature: + +- `test_add_paragraphs_using_jacquard_12` +- `test_add_paragraphs_using_pacifico` +- `test_add_paragraphs_using_shadows_into_light` Some tests have been added to guard code quality: -- `TestCodeFilesAreSmall` -- `TestCodeFilesContainVisibilityCommentBlocks` -- `TestCodeFilesStartWithPythonBash` -- `TestCodeFilesUseFullyQualifiedBorbImports` -- `TestCodeFilesUseKnownExternalImports` -- `TestCodeFilesUseSingleLineImports` \ No newline at end of file +- `TestCodeFilesContainSortedMethods` +- `TestCodeFilesContainVisibilityComments` +- `TestCodeFilesDoNotContainNumbersInMethods` +- `TestCodeFilesNeverUseKeyring` \ No newline at end of file diff --git a/tests/borb_secrets.py b/tests/borb_secrets.py deleted file mode 100755 index 05535d175..000000000 --- a/tests/borb_secrets.py +++ /dev/null @@ -1,11 +0,0 @@ -import keyring - - -def populate_keyring() -> None: - """ - This method populates the keyring with the credentials for unsplash - :return: None - """ - keyring.set_password( - "unsplash", "access_key", "FgpGELvBVuBuz3caU8wLz-_gkKa08hwDMb9QGR5AiMg" - ) diff --git a/tests/license/artifacts_test_register_license/license.json b/tests/license/artifacts_test_register_license/license.json index ecde162bf..cb5b823a4 100644 --- a/tests/license/artifacts_test_register_license/license.json +++ b/tests/license/artifacts_test_register_license/license.json @@ -1,7 +1,7 @@ { "anonymous_user_id": "Joris Schellekens", "company": "borb (EZ)", - "valid_from_as_str": "2024-05-04 00:35:59", - "valid_until_as_str": "2024-05-11 00:35:59", - "license_key": "P5yPQlUVr8ub0/TdH5vS+FGl3FGM3ZtBXQkWT6vQm4lQIE+jQjGf/ZMd8nACHAtfAL7JLC5PoPMAgvBPuj8RhxW7E8k3aG2bQVqG8pvQajl/o+hXpAv8Nlh4h/Ug3YNDnfxQBxACNdQnhYOv1GOpsVbYkWvjppifTs9KiE+BOc4TxtlxVYFaBtb90HdOxpx00nbRORlkz9ID0/ZYMhXMaNo8BkXHC60orbnS05V03PbfjQswW/G+MJ7hBmhxouW4cxWdhrE1/ReIoqrDIkZvu6Wl7lrLIzyYbbSkpTykoCyQkHXCgnTstUwfeE1Ou4sZmbdSpeZEtu6UzBAWe52NVg==" + "valid_from_as_str": "2024-06-16 19:24:45", + "valid_until_as_str": "2024-06-23 19:24:45", + "license_key": "d3V8jPaCN7OPrLqmyTjnRWBQEs5fe1/NodIFf11Qq/LKVQHS58+5pkJ7wI2RlkIG27o6SlznCSuH9le5+O2Wn79UVGFxbWk0IrqIN8c5vWZlF8Jydd55UQcc5EXxyMzNxvVBSja7vcplUr6CB3yMjLTbJN9iM8QLTb0p7SBXjRqurT9+33VQLgGZeQBcsyEZnUTZW2CF5LqbB+fIGAyIG4CeCtp0mmsTx5LDwyGJnje/zFvk9qoMsLEyDJdPEWNTmWtSoz39nq4MpYuD/LEjB9NIXEgnxQgA9S5OGV+wvZxWlJlpMDZdXV57WjsN0ynVIFwVAsCvXIR+70eETxasEA==" } \ No newline at end of file diff --git a/tests/pdf/canvas/font/artifacts_test_add_paragraphs_using_google_fonts/output_001_ground_truth.png b/tests/pdf/canvas/font/artifacts_test_add_paragraphs_using_google_fonts/output_001_ground_truth.png new file mode 100644 index 000000000..481e5e662 Binary files /dev/null and b/tests/pdf/canvas/font/artifacts_test_add_paragraphs_using_google_fonts/output_001_ground_truth.png differ diff --git a/tests/pdf/canvas/font/artifacts_test_add_paragraphs_using_google_fonts/output_002_ground_truth.png b/tests/pdf/canvas/font/artifacts_test_add_paragraphs_using_google_fonts/output_002_ground_truth.png new file mode 100644 index 000000000..b77106999 Binary files /dev/null and b/tests/pdf/canvas/font/artifacts_test_add_paragraphs_using_google_fonts/output_002_ground_truth.png differ diff --git a/tests/pdf/canvas/font/artifacts_test_add_paragraphs_using_google_fonts/output_003_ground_truth.png b/tests/pdf/canvas/font/artifacts_test_add_paragraphs_using_google_fonts/output_003_ground_truth.png new file mode 100644 index 000000000..e4f277d9a Binary files /dev/null and b/tests/pdf/canvas/font/artifacts_test_add_paragraphs_using_google_fonts/output_003_ground_truth.png differ diff --git a/tests/pdf/canvas/font/test_add_paragraphs_using_google_fonts.py b/tests/pdf/canvas/font/test_add_paragraphs_using_google_fonts.py new file mode 100644 index 000000000..00b65ba71 --- /dev/null +++ b/tests/pdf/canvas/font/test_add_paragraphs_using_google_fonts.py @@ -0,0 +1,139 @@ +from decimal import Decimal + +from borb.pdf import Document +from borb.pdf import FixedColumnWidthTable +from borb.pdf import GoogleTrueTypeFont +from borb.pdf import PDF +from borb.pdf import Page +from borb.pdf import PageLayout +from borb.pdf import Paragraph +from borb.pdf import SingleColumnLayout +from borb.pdf import Table +from borb.pdf import TrueTypeFont +from tests.test_case import TestCase + + +class TestAddParagraphsUsingGoogleFonts(TestCase): + """ + This test loads a truetype _font from a .ttf file and attempts to use it to write 2 paragraphs of lorem ipsum. + """ + + def _write_document_with_font( + self, + font_name: str, + ) -> Document: + + # create document + pdf = Document() + + # add page + page = Page() + pdf.add_page(page) + + # layout + layout: PageLayout = SingleColumnLayout(page) + + # add test information + layout.add( + self.get_test_header( + f"This test loads {font_name} from a file and attempts to write letters and numbers with it." + ) + ) + + # load font + ttf: TrueTypeFont = GoogleTrueTypeFont.true_type_font_from_google(font_name) + + # add paragraph 1 + uppercase_letter_table: Table = FixedColumnWidthTable( + number_of_columns=5, number_of_rows=6 + ) + for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ": + try: + uppercase_letter_table.add(Paragraph(c, font=ttf)) + except: + uppercase_letter_table.add(Paragraph("")) + uppercase_letter_table.set_padding_on_all_cells( + Decimal(2), Decimal(2), Decimal(2), Decimal(2) + ) + layout.add(Paragraph("Uppercase:")) + layout.add(uppercase_letter_table) + + # lowercase + lowercase_letter_table: Table = FixedColumnWidthTable( + number_of_columns=5, number_of_rows=6 + ) + for c in "abcdefghijklmnopqrstuvwxyz": + try: + lowercase_letter_table.add(Paragraph(c, font=ttf)) + except: + lowercase_letter_table.add(Paragraph("")) + lowercase_letter_table.set_padding_on_all_cells( + Decimal(2), Decimal(2), Decimal(2), Decimal(2) + ) + layout.add(Paragraph("Lowercase:")) + layout.add(lowercase_letter_table) + + # lowercase + digit_table: Table = FixedColumnWidthTable( + number_of_columns=5, number_of_rows=2 + ) + for c in "0123456789": + try: + digit_table.add(Paragraph(c, font=ttf)) + except: + digit_table.add(Paragraph("")) + digit_table.set_padding_on_all_cells( + Decimal(2), Decimal(2), Decimal(2), Decimal(2) + ) + layout.add(Paragraph("Digits:")) + layout.add(digit_table) + + # return + return pdf + + def test_add_paragraphs_using_jacquard_12(self): + + # set GOOGLE_FONTS_API_KEY + try: + from tests.borb_secrets import populate_os_environ + + populate_os_environ() + except: + pass + + with open(self.get_first_output_file(), "wb") as in_file_handle: + PDF.dumps(in_file_handle, self._write_document_with_font("Jacquard 12")) + self.compare_visually_to_ground_truth(self.get_first_output_file()) + self.check_pdf_using_validator(self.get_first_output_file()) + + def test_add_paragraphs_using_pacifico(self): + + # set GOOGLE_FONTS_API_KEY + try: + from tests.borb_secrets import populate_os_environ + + populate_os_environ() + except: + pass + + with open(self.get_second_output_file(), "wb") as in_file_handle: + PDF.dumps(in_file_handle, self._write_document_with_font("Pacifico")) + self.compare_visually_to_ground_truth(self.get_second_output_file()) + self.check_pdf_using_validator(self.get_second_output_file()) + + def test_add_paragraphs_using_shadows_into_light(self): + + # set GOOGLE_FONTS_API_KEY + try: + from tests.borb_secrets import populate_os_environ + + populate_os_environ() + except: + pass + + with open(self.get_third_output_file(), "wb") as in_file_handle: + PDF.dumps( + in_file_handle, self._write_document_with_font("Shadows Into Light") + ) + self.compare_visually_to_ground_truth(self.get_third_output_file()) + self.check_pdf_using_validator(self.get_third_output_file()) diff --git a/tests/pdf/canvas/layout/equation/artifacts_test_add_equation_using_horizontal_alignment/output_002.png b/tests/pdf/canvas/layout/equation/artifacts_test_add_equation_using_horizontal_alignment/output_002.png deleted file mode 100644 index 40e783de7..000000000 Binary files a/tests/pdf/canvas/layout/equation/artifacts_test_add_equation_using_horizontal_alignment/output_002.png and /dev/null differ diff --git a/tests/pdf/canvas/layout/image/image/artifacts_test_add_png_image/output_001.png b/tests/pdf/canvas/layout/image/image/artifacts_test_add_png_image/output_001.png index f8f37a6c7..36dece548 100644 Binary files a/tests/pdf/canvas/layout/image/image/artifacts_test_add_png_image/output_001.png and b/tests/pdf/canvas/layout/image/image/artifacts_test_add_png_image/output_001.png differ diff --git a/tests/pdf/canvas/layout/image/image/artifacts_test_add_png_image/output_002.png b/tests/pdf/canvas/layout/image/image/artifacts_test_add_png_image/output_002.png index f984a5f9b..4ff35e20c 100644 Binary files a/tests/pdf/canvas/layout/image/image/artifacts_test_add_png_image/output_002.png and b/tests/pdf/canvas/layout/image/image/artifacts_test_add_png_image/output_002.png differ diff --git a/tests/pdf/canvas/layout/image/unsplash/artifacts_test_add_unsplash_image/output_004.png b/tests/pdf/canvas/layout/image/unsplash/artifacts_test_add_unsplash_image/output_004.png new file mode 100644 index 000000000..0df105f71 Binary files /dev/null and b/tests/pdf/canvas/layout/image/unsplash/artifacts_test_add_unsplash_image/output_004.png differ diff --git a/tests/pdf/canvas/layout/image/unsplash/test_add_unsplash_image.py b/tests/pdf/canvas/layout/image/unsplash/test_add_unsplash_image.py index 52797d5ea..fcd66ac21 100644 --- a/tests/pdf/canvas/layout/image/unsplash/test_add_unsplash_image.py +++ b/tests/pdf/canvas/layout/image/unsplash/test_add_unsplash_image.py @@ -20,11 +20,11 @@ class TestAddUnsplashImage(TestCase): def test_add_unsplash_image(self): - # set unsplash API key + # set UNSPLASH_API_KEY try: - from tests.borb_secrets import populate_keyring + from tests.borb_secrets import populate_os_environ - populate_keyring() + populate_os_environ() except: pass @@ -52,11 +52,11 @@ def test_add_unsplash_image(self): def test_add_orderedlist_of_unsplash_images(self): - # set unsplash API key + # set UNSPLASH_API_KEY try: - from tests.borb_secrets import populate_keyring + from tests.borb_secrets import populate_os_environ - populate_keyring() + populate_os_environ() except: pass @@ -99,11 +99,11 @@ def test_add_orderedlist_of_unsplash_images(self): def test_add_unorderedlist_of_unsplash_images(self): - # set unsplash API key + # set UNSPLASH_API_KEY try: - from tests.borb_secrets import populate_keyring + from tests.borb_secrets import populate_os_environ - populate_keyring() + populate_os_environ() except: pass @@ -146,11 +146,11 @@ def test_add_unorderedlist_of_unsplash_images(self): def test_add_table_of_unsplash_images(self): - # set unsplash API key + # set UNSPLASH_API_KEY try: - from tests.borb_secrets import populate_keyring + from tests.borb_secrets import populate_os_environ - populate_keyring() + populate_os_environ() except: pass diff --git a/tests/pdf/canvas/layout/page_layout/test_singlecolumnlayoutwithoverflow.py b/tests/pdf/canvas/layout/page_layout/test_singlecolumnlayoutwithoverflow.py index 2e655e2b3..4d6c9acc5 100644 --- a/tests/pdf/canvas/layout/page_layout/test_singlecolumnlayoutwithoverflow.py +++ b/tests/pdf/canvas/layout/page_layout/test_singlecolumnlayoutwithoverflow.py @@ -1,5 +1,8 @@ +from decimal import Decimal + from borb.pdf import Document from borb.pdf import FixedColumnWidthTable +from borb.pdf import Image from borb.pdf import PDF from borb.pdf import Page from borb.pdf import Paragraph @@ -8,7 +11,7 @@ class TestSingleColumnLayoutWithOverflow(TestCase): - def test_singlecolumnlayoutwithoverflow(self): + def test_singlecolumnlayoutwithoverflow_with_text(self): pdf: Document = Document() page: Page = Page() @@ -34,3 +37,59 @@ def test_singlecolumnlayoutwithoverflow(self): with open(self.get_first_output_file(), "wb") as pdf_file_handle: PDF.dumps(pdf_file_handle, pdf) + + def test_singlecolumnlayoutwithoverflow_with_images(self): + + # create an empty Document + pdf: Document = Document() + + # create an empty Page + page: Page = Page() + pdf.add_page(page) + + # create a SingleColumnLayoutWithOverflow + layout: SingleColumnLayoutWithOverflow = SingleColumnLayoutWithOverflow(page) + + # decide how many images to add + number_of_content_rows: int = 5 + + # create FixedColumnWidthTable + table: FixedColumnWidthTable = FixedColumnWidthTable( + number_of_columns=7, + number_of_rows=number_of_content_rows + 1, + column_widths=[ + Decimal(2), + Decimal(6), + Decimal(1), + Decimal(2), + Decimal(1), + Decimal(2), + Decimal(1), + ], + ) + + # Add the table header + table.add(Paragraph("Name", font="Helvetica-Bold")) + table.add(Paragraph("Image", font="Helvetica-Bold")) + table.add(Paragraph("A", font="Helvetica-Bold")) + table.add(Paragraph("B", font="Helvetica-Bold")) + table.add(Paragraph("C", font="Helvetica-Bold")) + table.add(Paragraph("D", font="Helvetica-Bold")) + table.add(Paragraph("E", font="Helvetica-Bold")) + + image_url: str = "https://images.unsplash.com/photo-1606567595334-d39972c85dbe" + + for i in range(number_of_content_rows): + table.add(Paragraph(f"row_{i}")) + table.add(Image(image_url, width=Decimal(180), height=Decimal(156))) + table.add(Paragraph("a")) + table.add(Paragraph("b")) + table.add(Paragraph("c")) + table.add(Paragraph("d")) + table.add(Paragraph("e")) + + table.set_padding_on_all_cells(Decimal(2), Decimal(2), Decimal(2), Decimal(2)) + layout.add(table) + + with open(self.get_second_output_file(), "wb") as out_file_handle: + PDF.dumps(out_file_handle, pdf) diff --git a/tests/pdf/canvas/layout/text/paragraph/artifacts_test_add_paragraph_paint_box/output_001.png b/tests/pdf/canvas/layout/text/paragraph/artifacts_test_add_paragraph_paint_box/output_001.png index f85abb860..d958461a2 100644 Binary files a/tests/pdf/canvas/layout/text/paragraph/artifacts_test_add_paragraph_paint_box/output_001.png and b/tests/pdf/canvas/layout/text/paragraph/artifacts_test_add_paragraph_paint_box/output_001.png differ diff --git a/tests/pdf/xref/test_fix_broken_xref.py b/tests/pdf/xref/test_fix_broken_xref.py index cd822b1b4..f9028ff1e 100644 --- a/tests/pdf/xref/test_fix_broken_xref.py +++ b/tests/pdf/xref/test_fix_broken_xref.py @@ -31,6 +31,10 @@ def test_create_dummy_pdf(self): PDF.dumps(in_file_handle, pdf) def test_break_document(self): + + # create dummy PDF + self.test_create_dummy_pdf() + # read input document bytes_in: bytes = b"" with open(self.get_first_output_file(), "rb") as pdf_in_file_handle: @@ -69,6 +73,9 @@ def test_break_document(self): def test_read_broken_document(self): + # create broken PDF + self.test_break_document() + # read input document doc: typing.Optional[Document] = None l: SimpleTextExtraction = SimpleTextExtraction() diff --git a/tests/quality/test_code_files_are_small.py b/tests/quality/test_code_files_are_small.py index 74357159b..afcfb9e27 100644 --- a/tests/quality/test_code_files_are_small.py +++ b/tests/quality/test_code_files_are_small.py @@ -8,6 +8,7 @@ class TestCodeFilesAreSmall(unittest.TestCase): KNOWN_EXCEPTIONS: typing.List[str] = [ "a4_portrait_invoice_template.py", + "a4_portrait_resume_template.py", "a4_portrait_template.py", "adobe_glyph_list.py", "color.py", diff --git a/tests/quality/test_code_files_never_use_keyring.py b/tests/quality/test_code_files_never_use_keyring.py new file mode 100644 index 000000000..0c5635ffa --- /dev/null +++ b/tests/quality/test_code_files_never_use_keyring.py @@ -0,0 +1,22 @@ +import typing +import unittest + +from tests.quality.all_code_files import get_all_code_files_in_repository + + +class TestCodeFilesNeverUseKeyring(unittest.TestCase): + def test_code_files_never_use_keyring(self): + + # check all the imports in each file + for python_file in get_all_code_files_in_repository(): + + # fmt: off + lines: typing.List[str] = [] + with open(python_file, "r") as fh: + lines = fh.readlines() + imports: typing.List[str] = [x.strip() for x in lines if x.strip().startswith("import") or x.strip().startswith("from")] + # fmt: on + + # fmt: off + assert not any([x.startswith("import keyring") for x in imports]), f"keyring is used in {python_file}" + # fmt: on diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_000.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_000.pdf index 4ef65d0ef..6935ba9a5 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_000.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_000.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_001.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_001.pdf index 3b944aad7..e1420287d 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_001.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_001.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_002.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_002.pdf index 44525aa8a..f0ff3547b 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_002.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_002.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_003.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_003.pdf index cbd2ab38d..657509f23 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_003.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_003.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_004.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_004.pdf index a946de1e0..f81e9455a 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_004.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_004.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_005.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_005.pdf index 8b1b343d8..e2433615e 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_005.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_005.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_006.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_006.pdf index 26c728cf7..dcb974195 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_006.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_006.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_007.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_007.pdf index c032a72a8..9796fba3c 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_007.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_007.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_008.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_008.pdf index b31f77081..e69e82c2e 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_008.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_008.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_009.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_009.pdf index 63c2fd053..4ee994521 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_009.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_009.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_011.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_011.pdf index c5d62c7d9..e4c26fff1 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_011.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_011.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_012.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_012.pdf index db56c7e88..f89d8dd72 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_012.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_012.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_013.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_013.pdf index 1619b2e22..b362af456 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_013.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_013.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_014.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_014.pdf index 5f39d33ba..6945b565e 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_014.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_014.pdf differ diff --git a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_015.pdf b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_015.pdf index 1af697efd..9d83a0214 100644 Binary files a/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_015.pdf and b/tests/toolkit/export/html_to_pdf/artifacts_test_export_html_to_pdf/example_html_input_015.pdf differ diff --git a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-001.pdf b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-001.pdf index e1210e79a..7c80ee0e5 100644 Binary files a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-001.pdf and b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-001.pdf differ diff --git a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-002.pdf b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-002.pdf index 85c18d93e..daa5c4ed1 100644 Binary files a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-002.pdf and b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-002.pdf differ diff --git a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-003.pdf b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-003.pdf index 96f677c56..4775744a8 100644 Binary files a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-003.pdf and b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-003.pdf differ diff --git a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-004.pdf b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-004.pdf index dc35adf9f..33c009ef2 100644 Binary files a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-004.pdf and b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-004.pdf differ diff --git a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-005.pdf b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-005.pdf index aca7ed516..949acbd63 100644 Binary files a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-005.pdf and b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-005.pdf differ diff --git a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-006.pdf b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-006.pdf index 469020ab7..0714a507f 100644 Binary files a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-006.pdf and b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-006.pdf differ diff --git a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-007.pdf b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-007.pdf index 11c22451d..4da8d8a91 100644 Binary files a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-007.pdf and b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-007.pdf differ diff --git a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-008.pdf b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-008.pdf index fdcbc1018..6ccadf9c9 100644 Binary files a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-008.pdf and b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-008.pdf differ diff --git a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-009.pdf b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-009.pdf index 0a3a76f9d..5db477e20 100644 Binary files a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-009.pdf and b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-009.pdf differ diff --git a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-010.pdf b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-010.pdf index 628db4cc1..bf76273a4 100644 Binary files a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-010.pdf and b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-010.pdf differ diff --git a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-011.pdf b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-011.pdf index 41322ff33..25898a320 100644 Binary files a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-011.pdf and b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-011.pdf differ diff --git a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-012.pdf b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-012.pdf index fc6ee5687..8908c49e0 100644 Binary files a/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-012.pdf and b/tests/toolkit/export/markdown_to_pdf/artifacts_test_export_markdown_to_pdf/example-markdown-input-012.pdf differ diff --git a/tests/toolkit/export/pdf_to_mp3/artifacts_test_export_pdf_to_mp3/output.mp3 b/tests/toolkit/export/pdf_to_mp3/artifacts_test_export_pdf_to_mp3/output.mp3 index 174630a89..e835959c7 100644 Binary files a/tests/toolkit/export/pdf_to_mp3/artifacts_test_export_pdf_to_mp3/output.mp3 and b/tests/toolkit/export/pdf_to_mp3/artifacts_test_export_pdf_to_mp3/output.mp3 differ diff --git a/tests/toolkit/table/artifacts_test_detect_table/input_000.pdf b/tests/toolkit/table/artifacts_test_detect_table/input_000.pdf index af03f557b..7bfe888fe 100644 Binary files a/tests/toolkit/table/artifacts_test_detect_table/input_000.pdf and b/tests/toolkit/table/artifacts_test_detect_table/input_000.pdf differ diff --git a/tests/toolkit/table/artifacts_test_detect_table/input_001.pdf b/tests/toolkit/table/artifacts_test_detect_table/input_001.pdf index 3aafd9dc3..2a59977dc 100644 Binary files a/tests/toolkit/table/artifacts_test_detect_table/input_001.pdf and b/tests/toolkit/table/artifacts_test_detect_table/input_001.pdf differ diff --git a/tests/toolkit/table/artifacts_test_detect_table/input_002.pdf b/tests/toolkit/table/artifacts_test_detect_table/input_002.pdf index f93b2829f..5d0f4a35e 100644 Binary files a/tests/toolkit/table/artifacts_test_detect_table/input_002.pdf and b/tests/toolkit/table/artifacts_test_detect_table/input_002.pdf differ diff --git a/tests/toolkit/table/artifacts_test_detect_table/input_003.pdf b/tests/toolkit/table/artifacts_test_detect_table/input_003.pdf index 96d61ea43..e1d4ae2f0 100644 Binary files a/tests/toolkit/table/artifacts_test_detect_table/input_003.pdf and b/tests/toolkit/table/artifacts_test_detect_table/input_003.pdf differ diff --git a/tests/toolkit/table/artifacts_test_detect_table/input_004.pdf b/tests/toolkit/table/artifacts_test_detect_table/input_004.pdf index 5bba2e0e2..1dcb9c367 100644 Binary files a/tests/toolkit/table/artifacts_test_detect_table/input_004.pdf and b/tests/toolkit/table/artifacts_test_detect_table/input_004.pdf differ diff --git a/tests/toolkit/table/artifacts_test_detect_table/input_005.pdf b/tests/toolkit/table/artifacts_test_detect_table/input_005.pdf index fda61ef3c..5f9d3a882 100644 Binary files a/tests/toolkit/table/artifacts_test_detect_table/input_005.pdf and b/tests/toolkit/table/artifacts_test_detect_table/input_005.pdf differ diff --git a/tests/toolkit/table/artifacts_test_detect_table/input_006.pdf b/tests/toolkit/table/artifacts_test_detect_table/input_006.pdf index 29fbc5688..5fe5319c6 100644 Binary files a/tests/toolkit/table/artifacts_test_detect_table/input_006.pdf and b/tests/toolkit/table/artifacts_test_detect_table/input_006.pdf differ