From 853a39390cfc3afde715a31d5cdc7fbcb81b1e45 Mon Sep 17 00:00:00 2001 From: Adrien Brignon Date: Mon, 8 May 2023 17:50:21 +0200 Subject: [PATCH] fix: compatibility with Python 3.7+ --- mkdocs_exporter/browser.py | 11 +++++----- mkdocs_exporter/page.py | 3 ++- mkdocs_exporter/plugin.py | 2 +- mkdocs_exporter/plugins/extras/config.py | 8 +++---- mkdocs_exporter/plugins/extras/plugin.py | 3 ++- mkdocs_exporter/plugins/pdf/plugin.py | 9 ++++---- mkdocs_exporter/plugins/pdf/renderer.py | 15 +++++++------ mkdocs_exporter/preprocessor.py | 28 +++++++++++++++--------- poetry.lock | 21 +++++++++++++++++- pyproject.toml | 3 ++- 10 files changed, 68 insertions(+), 35 deletions(-) diff --git a/mkdocs_exporter/browser.py b/mkdocs_exporter/browser.py index c01fd13..b5d988e 100644 --- a/mkdocs_exporter/browser.py +++ b/mkdocs_exporter/browser.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import asyncio -from typing import Self from tempfile import NamedTemporaryFile from mkdocs_exporter.logging import logger from playwright.async_api import async_playwright @@ -29,7 +30,7 @@ def __init__(self): self.lock = asyncio.Lock() - async def launch(self) -> Self: + async def launch(self) -> Browser: """Launches the browser.""" if self.launched: @@ -50,15 +51,15 @@ async def launch(self) -> Self: return self - async def close(self) -> Self: + async def close(self) -> Browser: """Closes the browser.""" if self.context: await self.context.close() if self.browser: await self.browser.close() - if self.playwright: - await self.playwright.stop() + + self._launched = False return self diff --git a/mkdocs_exporter/page.py b/mkdocs_exporter/page.py index 9dfcf15..47779ac 100644 --- a/mkdocs_exporter/page.py +++ b/mkdocs_exporter/page.py @@ -1,3 +1,4 @@ +from typing import Optional from mkdocs.structure.pages import Page as BasePage @@ -8,7 +9,7 @@ class Page(BasePage): def __init__(self, *args, **kwargs): """The constructor.""" - self.html: None | str = None + self.html: Optional[str] = None """The page's HTML content.""" self.formats: dict[str, str] diff --git a/mkdocs_exporter/plugin.py b/mkdocs_exporter/plugin.py index 1372c77..cac1e89 100644 --- a/mkdocs_exporter/plugin.py +++ b/mkdocs_exporter/plugin.py @@ -16,7 +16,7 @@ def on_pre_page(self, page: Page, **kwargs) -> None: @event_priority(-100) - def on_post_page(self, html: str, **kwargs) -> str | None: + def on_post_page(self, html: str, **kwargs) -> str: """Invoked after a page has been built (and after all other plugins).""" preprocessor = Preprocessor() diff --git a/mkdocs_exporter/plugins/extras/config.py b/mkdocs_exporter/plugins/extras/config.py index 6876479..c26bd88 100644 --- a/mkdocs_exporter/plugins/extras/config.py +++ b/mkdocs_exporter/plugins/extras/config.py @@ -6,16 +6,16 @@ class ButtonConfig(BaseConfig): """The configuration of a button.""" - title = c.Type(str | Callable) + title = c.Type((str, Callable)) """The button's title.""" - icon = c.Type(str | Callable) + icon = c.Type((str, Callable)) """The button's icon (typically, an SVG element).""" - href = c.Type(str | Callable) + href = c.Type((str, Callable)) """The button's 'href' attribute.""" - download = c.Optional(c.Type(bool | str | Callable)) + download = c.Optional(c.Type((bool, str, Callable))) """The button's 'download' attribute.""" target = c.Optional(c.Choice(('_blank', '_self', '_parent', '_top'))) diff --git a/mkdocs_exporter/plugins/extras/plugin.py b/mkdocs_exporter/plugins/extras/plugin.py index ee63ba1..ffd9fed 100644 --- a/mkdocs_exporter/plugins/extras/plugin.py +++ b/mkdocs_exporter/plugins/extras/plugin.py @@ -1,3 +1,4 @@ +from typing import Optional from mkdocs.plugins import BasePlugin from mkdocs_exporter.page import Page from mkdocs_exporter.preprocessor import Preprocessor @@ -8,7 +9,7 @@ class Plugin(BasePlugin[Config]): """The plugin.""" - def on_post_page(self, html: str, page: Page, **kwargs) -> None | str: + def on_post_page(self, html: str, page: Page, **kwargs) -> Optional[str]: """Invoked after a page has been built.""" preprocessor = Preprocessor() diff --git a/mkdocs_exporter/plugins/pdf/plugin.py b/mkdocs_exporter/plugins/pdf/plugin.py index 357aa51..cb4ad75 100644 --- a/mkdocs_exporter/plugins/pdf/plugin.py +++ b/mkdocs_exporter/plugins/pdf/plugin.py @@ -3,6 +3,7 @@ import asyncio from weasyprint import urls +from typing import Optional from mkdocs.plugins import BasePlugin from mkdocs_exporter.page import Page from mkdocs.structure.pages import Page @@ -20,9 +21,9 @@ class Plugin(BasePlugin[Config]): def __init__(self): """The constructor.""" - self.renderer: None | Renderer = None + self.renderer: Optional[Renderer] = None self.tasks: list[types.CoroutineType] = [] - self.loop: None | asyncio.AbstractEventLoop = None + self.loop: Optional[asyncio.AbstractEventLoop] = None def on_config(self, config: dict) -> None: @@ -101,7 +102,7 @@ def on_pre_page(self, page: Page, config: dict, **kwargs): @event_priority(-75) - def on_post_page(self, html: str, page: Page, config: dict) -> None | str: + def on_post_page(self, html: str, page: Page, config: dict) -> Optional[str]: """Invoked after a page has been built.""" page.html = html @@ -125,7 +126,7 @@ async def render(page: Page) -> None: return page.html - def on_post_build(self, **kwargs): + def on_post_build(self, **kwargs) -> None: """Invoked after the build process.""" if not self.config.enabled: diff --git a/mkdocs_exporter/plugins/pdf/renderer.py b/mkdocs_exporter/plugins/pdf/renderer.py index ea3981a..5824fed 100644 --- a/mkdocs_exporter/plugins/pdf/renderer.py +++ b/mkdocs_exporter/plugins/pdf/renderer.py @@ -1,7 +1,8 @@ +from __future__ import annotations + import os -import importlib.resources +import importlib_resources -from typing import Self from mkdocs_exporter.page import Page from mkdocs_exporter.resources import js from mkdocs_exporter.browser import Browser @@ -22,7 +23,7 @@ def __init__(self, browser: Browser = None): self.browser = browser or Browser() - def add_stylesheet(self, path: str) -> Self: + def add_stylesheet(self, path: str) -> Renderer: """Adds a stylesheet to the renderer.""" self.stylesheets.append(path) @@ -30,7 +31,7 @@ def add_stylesheet(self, path: str) -> Self: return self - def add_script(self, path: str) -> Self: + def add_script(self, path: str) -> Renderer: """Adds a script to the renderer.""" self.scripts.append(path) @@ -38,7 +39,7 @@ def add_script(self, path: str) -> Self: return self - def cover(self, template: str) -> Self: + def cover(self, template: str) -> Renderer: """Renders a cover.""" content = template.strip('\n') @@ -70,14 +71,14 @@ async def render(self, page: Page, **kwargs) -> bytes: preprocessor.script(file.read()) if kwargs.get('polyfills', True): - preprocessor.script(importlib.resources.files(js).joinpath('pagedjs.min.js').read_text()) + preprocessor.script(importlib_resources.files(js).joinpath('pagedjs.min.js').read_text()) html = preprocessor.done() return await self.browser.print(html) - async def dispose(self): + async def dispose(self) -> None: """Dispose of the renderer.""" if self.browser: diff --git a/mkdocs_exporter/preprocessor.py b/mkdocs_exporter/preprocessor.py index bcab2db..7f5a380 100644 --- a/mkdocs_exporter/preprocessor.py +++ b/mkdocs_exporter/preprocessor.py @@ -1,9 +1,11 @@ +from __future__ import annotations + import os import sass from weasyprint import urls from bs4 import BeautifulSoup, Tag -from typing import Any, Callable, Self +from typing import Any, Callable, Union from mkdocs_exporter.logging import logger @@ -16,7 +18,7 @@ def __init__(self, html: str = None): self.preprocess(html) - def preprocess(self, html: str) -> Self: + def preprocess(self, html: str) -> Preprocessor: """Gives the preprocessor some HTML to work on.""" self.html = BeautifulSoup(html, 'lxml') if isinstance(html, str) else None @@ -24,7 +26,7 @@ def preprocess(self, html: str) -> Self: return self - def button(self, title: str, href: str, icon: str, **kwargs) -> Self: + def button(self, title: str, href: str, icon: str, **kwargs) -> Preprocessor: """Adds a button at the top of the page.""" button = self.html.new_tag('a', title=title, href=href, **kwargs, attrs={'class': 'md-content__button md-icon'}) @@ -36,7 +38,7 @@ def button(self, title: str, href: str, icon: str, **kwargs) -> Self: return self - def teleport(self) -> Self: + def teleport(self) -> Preprocessor: """Teleport elements to their destination.""" for element in self.html.select('*[data-teleport]'): @@ -59,7 +61,7 @@ def teleport(self) -> Self: return self - def script(self, script: str = None, type: str = 'text/javascript', **kwargs): + def script(self, script: str = None, type: str = 'text/javascript', **kwargs) -> Preprocessor: """Appends a script to the document's body.""" element = self.html.new_tag('script', type=type, **kwargs) @@ -68,8 +70,10 @@ def script(self, script: str = None, type: str = 'text/javascript', **kwargs): self.html.body.append(element) + return self + - def stylesheet(self, stylesheet: str, **kwargs) -> Self: + def stylesheet(self, stylesheet: str, **kwargs) -> Preprocessor: """Appends a stylesheet to the document's head.""" css = sass.compile(string=stylesheet, output_style='compressed') @@ -79,8 +83,10 @@ def stylesheet(self, stylesheet: str, **kwargs) -> Self: self.html.head.append(element) + return self - def remove(self, selectors: str | list[str]) -> Self: + + def remove(self, selectors: Union[str, list[str]]) -> Preprocessor: """Removes some elements.""" if isinstance(selectors, str): @@ -90,8 +96,10 @@ def remove(self, selectors: str | list[str]) -> Self: for element in self.html.select(selector): element.decompose() + return self + - def remove_scripts(self, predicate: Callable[[Any], bool] = lambda _: True) -> Self: + def remove_scripts(self, predicate: Callable[[Any], bool] = lambda _: True) -> Preprocessor: """Remove all script tags.""" for element in self.html.find_all('script'): @@ -101,7 +109,7 @@ def remove_scripts(self, predicate: Callable[[Any], bool] = lambda _: True) -> S return self - def update_links(self, base: str, root: str = None) -> Self: + def update_links(self, base: str, root: str = None) -> Preprocessor: """Updates links to their new base location.""" for element in self.html.find_all('link', href=True): @@ -122,7 +130,7 @@ def done(self) -> str: return result - def _resolve_link(self, url: str, base: str, root: str = None): + def _resolve_link(self, url: str, base: str, root: str = None) -> str: """Resolves a link to its new base location.""" if urls.url_is_absolute(url): diff --git a/poetry.lock b/poetry.lock index b18c819..5833308 100644 --- a/poetry.lock +++ b/poetry.lock @@ -445,6 +445,25 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker perf = ["ipython"] testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] +[[package]] +name = "importlib-resources" +version = "5.12.0" +description = "Read resources from Python packages" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "importlib_resources-5.12.0-py3-none-any.whl", hash = "sha256:7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a"}, + {file = "importlib_resources-5.12.0.tar.gz", hash = "sha256:4be82589bf5c1d7999aedf2a45159d10cb3ca4f19b2271f8792bc8e6da7b22f6"}, +] + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + [[package]] name = "jinja2" version = "3.1.2" @@ -1171,4 +1190,4 @@ test = ["pytest"] [metadata] lock-version = "2.0" python-versions = ">=3.7" -content-hash = "5586c95d40c196405b2fff86e81505950348437ae6fec74642fe95dc603c7f20" +content-hash = "7d31a1a664c2fd354e16a2fd74c76ea926764c01969d588d1e50bb246d91e137" diff --git a/pyproject.toml b/pyproject.toml index 87358fa..37f88ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "mkdocs-exporter" -version = "0.0.1" +version = "0.0.2" repository = "https://github.com/adrienbrignon/mkdocs-exporter" keywords = ["mkdocs", "pdf", "exporter"] description = "A highly-configurable plugin for MkDocs that exports your pages to PDF files." @@ -27,6 +27,7 @@ beautifulsoup4 = ">=4.12.2" weasyprint = ">=50.0" lxml = ">=4.9" libsass = ">=0.22.0" +importlib-resources = "*" [tool.poetry.plugins."mkdocs.plugins"] "mkdocs/exporter" = "mkdocs_exporter.plugin:Plugin"