From 335a20009d6e5e9b377ea51f70f34ac6e3ec1e90 Mon Sep 17 00:00:00 2001 From: aarons20 Date: Thu, 9 Nov 2023 19:45:30 +0100 Subject: [PATCH] Adding action for publishing to PyPi -[ADDED] GitHub action to publish python package to PyPi -[CHANGED] Formatting with black (PEP 8) --- .github/workflows/pypi_ci.yaml | 52 +++++++++++++ .gitignore | 3 + README.md | 42 ++++++++--- mkdocs_build_plantuml_plugin/plantuml.py | 93 +++++++++++++----------- setup.py | 53 ++++++++------ 5 files changed, 165 insertions(+), 78 deletions(-) create mode 100644 .github/workflows/pypi_ci.yaml diff --git a/.github/workflows/pypi_ci.yaml b/.github/workflows/pypi_ci.yaml new file mode 100644 index 0000000..2be8630 --- /dev/null +++ b/.github/workflows/pypi_ci.yaml @@ -0,0 +1,52 @@ +name: Publish python package to PyPi +on: + push: + branches: + - master + - main + +permissions: + contents: write + +jobs: + build-python-package: + name: Build distribution packages + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: 3.x + - name: Install dependencies and build distribution packages + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + python setup.py sdist bdist_wheel + twine check dist/* + - name: Store the distribution packages + uses: actions/upload-artifact@v3 + with: + name: python-package-distributions + path: dist/ + + publish-to-pypi: + name: Publish Python distribution package to PyPI + if: ${{ github.repository == 'quantorconsulting/mkdocs_build_plantuml' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') }} + needs: + - build-python-package + runs-on: ubuntu-latest + environment: + name: pipy + url: https://pypi.org/p/mkdocs-build-plantuml-plugin + permissions: + id-token: write + + steps: + - name: Download all the dists + uses: actions/download-artifact@v3 + with: + name: python-package-distributions + path: dist/ + - name: Publish distribution packages to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.gitignore b/.gitignore index 69150a4..838355a 100644 --- a/.gitignore +++ b/.gitignore @@ -90,3 +90,6 @@ ENV/ # Vs Code .vscode/ + +# Python virtual environments +.venv diff --git a/README.md b/README.md index 132cbb5..460089a 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,23 @@ # MkDocs-Build-Plantuml-Plugin -This plugin builds your Plantuml image files with `mkdocs serve` automatically. +## Table of Contents -My intend was, that I do not like inline diagrams and stumbled upon issues like non-working `!includes`. +- [About the Project](#about-the-project) +- [Prerequisites](#prerequisites) +- [Installation](#installation) +- [Usage](#usage) +- [Dark Mode Support](#dark-mode-support) +- [Known restrictions](#known-restrictions) +- [Contributing](#contributing) -**Note**: if you want inline diagrams in your Markdown files like +## About the Project + +This plugin automates the generation of PlantUML image files when using `mkdocs serve`. + +The motivation behind this plugin is to provide a solution for users who prefer not to use inline diagrams and have encountered challenges with non-functional !includes. + +**Note**: If you want inline diagrams in your Markdown files ````markdown ```plantuml @@ -14,23 +26,25 @@ Alice -> Bob ``` ```` -this is plugin is _not_ the right one. Please check out [plantuml-markdown](https://github.com/mikitex70/plantuml-markdown) which does exactly that. +this plugin does _not_ meet your requirements. Please check out [plantuml-markdown](https://github.com/mikitex70/plantuml-markdown) which does exactly that. ## Prerequisites -You need to have installed +You need to have installed: - Python3 - [MkDocs](https://www.mkdocs.org) -- Java for Plantuml (if running locally) +- Java for Plantuml (If running locally) - [Plantuml](https://plantuml.com) (if running locally) - This plugin (needs httplib2 for server rendering) -On OSX you can install plantuml with homebrew which puts a plantuml executable in `/usr/local/bin/plantuml`. +On macOS you can install plantuml with homebrew which puts a plantuml executable in `/usr/local/bin/plantuml`. ## Installation -`pip3 install mkdocs-build-plantuml-plugin` +```shell +pip3 install mkdocs-build-plantuml-plugin +``` ## Usage @@ -93,11 +107,11 @@ Inside your `index.md` or any other Markdown file you can then reference any cre ![file1](diagrams/out/subdir1/file1.svg) ``` -## Dark Mode Support with >=1.4 (prefers-color-scheme) +## Dark Mode Support -Since Version 1.4 this plugin can support dark mode when rendering with `server`. +Since Version 1.4 this plugin can support dark mode when rendering with `server` (prefers-color-scheme). -**Note: Not in local mode, only server rendering mode** +**Note**: Not in local mode, only server rendering mode 1. Grab a general (ie. for [Material Theme](https://squidfunk.github.io/mkdocs-material/)) dark mode support css file (i.e. from [henrywhitaker3/mkdocs-material-dark-theme](https://github.com/henrywhitaker3/mkdocs-material-dark-theme)) for your theme 1. Enable theme support in this plugin: @@ -122,5 +136,9 @@ You can find an example in the [example folder](./example/) ## Known restrictions -- If you use `!include`s and the `render: "server"` option, this plugin merges those files manually. If there are any issues or side effects because of that, please open a ticket. +- If you use `!include` and the `render: "server"` option, this plugin merges those files manually. If there are any issues or side effects because of that, please open a ticket. - Dark mode / theme support is currently only available in server rendering mode. + +## Contributing + +Contributions are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request. diff --git a/mkdocs_build_plantuml_plugin/plantuml.py b/mkdocs_build_plantuml_plugin/plantuml.py index 0129c9f..56b88e6 100644 --- a/mkdocs_build_plantuml_plugin/plantuml.py +++ b/mkdocs_build_plantuml_plugin/plantuml.py @@ -21,8 +21,7 @@ plantuml_alphabet = ( string.digits + string.ascii_uppercase + string.ascii_lowercase + "-_" ) -base64_alphabet = string.ascii_uppercase + \ - string.ascii_lowercase + string.digits + "+/" +base64_alphabet = string.ascii_uppercase + string.ascii_lowercase + string.digits + "+/" b64_to_plantuml = maketrans( base64_alphabet.encode("utf-8"), plantuml_alphabet.encode("utf-8") ) @@ -30,8 +29,12 @@ class BuildPlantumlPluginConfig(base.Config): render = mkdocs.config.config_options.Type(str, default="server") - server = mkdocs.config.config_options.Type(str, default="http://www.plantuml.com/plantuml") - disable_ssl_certificate_validation = mkdocs.config.config_options.Type(bool, default=False) + server = mkdocs.config.config_options.Type( + str, default="http://www.plantuml.com/plantuml" + ) + disable_ssl_certificate_validation = mkdocs.config.config_options.Type( + bool, default=False + ) bin_path = mkdocs.config.config_options.Type(str, default="/usr/local/bin/plantuml") output_format = mkdocs.config.config_options.Type(str, default="png") allow_multiple_roots = mkdocs.config.config_options.Type(bool, default=False) @@ -47,13 +50,13 @@ class BuildPlantumlPluginConfig(base.Config): class BuildPlantumlPlugin(BasePlugin[BuildPlantumlPluginConfig]): - """ main plugin entry point """ + """main plugin entry point""" def __init__(self): self.total_time = 0 def on_pre_build(self, config): - """ Checking given parameters and looking for files """ + """Checking given parameters and looking for files""" diagram_roots = [] @@ -77,7 +80,11 @@ def on_pre_build(self, config): diagram.out_dir = self._get_out_directory(root, subdir) # Handle to read source file - with open(os.path.join(diagram.directory, diagram.file), "r", encoding="utf-8") as f: + with open( + os.path.join(diagram.directory, diagram.file), + "r", + encoding="utf-8", + ) as f: diagram.src_file = f.readlines() # Search for start (@startuml ) @@ -107,8 +114,14 @@ def on_pre_build(self, config): def _make_diagram_root(self, subdir): diagram_root = DiagramRoot() diagram_root.root_dir = os.path.join(os.getcwd(), subdir) - diagram_root.src_dir = os.path.join(os.getcwd(), subdir, self.config["input_folder"]) - print("root dir: {}, src dir: {}".format(diagram_root.root_dir, diagram_root.src_dir)) + diagram_root.src_dir = os.path.join( + os.getcwd(), subdir, self.config["input_folder"] + ) + print( + "root dir: {}, src dir: {}".format( + diagram_root.root_dir, diagram_root.src_dir + ) + ) return diagram_root def _get_out_directory(self, root, subdir): @@ -135,17 +148,15 @@ def _search_start_tag(self, diagram): ws = line.find(" ") if ws > 0: # we look for which starts after a whitespace - out_filename = line[ws + 1:] + out_filename = line[ws + 1 :] diagram.out_file = os.path.join( diagram.out_dir, - out_filename + "." + - self.config["output_format"], + out_filename + "." + self.config["output_format"], ) if self.config["theme_enabled"]: diagram.out_file_dark = os.path.join( diagram.out_dir, - out_filename + "_dark." + - self.config["output_format"], + out_filename + "_dark." + self.config["output_format"], ) return True return False @@ -203,19 +214,19 @@ def _readFileRecursively(self, lines, temp_file, diagram, directory, dark_mode): return temp_file def _readIncludeLine(self, diagram, line, temp_file, directory, dark_mode): - """ Handles the different include types like !includeurl, !include and !includesub """ - # If includeurl is found, we do not have to do anything here. + """Handles the different include types like !includeurl, !include and !includesub""" + # If includeurl is found, we do not have to do anything here. # Server can handle that if re.match(r"^!includeurl\s+\S+\s*$", line): temp_file += line - + elif re.match(r"^!includesub\s+\S+\s*$", line): # on the eleventh position starts the inluded file - parts = line[11:].strip().split('!') + parts = line[11:].strip().split("!") if len(parts) == 2: inc_file = parts[0] # Extract the file path sub_name = parts[1] # Extract the sub name after the '!' - + if dark_mode: inc_file = inc_file.replace( self.config["theme_light"], self.config["theme_dark"] @@ -239,8 +250,10 @@ def _readIncludeLine(self, diagram, line, temp_file, directory, dark_mode): print("Could not find included file" + str(e1) + str(e2)) raise e2 else: - raise Exception("Invalid !includesub syntax. Expected: !includesub !") - + raise Exception( + "Invalid !includesub syntax. Expected: !includesub !" + ) + elif re.match(r"^!include\s+\S+\s*$", line): # on the ninth position starts the filename inc_file = line[9:].rstrip() @@ -274,11 +287,11 @@ def _readIncludeLine(self, diagram, line, temp_file, directory, dark_mode): print("Could not find include " + str(e1) + str(e2)) raise e2 else: - raise Exception("Unnown include type: " + line) + raise Exception("Unknown include type: " + line) return temp_file def _read_incl_line_file(self, diagram, temp_file, dark_mode, inc_file_abs): - """ Save the mtime of the inc file to compare """ + """Save the mtime of the inc file to compare""" try: local_inc_time = os.path.getmtime(inc_file_abs) except Exception as _: @@ -297,9 +310,9 @@ def _read_incl_line_file(self, diagram, temp_file, dark_mode, inc_file_abs): ) return temp_file - + def _read_incl_sub(self, diagram, temp_file, dark_mode, inc_file_abs, inc_sub_name): - """ Handle !includesub statements """ + """Handle !includesub statements""" # Save the mtime of the inc file to compare try: local_inc_time = os.path.getmtime(inc_file_abs) @@ -308,7 +321,7 @@ def _read_incl_sub(self, diagram, temp_file, dark_mode, inc_file_abs, inc_sub_na if local_inc_time > diagram.inc_time: diagram.inc_time = local_inc_time - + temp_sub = [] add_following = False with open(inc_file_abs, "r") as inc: @@ -320,9 +333,9 @@ def _read_incl_sub(self, diagram, temp_file, dark_mode, inc_file_abs, inc_sub_na add_following = False elif add_following: temp_sub.append(line) - + temp_file = self._readFileRecursively( - temp_sub, # Do only use the subs for further recursion + temp_sub, # Do only use the subs for further recursion temp_file, diagram, os.path.dirname(os.path.realpath(inc_file_abs)), @@ -339,24 +352,20 @@ def _build_out_filename(self, diagram): ) if self.config["theme_enabled"]: diagram.out_file_dark = ( - diagram.file[:out_index] + "_dark." + - self.config["output_format"] + diagram.file[:out_index] + "_dark." + self.config["output_format"] ) diagram.out_file = os.path.join(diagram.out_dir, diagram.out_file) if self.config["theme_enabled"]: - diagram.out_file_dark = os.path.join( - diagram.out_dir, diagram.out_file_dark) + diagram.out_file_dark = os.path.join(diagram.out_dir, diagram.out_file_dark) return diagram def _convert(self, diagram, dark_mode=False): - if not dark_mode: if (diagram.img_time < diagram.src_time) or ( diagram.inc_time > diagram.img_time ): - print("Converting " + os.path.join(diagram.directory, diagram.file)) if self.config["render"] == "local": command = self.config["bin_path"].rsplit() @@ -385,7 +394,6 @@ def _convert(self, diagram, dark_mode=False): self._call_server(diagram, diagram.out_file_dark) def _call_server(self, diagram, out_file): - http = httplib2.Http({}) if self.config["disable_ssl_certificate_validation"]: @@ -403,14 +411,13 @@ def _call_server(self, diagram, out_file): response, content = http.request(url) if response.status != 200: print( - "Wrong response status for " + - diagram.file + ": " + str(response.status) + "Wrong response status for " + + diagram.file + + ": " + + str(response.status) ) except Exception as error: - print( - "Server error while processing " - + diagram.file + ": " + str(error) - ) + print("Server error while processing " + diagram.file + ": " + str(error)) raise error else: if not os.path.exists(os.path.join(diagram.out_dir)): @@ -431,7 +438,7 @@ def _file_matches_extension(self, file): class PuElement: - """ plantuml helper object """ + """plantuml helper object""" def __init__(self, file, subdir): self.file = file @@ -450,7 +457,7 @@ def __init__(self, file, subdir): class DiagramRoot: - """ object containing the src and out directories per diagram root """ + """object containing the src and out directories per diagram root""" def __init__(self): self.root_dir = "" diff --git a/setup.py b/setup.py index 84dac15..157ddec 100644 --- a/setup.py +++ b/setup.py @@ -1,32 +1,39 @@ +import io +import os + from setuptools import setup, find_packages +with open("README.md", "r") as f: + long_description = f.read() + + setup( - name='mkdocs-build-plantuml-plugin', - version='1.9.0', - description='An MkDocs plugin to call plantuml locally or remote', - long_description='', - keywords='mkdocs plantuml publishing documentation uml sequence diagram', - url='https://github.com/christo-ph/mkdocs_build_plantuml', - author='Christoph Galler', - author_email='galler@quantor.consulting', - license='MIT', - python_requires='>=3.2', - install_requires=[ - 'mkdocs>=1.0.4', 'httplib2' - ], + name="mkdocs-build-plantuml-plugin", + version="1.9.0", + description="An MkDocs plugin to call plantuml locally or remote", + long_description=long_description, + long_description_content_type="text/markdown", + keywords="mkdocs plantuml publishing documentation uml sequence diagram", + url="https://github.com/christo-ph/mkdocs_build_plantuml", + author="Christoph Galler", + author_email="galler@quantor.consulting", + license="MIT", + python_requires=">=3.2", + install_requires=["mkdocs>=1.0.4", "httplib2"], classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: Information Technology', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3 :: Only', + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: Information Technology", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", ], packages=find_packages( - exclude=["*.tests", "*.tests.*", "tests.*", "tests", "example"]), + exclude=["*.tests", "*.tests.*", "tests.*", "tests", "example"] + ), entry_points={ - 'mkdocs.plugins': [ - 'build_plantuml = mkdocs_build_plantuml_plugin.plantuml:BuildPlantumlPlugin' + "mkdocs.plugins": [ + "build_plantuml = mkdocs_build_plantuml_plugin.plantuml:BuildPlantumlPlugin" ] - } + }, )