pypod

PyPOD is a simple markup language used for embedding documentation in Python scripts.  It is a subset of the Perl Plain-Old-Documentation (POD).

Information and software on this web site are provided under the Granite Mountain Informatics LLC End User License Agreement (EULA).

Send questions or comments to GraniteMountainInformaticsLLC@gmail.com.

"""

=pod

=head1 NAME

pypod.py

=head1 VERSION

202302141500

=head1 SYNOPSIS

python3 pypod.py FileSpecification

=head1 DESCRIPTION

PyPOD is a simple markup language used for embedding documentation in Python scripts.  It is based on Perl Plain-Old-Documentation (POD).

The pypod.py Python program converts PyPOD embedded in a Python script into an HTML document.

=head2 PyPOD Blocks

There can be one or more PyPOD blocks in the Python source code file.  PyPOD blocks start with the "=pod" command and end with the "=cut" command in a Python multiline string block that begins and ends with 3 consecutive double quotes on separate lines.

=head2 Paragraphs

Paragraphs consist of text that starts at the left margin and ends with the end of the line.

=head2 Plain Text

Any paragraph that begins with a space or tab and consists of text that starts at the left margin and ends with the end of the line.

 Plain Text that starts with a space

Plain Text that starts with a tab

=head2 Command Statements


=head2 head commands


The "=head1" through "=head6" command statements produce headings.


=head1 Label Text

=head2 Label Text

=head3 Label Text

=head4 Label Text

=head5 Label Text

=head6 Label Text


=head2 html command


HTML statements can be embedded between "=begin html" and "=end html" statements.


=begin html

<p>This is an embedded HTML paragraph</p>

=end html


=head2 Differences Between Perl POD and Python PyPOD


PyPOD is a subset of Perl POD and only supports the previously specified functionality of Perl POD.


For example, PyPOD does not support Perl POD "Formatting Codes" since embedded HTML can be used for that purpose.

=cut

"""


# ######################################################################

# IMPORT CORE MODULES

# ######################################################################


import datetime

import glob

import os

import re

import sys

import time


print(' '.join(sys.argv))


# ######################################################################

# IMPORT CUSTOM MODULES

# ######################################################################


# ######################################################################

# DECLARE FUNCTIONS

# ######################################################################


"""


nv(n, v)


Prints the string "[DEBUG] name: value.


"""


def nv(n, v):

print(f"[DEBUG] {n}='{v}'")


# ######################################################################

# DECLARE GLOBAL CONSTANTS

# ######################################################################


yyyymmddhhmmss = datetime.datetime.now().strftime("%Y%m%d%H%M%S")

#nv('yyyymmddhhmmss', yyyymmddhhmmss)


# ######################################################################

# DECLARE GLOBAL VARIABLES

# ######################################################################


# ######################################################################

# GET COMMAND LINE ARGUMENTS

# ######################################################################


# get the python file specification

fs = sys.argv[1]

#nv('fs', fs)

if fs == '':

print("FATAL Command line argument 'fs' is not defined")

sys.exit()

if not os.path.exists(fs):

print(f"FATAL Command line argument 'fs' does not exist: {fs}")

sys.exit()


# ######################################################################

# MAIN

# ######################################################################


# get the pod in the input file

pod_list = []

pod_bool = False

with open(fs, 'r') as fh:

for line in fh:

s = line.rstrip()

if re.match('^=pod', s):

#pod_list.append(s)

pod_bool = True

elif re.match('^=cut', s):

#pod_list.append(s)

pod_bool = False

elif pod_bool:

pod_list.append(s)

#nv('pod_list', pod_list)


# convert pod to HTML

html_head_list = []

html_body_list = []

index_list = []

for s in pod_list:

#nv('s', s)

m = re.match('^\s', s)

if m:

html_body_list.append(f"<pre>{s}</pre>")

continue

# get command statements

m = re.match('^=(.+?) (.+?)$', s)

if m:

command = m.group(1)

#nv('command', command)

text = m.group(2)

#nv('text', text)

head_index = 0

m = re.match('^head(.+?)$', command)

if m:

head_index = int(m.group(1))

#nv('head_index', head_index)

index_list.append([head_index, text])

if command == 'head1':

html_body_list.append(f"<h1 id=\"{text}\">{text}</h1>")

elif command == 'head2':

html_body_list.append(f"<h2 id=\"{text}\">{text}</h2>")

elif command == 'head3':

html_body_list.append(f"<h3 id=\"{text}\">{text}</h3>")

elif command == 'head4':

html_body_list.append(f"<h4 id=\"{text}\">{text}</h4>")

elif command == 'head5':

html_body_list.append(f"<h5 id=\"{text}\">{text}</h5>")

elif command == 'head6':

html_body_list.append(f"<h6 id=\"{text}\">{text}</h6>")

elif command == 'begin' and text == 'html':

while True:

m = re.match('^=end\s+html$', s)

if m:

break

html_body_list.append(s)

continue

html_body_list.append(f"<p>{s}</p>")

#nv('html_head_list', html_head_list)

#nv('html_body_list', html_body_list)

#nv('index_list', index_list)


# assemble the HTML index

html_index_list = ['<ul id="index">']

prev_index = 1

for row in index_list:

this_index = row[0]

this_text = row[1]

if this_index > prev_index:

html_index_list.append('<ul>')

prev_index = this_index

elif this_index == prev_index:

html_index_list.append(f"<li><a href=\"#{row[1]}\">{row[1]}</a></li>")

elif this_index < prev_index:

html_index_list.append('</ul>')

prev_index = this_index

html_index_list.append('</ul>')

#nv('html_index_list', html_index_list)


# write HTML to a file

fs_html = os.path.basename(fs) + '.html'

with open(fs_html, 'w', encoding='utf-8') as fh_html:

fh_html.write("<html>\n")

fh_html.write("<head>\n")

for s in html_head_list:

fh_html.write(s + "\n")

fh_html.write("</head>\n")

fh_html.write("<body>\n")

for s in html_index_list:

fh_html.write(s + "\n")

for s in html_body_list:

fh_html.write(s + "\n")

fh_html.write("</body>\n")

fh_html.write("</html>\n")


"""

=pod

=head1 REQUIRES

=head1 INSTALLATION

=head1 SEE ALSO

=head1 AUTHOR

Granite Mountain Informatics LLC

=head1 COPYRIGHT

Copyright 2023 Granite Mountain Informatics LLC

All Rights Reserved

=head1 PROPRIETARY SOFTWARE LICENSE

=head1 CHANGE HISTORY

=head1 TO DO

=cut

"""


The pypod.py utility can be executed using the following commands in a linux shell script:

clear

python3 pypod.py "FileName"

open -a 'Google Chrome' ./FileName.html

Executing the pypod.py utility renders the embedded PyPOD as HTML:

Finally, the function nv(n, v) in the code will print lines like "DEBUG n='v'".  These "debug" lines are commented out in the code.  To view the output uncomment these lines in your version of the code.