diff --git a/README.md b/README.md index f043f59..5b19751 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ ## Features -- Build static HTML files from Markdown files. - - Turn a single Markdown file into a HTML slideshow. - - Turn a folder with Markdown files into a collection of HTML slideshows. -- Publish your slideshow(s) anywhere that static files can be served. -- Preview your site as you work, thanks to [python-livereload](https://pypi.org/project/livereload/). -- Use custom favicons, CSS themes, templates, ... if desired. -- And more! +- Build static HTML files from Markdown files. + - Turn a single Markdown file into a HTML slideshow. + - Turn a folder with Markdown files into a collection of HTML slideshows. +- Publish your slideshow(s) anywhere that static files can be served. +- Preview your site as you work, thanks to [python-livereload](https://pypi.org/project/livereload/). +- Use custom favicons, CSS themes, templates, ... if desired. +- And more! ## Example @@ -53,3 +53,39 @@ mkslides-reveal serve docs/ ```bash mkslides-reveal serve test.md ``` + +## Configuration + +Just create a `mkslides.yml`. All options are optional, you only have to add what you want to change to `mkslides.yml`. + +Here's an example: + +```yml +index: + title: example-title + favicon: ./example-index-favicon.ico + theme: example-index-theme.css +slides: + favicon: ./example-slides-favicon.ico + theme: example-slides-theme.css + highlight_theme: example-slides-highlight-theme.css + separator: ^\s*---\s*$ + separator_vertical: ^\s*-v-\s*$ + separator_notes: "^Notes?:" + separator_charset: utf-8 +reveal.js: + height: 1080 + width: 1920 + transition: fade +plugins: + - name: RevealMermaid + extra_javascript: + - https://cdn.jsdelivr.net/npm/reveal.js-mermaid-plugin/plugin/mermaid/mermaid.min.js + - extra_javascript: + - https://cdn.jsdelivr.net/npm/reveal-plantuml/dist/reveal-plantuml.min.js +``` + +- `favicon`and `theme`, can also be configured as an URL, e.g. `https://example.org/theme.css`. +- `theme` can also be configured as a [Reveal.js built-in theme](https://revealjs.com/themes/), e.g. `black`, `white`, `league`, `solarized`, `dracula`, ... . +- `highlight_theme` can also be configured as a [highlight.js built-in theme](https://highlightjs.org/examples), e.g. `monokai`, `obsidian`, `tokyo-night-dark`, `vs`, ... . +- `reveal.js` can contain all [Reveal.js options](https://revealjs.com/config/). diff --git a/poetry.lock b/poetry.lock index b1517af..b31ed50 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,49 +1,5 @@ # This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. -[[package]] -name = "black" -version = "24.8.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6"}, - {file = "black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb"}, - {file = "black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42"}, - {file = "black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a"}, - {file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"}, - {file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"}, - {file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"}, - {file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"}, - {file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"}, - {file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"}, - {file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"}, - {file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"}, - {file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"}, - {file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"}, - {file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"}, - {file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"}, - {file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"}, - {file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"}, - {file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"}, - {file = "black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb"}, - {file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"}, - {file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "bumpver" version = "2023.1129" @@ -323,33 +279,6 @@ files = [ {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - -[[package]] -name = "platformdirs" -version = "4.3.2" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.8" -files = [ - {file = "platformdirs-4.3.2-py3-none-any.whl", hash = "sha256:eb1c8582560b34ed4ba105009a4badf7f6f85768b30126f351328507b2beb617"}, - {file = "platformdirs-4.3.2.tar.gz", hash = "sha256:9e5e27a08aa095dd127b9f2e764d74254f482fef22b0970773bfba79d091ab8c"}, -] - -[package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.11.2)"] - [[package]] name = "pluggy" version = "1.5.0" @@ -497,6 +426,33 @@ pygments = ">=2.13.0,<3.0.0" [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] +[[package]] +name = "ruff" +version = "0.6.4" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.6.4-py3-none-linux_armv6l.whl", hash = "sha256:c4b153fc152af51855458e79e835fb6b933032921756cec9af7d0ba2aa01a258"}, + {file = "ruff-0.6.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:bedff9e4f004dad5f7f76a9d39c4ca98af526c9b1695068198b3bda8c085ef60"}, + {file = "ruff-0.6.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d02a4127a86de23002e694d7ff19f905c51e338c72d8e09b56bfb60e1681724f"}, + {file = "ruff-0.6.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7862f42fc1a4aca1ea3ffe8a11f67819d183a5693b228f0bb3a531f5e40336fc"}, + {file = "ruff-0.6.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eebe4ff1967c838a1a9618a5a59a3b0a00406f8d7eefee97c70411fefc353617"}, + {file = "ruff-0.6.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:932063a03bac394866683e15710c25b8690ccdca1cf192b9a98260332ca93408"}, + {file = "ruff-0.6.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:50e30b437cebef547bd5c3edf9ce81343e5dd7c737cb36ccb4fe83573f3d392e"}, + {file = "ruff-0.6.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c44536df7b93a587de690e124b89bd47306fddd59398a0fb12afd6133c7b3818"}, + {file = "ruff-0.6.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ea086601b22dc5e7693a78f3fcfc460cceabfdf3bdc36dc898792aba48fbad6"}, + {file = "ruff-0.6.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b52387d3289ccd227b62102c24714ed75fbba0b16ecc69a923a37e3b5e0aaaa"}, + {file = "ruff-0.6.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0308610470fcc82969082fc83c76c0d362f562e2f0cdab0586516f03a4e06ec6"}, + {file = "ruff-0.6.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:803b96dea21795a6c9d5bfa9e96127cc9c31a1987802ca68f35e5c95aed3fc0d"}, + {file = "ruff-0.6.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:66dbfea86b663baab8fcae56c59f190caba9398df1488164e2df53e216248baa"}, + {file = "ruff-0.6.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:34d5efad480193c046c86608dbba2bccdc1c5fd11950fb271f8086e0c763a5d1"}, + {file = "ruff-0.6.4-py3-none-win32.whl", hash = "sha256:f0f8968feea5ce3777c0d8365653d5e91c40c31a81d95824ba61d871a11b8523"}, + {file = "ruff-0.6.4-py3-none-win_amd64.whl", hash = "sha256:549daccee5227282289390b0222d0fbee0275d1db6d514550d65420053021a58"}, + {file = "ruff-0.6.4-py3-none-win_arm64.whl", hash = "sha256:ac4b75e898ed189b3708c9ab3fc70b79a433219e1e87193b4f2b77251d058d14"}, + {file = "ruff-0.6.4.tar.gz", hash = "sha256:ac3b5bfbee99973f80aa1b7cbd1c9cbce200883bdd067300c22a6cc1c7fba212"}, +] + [[package]] name = "toml" version = "0.10.2" @@ -553,4 +509,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "fd2d6d1ef3eb918ac53a6d091e0f2014d281a5e953840fa49fe458774895ea8e" +content-hash = "1e951513746db3a7eb530ddd9f6f20dadfbd78a57de9400e8a19cd05113353b8" diff --git a/pyproject.toml b/pyproject.toml index ed0af60..8d0b424 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,9 +20,9 @@ click = "^8.1.7" [tool.poetry.group.dev.dependencies] bumpver = "^2023.1129" -black = "^24.8.0" mypy = "^1.11.2" types-pyyaml = "^6.0.12.20240808" +ruff = "^0.6.4" [tool.poetry.group.test.dependencies] @@ -50,3 +50,24 @@ push = true [tool.bumpver.file_patterns] "src/mkslides_reveal/__init__.py" = ['^__version__ = "{version}"'] "pyproject.toml" = ['^version = "{version}"', '^current_version = "{version}"'] + +[tool.ruff.lint] +ignore = [ + "ANN401", # Dynamically typed expressions (typing.Any) are disallowed + "D100", # Missing docstring in public module + "D101", # Missing docstring in public class + "D103", # Missing docstring in public function + "D102", # Missing docstring in public method + "D104", # Missing docstring in public package" + "D107", # Missing docstring in `__init__` + "E501", # Line too long + "FA102", # Missing `from __future__ import annotations`, but uses PEP 585 collection + "G004", # Logging statement uses f-string" + "PLR0913", # Too many arguments in function definition + "RET504", # Unnecessary assignment to `...` before `return` statement + "S101", # Use of `assert` detected + "TD002", # Missing author in TODO; try: `# TODO(): ...` or `# TODO @: ...` + "TD003", # Missing issue link on the line following this TODO + +] +select = ["ALL"] diff --git a/src/mkslides_reveal/__init__.py b/src/mkslides_reveal/__init__.py index cb8be20..fb69db9 100644 --- a/src/mkslides_reveal/__init__.py +++ b/src/mkslides_reveal/__init__.py @@ -1,3 +1 @@ -#!/usr/bin/env python - __version__ = "0.1.14" diff --git a/src/mkslides_reveal/__main__.py b/src/mkslides_reveal/__main__.py index 4e314c7..f2f5b26 100644 --- a/src/mkslides_reveal/__main__.py +++ b/src/mkslides_reveal/__main__.py @@ -1,27 +1,24 @@ -#!/usr/bin/env python - -import shutil -import click -import livereload import logging +import shutil import tempfile +from pathlib import Path +from urllib.parse import urlparse +import click +import livereload from livereload.handlers import LiveReloadHandler -from pathlib import Path from rich.logging import RichHandler -from urllib.parse import urlparse from .config import Config from .constants import ( - EXPECTED_CONFIG_LOCATION, DEFAULT_OUTPUT_DIR, - VERSION, - REVEALJS_VERSION, + EXPECTED_CONFIG_LOCATION, HIGHLIGHTJS_THEMES_VERSION, + REVEALJS_VERSION, + VERSION, ) from .markupgenerator import MarkupGenerator - logger = logging.getLogger() logger.setLevel("DEBUG") logger.addHandler(RichHandler(show_path=False)) @@ -54,8 +51,7 @@ "", ) def cli() -> None: - "MkSlides-Reveal - Slides with Markdown using the power of Reveal.js." - pass + """MkSlides-Reveal - Slides with Markdown using the power of Reveal.js.""" def read_config(config_location: str) -> Config: @@ -100,12 +96,10 @@ def generate(config_file, input_path: Path, output_directory: Path) -> None: default=DEFAULT_OUTPUT_DIR, ) def build(files, config_file, site_dir) -> None: - """ - Build the MkDocs documentation. + """Build the MkDocs documentation. FILENAME|PATH is the path to the Markdown file, or the directory containing Markdown files. """ - logger.info("Command: build") input_path = Path(files).resolve(strict=True) @@ -161,12 +155,10 @@ def serve( watch_slides_template, config_file, ) -> None: - """ - Run the builtin development server. + """Run the builtin development server. FILENAME|PATH is the path to the Markdown file, or the directory containing Markdown files. """ - logger.info("Command: serve") input_path = Path(files).resolve(strict=True) @@ -190,7 +182,7 @@ def reload() -> None: watched_paths = [ files, - config_file, # TODO reload config + config_file, # TODO: reload config ] if watch_index_theme: diff --git a/src/mkslides_reveal/config.py b/src/mkslides_reveal/config.py index 37bdc13..bc1997c 100644 --- a/src/mkslides_reveal/config.py +++ b/src/mkslides_reveal/config.py @@ -1,11 +1,9 @@ -import importlib import logging -import yaml - from pathlib import Path -from .constants import DEFAULT_CONFIG_RESOURCE +import yaml +from .constants import DEFAULT_CONFIG_RESOURCE logger = logging.getLogger(__name__) @@ -72,7 +70,7 @@ def merge_config_from_file(self, config_path: Path) -> None: def merge_config_from_dict(self, new_config: dict) -> None: self.__config = self.__recursive_merge(self.__config, new_config) - logger.info(f"Config merged from dict") + logger.info("Config merged from dict") logger.info(f"Config: {self.__config}") def __get(self, *keys) -> str | dict | list | None: diff --git a/src/mkslides_reveal/constants.py b/src/mkslides_reveal/constants.py index a4808de..ad61381 100644 --- a/src/mkslides_reveal/constants.py +++ b/src/mkslides_reveal/constants.py @@ -1,7 +1,7 @@ import json import re +from importlib import metadata, resources -from importlib import resources, metadata from jinja2 import Environment, FileSystemLoader, PackageLoader, select_autoescape MD_LINK_REGEX = re.compile( @@ -51,11 +51,12 @@ HIGHLIGHTJS_THEMES_RESOURCE = HIGHLIGHTJS_RESOURCE.joinpath("build", "styles") DEFAULT_JINJA2_ENVIRONMENT = Environment( - loader=PackageLoader("assets"), autoescape=select_autoescape() + loader=PackageLoader("assets"), + autoescape=select_autoescape(), ) DEFAULT_INDEX_TEMPLATE = DEFAULT_JINJA2_ENVIRONMENT.get_template("index.html.jinja") DEFAULT_SLIDESHOW_TEMPLATE = DEFAULT_JINJA2_ENVIRONMENT.get_template( - "slideshow.html.jinja" + "slideshow.html.jinja", ) LOCAL_JINJA2_ENVIRONMENT = Environment(loader=FileSystemLoader(".")) diff --git a/src/mkslides_reveal/markupgenerator.py b/src/mkslides_reveal/markupgenerator.py index b6220e9..f5f9c55 100644 --- a/src/mkslides_reveal/markupgenerator.py +++ b/src/mkslides_reveal/markupgenerator.py @@ -1,26 +1,26 @@ import datetime -import frontmatter import logging import shutil import time - from importlib import resources from importlib.resources.abc import Traversable from pathlib import Path from typing import Any from urllib.parse import urlparse +import frontmatter + from .config import Config from .constants import ( + DEFAULT_INDEX_TEMPLATE, + DEFAULT_SLIDESHOW_TEMPLATE, + HIGHLIGHTJS_THEMES_RESOURCE, HTML_BACKGROUND_IMAGE_REGEX, HTML_IMAGE_REGEX, + LOCAL_JINJA2_ENVIRONMENT, MD_LINK_REGEX, REVEALJS_RESOURCE, REVEALJS_THEMES_RESOURCE, - HIGHLIGHTJS_THEMES_RESOURCE, - DEFAULT_INDEX_TEMPLATE, - DEFAULT_SLIDESHOW_TEMPLATE, - LOCAL_JINJA2_ENVIRONMENT, ) logger = logging.getLogger(__name__) @@ -31,8 +31,7 @@ def __init__( self, config: Config, output_directory_path: Path, - ): - + ) -> None: # Config self.config = config @@ -41,7 +40,7 @@ def __init__( self.output_directory_path = output_directory_path.resolve(strict=False) logger.info( - f'Requested output directory: "{self.output_directory_path.absolute()}"' + f'Requested output directory: "{self.output_directory_path.absolute()}"', ) self.output_assets_path = self.output_directory_path / "assets" @@ -60,32 +59,33 @@ def create_output_directory(self) -> None: self.clear_output_directory() else: self.output_directory_path.mkdir(parents=True, exist_ok=True) - logger.info(f"Output directory created") + logger.info("Output directory created") - with resources.as_file(REVEALJS_RESOURCE) as REVEALJS_PATH: - self.__copy(REVEALJS_PATH, self.output_revealjs_path) + with resources.as_file(REVEALJS_RESOURCE) as revealjs_path: + self.__copy(revealjs_path, self.output_revealjs_path) def process_markdown(self, input_path: Path) -> None: - logger.info(f"Processing markdown") + logger.info("Processing markdown") start_time = time.perf_counter() if input_path.is_dir(): self.__process_markdown_directory(input_path) else: _, output_markup_path = self.__process_markdown_file( - input_path, input_path.parent + input_path, + input_path.parent, ) original_output_markup_path = output_markup_path if output_markup_path.stem != "index": output_markup_path.rename(output_markup_path.with_stem("index")) logger.info( - f'Renamed "{original_output_markup_path.absolute()}" to "{output_markup_path.absolute()}" as it was the only Markdown file' + f'Renamed "{original_output_markup_path.absolute()}" to "{output_markup_path.absolute()}" as it was the only Markdown file', ) end_time = time.perf_counter() logger.info( - f"Finished processing markdown in {end_time - start_time:.2f} seconds" + f"Finished processing markdown in {end_time - start_time:.2f} seconds", ) ################################################################################ @@ -108,12 +108,13 @@ def __process_markdown_file( # Get the relative path of reveal.js output_markup_path = self.output_directory_path / md_file.relative_to( - md_root_path + md_root_path, ) output_markup_path = output_markup_path.with_suffix(".html") relative_revealjs_path = self.output_revealjs_path.relative_to( - output_markup_path.parent, walk_up=True + output_markup_path.parent, + walk_up=True, ) revealjs_config = self.config.get_revealjs_options() @@ -123,7 +124,9 @@ def __process_markdown_file( relative_theme_path = None if theme := self.config.get_slides_theme(): relative_theme_path = self.__copy_theme( - output_markup_path, theme, REVEALJS_THEMES_RESOURCE + output_markup_path, + theme, + REVEALJS_THEMES_RESOURCE, ) # Copy the highlight CSS @@ -131,7 +134,9 @@ def __process_markdown_file( relative_highlight_theme_path = None if theme := self.config.get_slides_highlight_theme(): relative_highlight_theme_path = self.__copy_theme( - output_markup_path, theme, HIGHLIGHTJS_THEMES_RESOURCE + output_markup_path, + theme, + HIGHLIGHTJS_THEMES_RESOURCE, ) # Copy the favicon @@ -188,19 +193,20 @@ def __process_markdown_directory(self, md_root_path: Path) -> None: slideshows = [] for md_file in md_root_path.glob("**/*.md"): (metadata, output_markup_path) = self.__process_markdown_file( - md_file, md_root_path + md_file, + md_root_path, ) slideshows.append( { "title": metadata.get("title", md_file.stem), "location": output_markup_path.relative_to( - self.output_directory_path + self.output_directory_path, ), - } + }, ) - logger.info(f"Generating index") + logger.info("Generating index") index_path = self.output_directory_path / "index.html" @@ -233,7 +239,10 @@ def __process_markdown_directory(self, md_root_path: Path) -> None: self.__create_file(index_path, content) def __copy_local_files( - self, md_file: Path, md_root_path: Path, markdown: str + self, + md_file: Path, + md_root_path: Path, + markdown: str, ) -> None: for regex in [MD_LINK_REGEX, HTML_IMAGE_REGEX, HTML_BACKGROUND_IMAGE_REGEX]: for m in regex.finditer(markdown): @@ -251,7 +260,7 @@ def __copy_theme( ) -> Path | str: if self.__is_absolute_url(theme): logger.info( - f'Using theme "{theme}" from an absolute URL, no copy necessary' + f'Using theme "{theme}" from an absolute URL, no copy necessary', ) return theme @@ -259,11 +268,11 @@ def __copy_theme( if not theme.endswith(".css"): assert default_theme_resource is not None with resources.as_file( - default_theme_resource.joinpath(theme) + default_theme_resource.joinpath(theme), ) as theme_path: theme_path = theme_path.with_suffix(".css").resolve(strict=True) logger.info( - f'Using built-in theme "{theme}" from "{theme_path.absolute()}"' + f'Using built-in theme "{theme}" from "{theme_path.absolute()}"', ) else: theme_path = Path(theme).resolve(strict=True) @@ -273,7 +282,8 @@ def __copy_theme( self.__copy_to_output(theme_path, theme_output_path) relative_theme_path = theme_output_path.relative_to( - file_using_theme_path.parent, walk_up=True + file_using_theme_path.parent, + walk_up=True, ) return relative_theme_path @@ -281,7 +291,7 @@ def __copy_theme( def __copy_favicon(self, file_using_favicon_path: Path, favicon: str) -> Path | str: if self.__is_absolute_url(favicon): logger.info( - f'Using favicon "{favicon}" from an absolute URL, no copy necessary' + f'Using favicon "{favicon}" from an absolute URL, no copy necessary', ) return favicon @@ -292,7 +302,8 @@ def __copy_favicon(self, file_using_favicon_path: Path, favicon: str) -> Path | self.__copy_to_output(favicon_path, favicon_output_path) relative_favicon_path = favicon_output_path.relative_to( - file_using_favicon_path.parent, walk_up=True + file_using_favicon_path.parent, + walk_up=True, ) return relative_favicon_path @@ -314,12 +325,14 @@ def __copy_to_output(self, source_path: Path, destination_path: Path) -> Path: return relative_path def __copy_to_output_relative_to_md_root( - self, source_path: Path, md_root_path: Path + self, + source_path: Path, + md_root_path: Path, ) -> Path | None: source_path = source_path.resolve(strict=True) if not source_path.is_relative_to(md_root_path): logger.warning( - f'"{source_path.absolute()}" is outside the markdown root directory, skipped!"' + f'"{source_path.absolute()}" is outside the markdown root directory, skipped!"', ) return None @@ -343,7 +356,7 @@ def __copy_tree(self, source_path, destination_path) -> None: action = "Overwritten" if overwrite else "Copied" logger.info( - f'{action} directory "{source_path.absolute()}" to "{destination_path.absolute()}"' + f'{action} directory "{source_path.absolute()}" to "{destination_path.absolute()}"', ) def __copy_file(self, source_path, destination_path) -> None: @@ -353,7 +366,7 @@ def __copy_file(self, source_path, destination_path) -> None: action = "Overwritten" if overwrite else "Copied" logger.info( - f'{action} file "{source_path.absolute()}" to "{destination_path.absolute()}"' + f'{action} file "{source_path.absolute()}" to "{destination_path.absolute()}"', ) def __is_absolute_url(self, url: str) -> bool: diff --git a/tests/conftest.py b/tests/conftest.py index b980f86..d0a943d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,7 @@ -import pytest - from pathlib import Path +import pytest + from mkslides_reveal.config import Config from mkslides_reveal.markupgenerator import MarkupGenerator diff --git a/tests/test_base.py b/tests/test_base.py index 8096543..278cbbe 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,9 +1,10 @@ from pathlib import Path +from typing import Any from tests.utils import assert_files_exist, assert_html_contains -def test_process_directory_without_config(setup_markup_generator) -> None: +def test_process_directory_without_config(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator test_files_path = Path("tests/test_files") markup_generator.process_markdown(test_files_path) @@ -51,7 +52,7 @@ def test_process_directory_without_config(setup_markup_generator) -> None: ) -def test_process_file_without_config(setup_markup_generator) -> None: +def test_process_file_without_config(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator test_file_path = Path("tests/test_files/someslides.md") markup_generator.process_markdown(test_file_path) @@ -75,4 +76,6 @@ def test_process_file_without_config(setup_markup_generator) -> None: ], ) - assert not (output_path / "someslides.html").exists(), "someslides.html should not exist" + assert not ( + output_path / "someslides.html" + ).exists(), "someslides.html should not exist" diff --git a/tests/test_index.py b/tests/test_index.py index 8492015..42b795e 100644 --- a/tests/test_index.py +++ b/tests/test_index.py @@ -1,16 +1,17 @@ from pathlib import Path +from typing import Any from tests.utils import assert_html_contains -def test_index_title(setup_markup_generator) -> None: +def test_index_title(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { "index": { "title": "Lorem ipsum", - } - } + }, + }, ) test_files_path = Path("tests/test_files") @@ -19,7 +20,7 @@ def test_index_title(setup_markup_generator) -> None: assert_html_contains( output_path / "index.html", [ - 'Lorem ipsum', - '

Lorem ipsum

', + "Lorem ipsum", + "

Lorem ipsum

", ], ) diff --git a/tests/test_markdown_data_options.py b/tests/test_markdown_data_options.py index 43a3082..aa6de01 100644 --- a/tests/test_markdown_data_options.py +++ b/tests/test_markdown_data_options.py @@ -1,11 +1,11 @@ import re - from pathlib import Path +from typing import Any from tests.utils import assert_html_contains_regexp -def test_revealjs_markdown_data_options(setup_markup_generator) -> None: +def test_revealjs_markdown_data_options(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { @@ -14,8 +14,8 @@ def test_revealjs_markdown_data_options(setup_markup_generator) -> None: "separator": r"^\s*---\s*$", "separator_vertical": r"^\s*-v-\s*$", "separator_notes": r"^Notes?:", - } - } + }, + }, ) test_files_path = Path("tests/test_files") diff --git a/tests/test_plugins.py b/tests/test_plugins.py index 0e205cb..0991ec4 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -1,10 +1,11 @@ -from pathlib import Path import re +from pathlib import Path +from typing import Any from tests.utils import assert_html_contains, assert_html_contains_regexp -def test_plugins(setup_markup_generator) -> None: +def test_plugins(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { @@ -12,16 +13,16 @@ def test_plugins(setup_markup_generator) -> None: { "name": "RevealMermaid", "extra_javascript": [ - "https://cdn.jsdelivr.net/npm/reveal.js-mermaid-plugin/plugin/mermaid/mermaid.min.js" + "https://cdn.jsdelivr.net/npm/reveal.js-mermaid-plugin/plugin/mermaid/mermaid.min.js", ], }, { "extra_javascript": [ - "https://cdn.jsdelivr.net/npm/reveal-plantuml/dist/reveal-plantuml.min.js" - ] + "https://cdn.jsdelivr.net/npm/reveal-plantuml/dist/reveal-plantuml.min.js", + ], }, - ] - } + ], + }, ) test_files_path = Path("tests/test_files") @@ -35,10 +36,6 @@ def test_plugins(setup_markup_generator) -> None: ], ) - with open(output_path / "someslides.html", "r") as file: - contents = file.read() - print(contents) - assert_html_contains_regexp( output_path / "someslides.html", re.compile( diff --git a/tests/test_revealjs_options.py b/tests/test_revealjs_options.py index 0aa4c9b..6ed2e7a 100644 --- a/tests/test_revealjs_options.py +++ b/tests/test_revealjs_options.py @@ -1,10 +1,12 @@ -from pathlib import Path import re +from pathlib import Path +from typing import Any from tests.utils import assert_html_contains, assert_html_contains_regexp + # Necessary for livereload to work properly -def test_revealjs_default_options(setup_markup_generator) -> None: +def test_revealjs_default_options(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator test_files_path = Path("tests/test_files") @@ -18,15 +20,15 @@ def test_revealjs_default_options(setup_markup_generator) -> None: ) -def test_revealjs_integer_options(setup_markup_generator) -> None: +def test_revealjs_integer_options(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { "reveal.js": { "height": 1080, "width": 1920, - } - } + }, + }, ) test_files_path = Path("tests/test_files") @@ -48,23 +50,20 @@ def test_revealjs_integer_options(setup_markup_generator) -> None: ), ) -def test_revealjs_string_options(setup_markup_generator) -> None: + +def test_revealjs_string_options(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { "reveal.js": { "transition": "fade", - } - } + }, + }, ) test_files_path = Path("tests/test_files") markup_generator.process_markdown(test_files_path) - with open(output_path / "someslides.html", "r") as file: - contents = file.read() - print(contents) - assert_html_contains_regexp( output_path / "someslides.html", re.compile( diff --git a/tests/test_themes.py b/tests/test_themes.py index c332617..07ab2e0 100644 --- a/tests/test_themes.py +++ b/tests/test_themes.py @@ -1,17 +1,18 @@ from pathlib import Path +from typing import Any from tests.utils import assert_files_exist, assert_html_contains -def test_local_slideshow_theme_path(setup_markup_generator) -> None: +def test_local_slideshow_theme_path(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { "slides": { "theme": "tests/test_styles/theme.css", "highlight_theme": "tests/test_styles/highlight-theme.css", - } - } + }, + }, ) test_files_path = Path("tests/test_files") @@ -36,15 +37,15 @@ def test_local_slideshow_theme_path(setup_markup_generator) -> None: ) -def test_absolute_url_slideshow_theme_path(setup_markup_generator) -> None: +def test_absolute_url_slideshow_theme_path(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { "slides": { "theme": "https://example.org/theme.css", "highlight_theme": "https://example.org/highlight-theme.css", - } - } + }, + }, ) test_files_path = Path("tests/test_files") @@ -69,15 +70,15 @@ def test_absolute_url_slideshow_theme_path(setup_markup_generator) -> None: ) -def test_builtin_slideshow_theme_path(setup_markup_generator) -> None: +def test_builtin_slideshow_theme_path(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { "slides": { "theme": "simple", "highlight_theme": "vs", - } - } + }, + }, ) test_files_path = Path("tests/test_files") @@ -109,14 +110,14 @@ def test_builtin_slideshow_theme_path(setup_markup_generator) -> None: ) -def test_local_index_theme_path(setup_markup_generator) -> None: +def test_local_index_theme_path(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { "index": { "theme": "tests/test_styles/theme.css", - } - } + }, + }, ) test_files_path = Path("tests/test_files") @@ -130,14 +131,14 @@ def test_local_index_theme_path(setup_markup_generator) -> None: ) -def test_absolute_url_index_theme_path(setup_markup_generator) -> None: +def test_absolute_url_index_theme_path(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { "index": { "theme": "https://example.org/theme.css", - } - } + }, + }, ) test_files_path = Path("tests/test_files") @@ -150,14 +151,15 @@ def test_absolute_url_index_theme_path(setup_markup_generator) -> None: ], ) -def test_absolute_url_index_favicon_path(setup_markup_generator) -> None: + +def test_absolute_url_index_favicon_path(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { "index": { "favicon": "https://hogenttin.github.io/cdn/favicon/favicon.ico", - } - } + }, + }, ) test_files_path = Path("tests/test_files") @@ -170,14 +172,15 @@ def test_absolute_url_index_favicon_path(setup_markup_generator) -> None: ], ) -def test_absolute_url_slideshow_favicon_path(setup_markup_generator) -> None: + +def test_absolute_url_slideshow_favicon_path(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { "slides": { "favicon": "https://hogenttin.github.io/cdn/favicon/favicon.ico", - } - } + }, + }, ) test_files_path = Path("tests/test_files") @@ -197,14 +200,15 @@ def test_absolute_url_slideshow_favicon_path(setup_markup_generator) -> None: ], ) -def test_local_index_favicon_path(setup_markup_generator) -> None: + +def test_local_index_favicon_path(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { "index": { "favicon": "tests/test_styles/favicon.ico", - } - } + }, + }, ) test_files_path = Path("tests/test_files") @@ -217,14 +221,15 @@ def test_local_index_favicon_path(setup_markup_generator) -> None: ], ) -def test_local_slideshow_favicon_path(setup_markup_generator) -> None: + +def test_local_slideshow_favicon_path(setup_markup_generator: Any) -> None: markup_generator, output_path = setup_markup_generator markup_generator.config.merge_config_from_dict( { "slides": { "favicon": "tests/test_styles/favicon.ico", - } - } + }, + }, ) test_files_path = Path("tests/test_files") diff --git a/tests/utils.py b/tests/utils.py index e26ba7e..461ab2c 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,6 +1,5 @@ -import re - from pathlib import Path +from re import Pattern def assert_files_exist(output_path: Path, files: list[str]) -> None: @@ -14,7 +13,8 @@ def assert_html_contains(file_path: Path, expected_content: list[str]) -> None: for substring in expected_content: assert substring in content, f"{substring} not found in {file_path}" -def assert_html_contains_regexp(file_path: Path, regexp: re.Pattern) -> None: + +def assert_html_contains_regexp(file_path: Path, regexp: Pattern[str]) -> None: with file_path.open() as file: content = file.read() assert regexp.search(content), f"{regexp} not found in {file_path}"