#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
*Advanced, Multi-Pass, Front Matter Editing Example*
=======================================================
.. module:: example2
:Program: example2
:Synopsis: Example program that performs the following actions:
#. Derives a class from `EditFrontMatter`
#. Performs execution in a try block
#. raises an exception form the derived class for example purposes
#. catches the exception and prints a messae
#. Sets up a signal handler for `SIGHUP` and `SIGINT` for testing/example
#. Set up a `try` block for catching exceptions: Can be tested by providing \
a nonexistant file name for input
#. Uses a Jinja2 template
.. literalinclude:: ../../../../examples/data/template1.j2
:language: jinja
#. Reads a mardown file that contains yaml front matter via \
:func:`editfrontmatter.EditFrontMatter.EditFrontMatter.readFile`
.. literalinclude:: ../../../../examples/data/example1.md
:language: md
#. Extracts the front matter from the source file
#. Prorammitically edits the front matter via \
:func:`editfrontmatter.EditFrontMatter.EditFrontMatter.run`
#. Concatinates the edited front matter with the original file content via \
:func:`editfrontmatter.EditFrontMatter.EditFrontMatter.dumpFileData`
#. Prints the edited file to `stdout`
#. Resets the Jinja2 template for secondary processing
#. Resets the input file for processing against a new template
.. literalinclude:: ../../../../examples/data/template2.j2
:language: jinja
#. Reprocesses the previous output as input while concatinating the new input file
.. literalinclude:: ../../../../examples/data/example2.md
:language: md
#. Prints the edited output to `stdout`
:Platform: Unix, Windows, |python_version|
:Dependencies:
.. literalinclude:: ../../../../examples/requirements.txt
:language: text
:License: :download:`MIT <../../../../LICENSE>`
.. :moduleauthor: `Karl N. Redman <https://karlredman.github.io>`_
:Author: `Karl N. Redman <https://karlredman.github.io>`_
:homepage: `EditFrontMatter Example 2 <https://karlredman.github.io/EditFrontMatter/examples/example2/readme.html>`_
:Current Release:
version: |release|
.. versionadded:: 0.0.1
Initial Version
"""
import os
import signal
from editfrontmatter import EditFrontMatter
from editfrontmatter import EditFrontMatter_Exception
# setup signal handler for kicks and giggles
[docs]class Signal_Caught(Exception):
pass
[docs]def SignalHandler(sig, frame):
"""Generic Signal handler"""
message = ("Received signal {} on line {} in {}"
.format(str(sig), str(frame.f_lineno), frame.f_code.co_filename))
raise Signal_Caught(message)
# catch signals
signal.signal(signal.SIGINT, SignalHandler)
signal.signal(signal.SIGHUP, SignalHandler)
# Derive class
[docs]class Derived_EditFrontMatter (EditFrontMatter):
"""EditFrontMatter derived class for example purposes"""
[docs] def __init__(self, Superfluous, **kwargs):
"""A specialized signature for the derived class"""
EditFrontMatter.__init__(self, **kwargs)
self.Superfluous = Superfluous
[docs] def canPublish_method(self, var) -> bool:
"""Class level callback method
Note:
It's important that class level callbacks are codded to be reentrant.
If the class is used in a threaded app class level veriables would not
be thread-safe. Also, use critical sections if working with threads.
Returns: a mock value
"""
return "none"
pass
[docs] def run(self, template_str, file_path, **kwargs) -> None:
"""A override method for the baseclass `run` method
This is just a contrived example meant to demonstrate some advanced usage
of the base class.
"""
# update member vars
self.template_str = template_str
self.file_path = file_path
# save file data and yaml object (fmatter) yaml_end point
orig_file_lines = self.file_lines
orig_yaml_obj = self.fmatter
orig_yaml_end = self.yaml_end
# read new (no front matter) file
self.readFile(file_path)
# replace filter with class method
self.del_JinjaFilter('canPublish')
self.add_JinjaFilter('canPublish', self.canPublish_method)
# concatinate orig_file with new file
orig_file_lines.append("\n")
self.file_lines = orig_file_lines + self.file_lines
# replace new yaml obj with original
self.fmatter = orig_yaml_obj
self.keys_toDelete = ['stuff']
# procesess the data
super().run(extraVars_dict={'weight': 10})
# restore yaml_end so we can dump the file with the original end point
# (.i.e so we can dump the new yaml with the old file content starting
# point).
self.yaml_end = orig_yaml_end
[docs] def parent_run(self, extra_vars):
"""cheezy method to call a parent method"""
super().run(extra_vars)
# callback function for jinja filter
[docs]def canPublish_func(var) -> bool:
"""Callback function for Jinja2 filters"""
# ...do processing
return True
[docs]def main():
"""Main function
Attributes:
DATA_PATH (str):
Path that points to the data file directory. Must end with a `/`
file_path1 (str):
Path to input source 1
file_path2 (str):
Path to input source 2
template_str1 (str):
Contents of template1
template_str2 (str):
Contents of template2
:envvar: TEST_DATA_DIR
Variable used to specify the path to the data files.
Returns:
program exit status (0 or 1)
Example:
To run from a non program directory use the environment variable::
TEST_DATA_DIR="./data/" example2/example2.py
"""
# generic path - overridden by env var `TEST_DATA_DIR`
DATA_PATH = "../data/"
if "TEST_DATA_DIR" in os.environ:
DATA_PATH = os.path.abspath(os.environ.get("TEST_DATA_DIR")) + "/"
# set path to input file
file_path1 = os.path.abspath(DATA_PATH + "example1.md")
file_path2 = os.path.abspath(DATA_PATH + "example2.md") # no front matter
# initialize `template_str` with template file content
template_str1 = ''.join(open(os.path.abspath(DATA_PATH + "template1.j2"), "r").readlines())
template_str2 = ''.join(open(os.path.abspath(DATA_PATH + "template2.j2"), "r").readlines())
# create object
proc = Derived_EditFrontMatter(None, template_str=template_str1, do_readFile=False)
# add jinja filter for callback
proc.add_JinjaFilter('canPublish', canPublish_func)
try:
# normal processing
proc.readFile(file_path=file_path1)
proc.parent_run({'toc': 'no effect', 'hasMath': "false",
'addedVariable': ['one', 'two', 'three']})
print(proc.dumpFileData())
print("##################### PASS SEPERATION #######################")
# new swap the template
proc.run(template_str2, file_path2)
print(proc.dumpFileData())
except Signal_Caught as e:
print(str(e))
os.exit(1)
except EditFrontMatter_Exception as e:
print(str(e))
os.exit(1)
else:
print("No Exceptions.")
finally:
print("done.")
print("end program")
if __name__ == '__main__':
main()