diff --git a/pyproject.toml b/pyproject.toml index 4e565bb..f62dba5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,10 @@ classifiers = [ "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ] -dependencies = ["httpx[http2] ~= 0.24"] +dependencies = [ + "httpx[http2] ~= 0.24", + "typing-extensions; python_version < '3.11'" + ] [project.urls] Documentation = "https://github.com/stumpylog/gotenberg-client/#readme" diff --git a/src/gotenberg_client/_types_compat.py b/src/gotenberg_client/_types_compat.py new file mode 100644 index 0000000..91bfbc1 --- /dev/null +++ b/src/gotenberg_client/_types_compat.py @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2023-present Trenton H +# +# SPDX-License-Identifier: MPL-2.0 + +import sys + +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self # noqa: F401 diff --git a/src/gotenberg_client/base.py b/src/gotenberg_client/base.py index d5bb799..5061f3b 100644 --- a/src/gotenberg_client/base.py +++ b/src/gotenberg_client/base.py @@ -13,6 +13,7 @@ from httpx import Response from httpx._types import RequestFiles +from gotenberg_client._types_compat import Self from gotenberg_client.options import PdfAFormat from gotenberg_client.utils import guess_mime_type @@ -32,7 +33,7 @@ def __init__(self, client: Client, api_route: str) -> None: self._form_data: Dict[str, str] = {} self._file_map: Dict[str, Path] = {} - def __enter__(self) -> "BaseRoute": + def __enter__(self) -> Self: self.reset() return self diff --git a/src/gotenberg_client/convert/chromium.py b/src/gotenberg_client/convert/chromium.py index 378c422..1a0a577 100644 --- a/src/gotenberg_client/convert/chromium.py +++ b/src/gotenberg_client/convert/chromium.py @@ -9,6 +9,7 @@ from typing import List from typing import Union +from gotenberg_client._types_compat import Self from gotenberg_client.base import BaseApi from gotenberg_client.convert.common import ConvertBaseRoute from gotenberg_client.options import EmulatedMediaType @@ -51,94 +52,94 @@ class ChromiumBaseRoute(ConvertBaseRoute): https://gotenberg.dev/docs/routes#convert-with-chromium """ - def header(self, header: Path) -> "ChromiumBaseRoute": + def header(self, header: Path) -> Self: self._add_file_map(header, "header.html") return self - def footer(self, footer: Path) -> "ChromiumBaseRoute": + def footer(self, footer: Path) -> Self: self._add_file_map(footer, "footer.html") return self - def resource(self, resource: Path) -> "ChromiumBaseRoute": + def resource(self, resource: Path) -> Self: self._add_file_map(resource) return self - def resources(self, resources: List[Path]) -> "ChromiumBaseRoute": + def resources(self, resources: List[Path]) -> Self: for x in resources: self.resource(x) return self - def size(self, size: PageSize) -> "ChromiumBaseRoute": + def size(self, size: PageSize) -> Self: self._form_data.update(size.to_form()) return self page_size = size - def margins(self, margins: Margin) -> "ChromiumBaseRoute": + def margins(self, margins: Margin) -> Self: self._form_data.update(margins.to_form()) return self - def prefer_css_page_size(self) -> "ChromiumBaseRoute": + def prefer_css_page_size(self) -> Self: self._form_data.update({"preferCssPageSize": "true"}) return self - def prefer_set_page_size(self) -> "ChromiumBaseRoute": + def prefer_set_page_size(self) -> Self: self._form_data.update({"preferCssPageSize": "false"}) return self - def background_graphics(self) -> "ChromiumBaseRoute": + def background_graphics(self) -> Self: self._form_data.update({"printBackground": "true"}) return self - def no_background_graphics(self) -> "ChromiumBaseRoute": + def no_background_graphics(self) -> Self: self._form_data.update({"printBackground": "false"}) return self - def hide_background(self) -> "ChromiumBaseRoute": + def hide_background(self) -> Self: self._form_data.update({"omitBackground": "true"}) return self - def show_background(self) -> "ChromiumBaseRoute": + def show_background(self) -> Self: self._form_data.update({"omitBackground": "false"}) return self - def scale(self, scale: Union[int, float]) -> "ChromiumBaseRoute": + def scale(self, scale: Union[int, float]) -> Self: self._form_data.update({"scale": str(scale)}) return self - def render_wait(self, wait: Union[int, float]) -> "ChromiumBaseRoute": + def render_wait(self, wait: Union[int, float]) -> Self: self._form_data.update({"waitDelay": str(wait)}) return self - def render_expr(self, expr: str) -> "ChromiumBaseRoute": + def render_expr(self, expr: str) -> Self: self._form_data.update({"waitForExpression": expr}) return self - def media_type(self, media_type: EmulatedMediaType) -> "ChromiumBaseRoute": + def media_type(self, media_type: EmulatedMediaType) -> Self: self._form_data.update(media_type.to_form()) return self - def user_agent(self, agent: str) -> "ChromiumBaseRoute": + def user_agent(self, agent: str) -> Self: self._form_data.update({"userAgent": agent}) return self - def headers(self, headers: Dict[str, str]) -> "ChromiumBaseRoute": + def headers(self, headers: Dict[str, str]) -> Self: json_str = json.dumps(headers) # TODO: Need to check this self._form_data.update({"extraHttpHeaders": json_str}) return self - def fail_on_exceptions(self) -> "ChromiumBaseRoute": + def fail_on_exceptions(self) -> Self: self._form_data.update({"failOnConsoleExceptions": "true"}) return self - def dont_fail_on_exceptions(self) -> "ChromiumBaseRoute": + def dont_fail_on_exceptions(self) -> Self: self._form_data.update({"failOnConsoleExceptions": "false"}) return self class _FileBasedRoute(ChromiumBaseRoute): - def index(self, index: Path) -> "_FileBasedRoute": + def index(self, index: Path) -> Self: self._add_file_map(index, "index.html") return self @@ -154,7 +155,7 @@ class UrlRoute(ChromiumBaseRoute): https://gotenberg.dev/docs/routes#url-into-pdf-route """ - def url(self, url: str) -> "UrlRoute": + def url(self, url: str) -> Self: self._form_data["url"] = url return self @@ -167,11 +168,11 @@ class MarkdownRoute(_FileBasedRoute): https://gotenberg.dev/docs/routes#markdown-files-into-pdf-route """ - def markdown_file(self, markdown_file: Path) -> "MarkdownRoute": + def markdown_file(self, markdown_file: Path) -> Self: self._add_file_map(markdown_file) return self - def markdown_files(self, markdown_files: List[Path]) -> "MarkdownRoute": + def markdown_files(self, markdown_files: List[Path]) -> Self: for x in markdown_files: self.markdown_file(x) return self diff --git a/src/gotenberg_client/convert/common.py b/src/gotenberg_client/convert/common.py index bbc7599..72a6d45 100644 --- a/src/gotenberg_client/convert/common.py +++ b/src/gotenberg_client/convert/common.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: MPL-2.0 import logging +from gotenberg_client._types_compat import Self from gotenberg_client.base import BaseRoute from gotenberg_client.options import PageOrientation @@ -14,14 +15,14 @@ class ConvertBaseRoute(BaseRoute): All 3 convert routes provide control over orientation and page ranges """ - def orient(self, orient: PageOrientation) -> "ConvertBaseRoute": + def orient(self, orient: PageOrientation) -> Self: """ Sets the page orientation, either Landscape or portrait """ self._form_data.update(orient.to_form()) return self - def page_ranges(self, ranges: str) -> "ConvertBaseRoute": + def page_ranges(self, ranges: str) -> Self: """ Sets the page range string, allowing either some range or just a few pages diff --git a/src/gotenberg_client/convert/libre_office.py b/src/gotenberg_client/convert/libre_office.py index a75f4a5..3a35dfb 100644 --- a/src/gotenberg_client/convert/libre_office.py +++ b/src/gotenberg_client/convert/libre_office.py @@ -4,6 +4,7 @@ from pathlib import Path from typing import List +from gotenberg_client._types_compat import Self from gotenberg_client.base import BaseApi from gotenberg_client.convert.common import ConvertBaseRoute @@ -13,7 +14,7 @@ class LibreOfficeConvertRoute(ConvertBaseRoute): https://gotenberg.dev/docs/routes#convert-with-libreoffice """ - def convert(self, file_path: Path) -> "LibreOfficeConvertRoute": + def convert(self, file_path: Path) -> Self: """ Adds a single file to be converted to PDF. Can be called multiple times, resulting in a ZIP of the PDFs, unless merged @@ -21,7 +22,7 @@ def convert(self, file_path: Path) -> "LibreOfficeConvertRoute": self._add_file_map(file_path) return self - def convert_files(self, file_paths: List[Path]) -> "LibreOfficeConvertRoute": + def convert_files(self, file_paths: List[Path]) -> Self: """ Adds all provided files for conversion """ @@ -29,14 +30,14 @@ def convert_files(self, file_paths: List[Path]) -> "LibreOfficeConvertRoute": self.convert(x) return self - def merge(self) -> "LibreOfficeConvertRoute": + def merge(self) -> Self: """ Merge the resulting PDFs into one """ self._form_data.update({"merge": "true"}) return self - def no_merge(self) -> "LibreOfficeConvertRoute": + def no_merge(self) -> Self: """ Don't merge the resulting PDFs """ diff --git a/src/gotenberg_client/convert/pdfa.py b/src/gotenberg_client/convert/pdfa.py index dd5715e..2f9ec90 100644 --- a/src/gotenberg_client/convert/pdfa.py +++ b/src/gotenberg_client/convert/pdfa.py @@ -4,6 +4,7 @@ from pathlib import Path from typing import List +from gotenberg_client._types_compat import Self from gotenberg_client.base import BaseApi from gotenberg_client.convert.common import ConvertBaseRoute @@ -13,14 +14,14 @@ class PdfAConvertRoute(ConvertBaseRoute): https://gotenberg.dev/docs/routes#convert-into-pdfa-route """ - def convert(self, file_path: Path) -> "PdfAConvertRoute": + def convert(self, file_path: Path) -> Self: """ Convert a single PDF into the provided PDF/A format """ self._add_file_map(file_path) return self - def convert_files(self, file_paths: List[Path]) -> "PdfAConvertRoute": + def convert_files(self, file_paths: List[Path]) -> Self: for x in file_paths: self.convert(x) return self diff --git a/tests/test_merge.py b/tests/test_merge.py index 05a5961..be18b08 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -16,6 +16,10 @@ @pytest.fixture() def create_files(): + """ + Creates 2 files in a temporary directory and cleans them up + after their use + """ temp_dir = Path(tempfile.mkdtemp()) test_file = SAMPLE_DIR / "sample1.pdf" other_test_file = temp_dir / "sample2.pdf"