From 7b5aa21bc785b49e3f718c15688cee8bf2ee1394 Mon Sep 17 00:00:00 2001 From: Agathe Porte Date: Tue, 3 May 2022 17:05:05 +0200 Subject: feat!: move plugin to top level --- __init__.py | 111 +++++++++++++++++++++++++++++++++++++++++++++++++ dir_attach/__init__.py | 111 ------------------------------------------------- 2 files changed, 111 insertions(+), 111 deletions(-) create mode 100644 __init__.py delete mode 100644 dir_attach/__init__.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..930220c --- /dev/null +++ b/__init__.py @@ -0,0 +1,111 @@ + +"""dir_attach, a Pelican plugin to attach files from a directory named after +restructuredText file names. + +If your file is named ``foobar.rst``, then the following +restructuredText entry: + + .. image:: {dir_attach}example-thumbnail.jpg + :alt: An example image for demonstration. + :target: {dir_attach}example.jpg + +Will automatically be pre-processed by this plugin to become: + + .. image:: {attach}../images/foobar/example-thumbnail.jpg + :alt: An example image for demonstration. + :target: {attach}../images/foobar/example.jpg + +Using ``../images/`` directory instead of ``images/`` is mandatory. This is +because the current Pelican implementation will simplify the path only if the +target directory is not in the same root as the current page. + +If ``images/`` directory was used, then the resulting path in HTML would be: + + foobar/images/foobar/example.jpg + +By using a directory outside of the page's source folder, the generated HTML +path is simplified by Pelican: + + foobar/example.jpg + +""" + +import os +import tempfile +import re + +from pelican import signals +from pelican.readers import RstReader + + +def dirname_from_source_path(source_path): + """Get the dirname to use from the .rst filename. + + >>> dirname_from_source_path("/tmp/foobar.rst") + 'foobar' + + """ + return os.path.splitext(os.path.basename(source_path))[0] + + +def expand_dir_attach(content, dirname): + """Expand the {dir_attach} directives to image {attach} directives. + + >>> src = \ + ".. image:: {dir_attach}example.jpg\\n" \ + " :alt: Example illustration.\\n" \ + " :target: {dir_attach}example.jpg\\n" + >>> expand_dir_attach(src, "foobar") + '.. image:: {attach}../images/foobar/example.jpg\\n\ + :alt: Example illustration.\\n\ + :target: {attach}../images/foobar/example.jpg\\n' + + """ + + dest = f"{{attach}}../images/{dirname}/" + + # We are trying to match only restructuredText directives instead of doing + # a whole content.replace to avoid to replace inside of paragraphs, etc. + regexes = ( + (r"^(.. \w+::) {dir_attach}(.*)$", fr"\1 {dest}\2"), + (r"^(.. _.*:) {dir_attach}(.*)$", fr"\1 {dest}\2"), + (r"^( :\w+:) {dir_attach}(.*)$", fr"\1 {dest}\2"), + ) + + for match, replace in regexes: + content = re.sub(match, replace, content, flags=re.MULTILINE) + + return content + + +class CustomRstReader(RstReader): + """A custom restructuredText reader that will pre-process source first.""" + + enabled = True + file_extensions = ['rst'] + + def read(self, source_path): + """Parses restructured text.""" + dirname = dirname_from_source_path(source_path) + + # Open temporary file in "w" instead of default "w+b" in order to + # use utf-8 by default. + with tempfile.NamedTemporaryFile(mode="w") as tmp: + with open(source_path) as src: + tmp.write(expand_dir_attach(src.read(), dirname)) + + # Force flush to disk before docutils tries to open the file + # in super().read(), elsewise file may be empty. + tmp.flush() + + return super().read(tmp.name) + + +def add_reader(readers): + """Override the .rst reader with our custom reader.""" + readers.reader_classes['rst'] = CustomRstReader + + +def register(): + """Register the plugin to Pelican.""" + signals.readers_init.connect(add_reader) diff --git a/dir_attach/__init__.py b/dir_attach/__init__.py deleted file mode 100644 index 930220c..0000000 --- a/dir_attach/__init__.py +++ /dev/null @@ -1,111 +0,0 @@ - -"""dir_attach, a Pelican plugin to attach files from a directory named after -restructuredText file names. - -If your file is named ``foobar.rst``, then the following -restructuredText entry: - - .. image:: {dir_attach}example-thumbnail.jpg - :alt: An example image for demonstration. - :target: {dir_attach}example.jpg - -Will automatically be pre-processed by this plugin to become: - - .. image:: {attach}../images/foobar/example-thumbnail.jpg - :alt: An example image for demonstration. - :target: {attach}../images/foobar/example.jpg - -Using ``../images/`` directory instead of ``images/`` is mandatory. This is -because the current Pelican implementation will simplify the path only if the -target directory is not in the same root as the current page. - -If ``images/`` directory was used, then the resulting path in HTML would be: - - foobar/images/foobar/example.jpg - -By using a directory outside of the page's source folder, the generated HTML -path is simplified by Pelican: - - foobar/example.jpg - -""" - -import os -import tempfile -import re - -from pelican import signals -from pelican.readers import RstReader - - -def dirname_from_source_path(source_path): - """Get the dirname to use from the .rst filename. - - >>> dirname_from_source_path("/tmp/foobar.rst") - 'foobar' - - """ - return os.path.splitext(os.path.basename(source_path))[0] - - -def expand_dir_attach(content, dirname): - """Expand the {dir_attach} directives to image {attach} directives. - - >>> src = \ - ".. image:: {dir_attach}example.jpg\\n" \ - " :alt: Example illustration.\\n" \ - " :target: {dir_attach}example.jpg\\n" - >>> expand_dir_attach(src, "foobar") - '.. image:: {attach}../images/foobar/example.jpg\\n\ - :alt: Example illustration.\\n\ - :target: {attach}../images/foobar/example.jpg\\n' - - """ - - dest = f"{{attach}}../images/{dirname}/" - - # We are trying to match only restructuredText directives instead of doing - # a whole content.replace to avoid to replace inside of paragraphs, etc. - regexes = ( - (r"^(.. \w+::) {dir_attach}(.*)$", fr"\1 {dest}\2"), - (r"^(.. _.*:) {dir_attach}(.*)$", fr"\1 {dest}\2"), - (r"^( :\w+:) {dir_attach}(.*)$", fr"\1 {dest}\2"), - ) - - for match, replace in regexes: - content = re.sub(match, replace, content, flags=re.MULTILINE) - - return content - - -class CustomRstReader(RstReader): - """A custom restructuredText reader that will pre-process source first.""" - - enabled = True - file_extensions = ['rst'] - - def read(self, source_path): - """Parses restructured text.""" - dirname = dirname_from_source_path(source_path) - - # Open temporary file in "w" instead of default "w+b" in order to - # use utf-8 by default. - with tempfile.NamedTemporaryFile(mode="w") as tmp: - with open(source_path) as src: - tmp.write(expand_dir_attach(src.read(), dirname)) - - # Force flush to disk before docutils tries to open the file - # in super().read(), elsewise file may be empty. - tmp.flush() - - return super().read(tmp.name) - - -def add_reader(readers): - """Override the .rst reader with our custom reader.""" - readers.reader_classes['rst'] = CustomRstReader - - -def register(): - """Register the plugin to Pelican.""" - signals.readers_init.connect(add_reader) -- cgit v1.2.3