see CHANGELOG 2018-09-16
authorSabine Engelhardt (Becker) <frosch@atari-frosch.de>
Sun, 16 Sep 2018 22:10:17 +0000 (00:10 +0200)
committerSabine Engelhardt (Becker) <frosch@atari-frosch.de>
Sun, 16 Sep 2018 22:10:17 +0000 (00:10 +0200)
CHANGELOG
ToDo
makesite.py
preparesite.py
sites/atarifrosch/DEFAULTS/settings.py

index d1fd119..db242c9 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,26 @@
+2018-09-16 frosch@atari-frosch.de
+
+    * preparesite.py: TIL that if a variable is not available in an imported
+      module and I try: for it, I should ask for AttributeError not
+      NameError in the except statement in order to avoid the interpreter to
+      grumble about it. Thx to <penma@chaosdorf.de> for pointing me to
+      <https://stackoverflow.com/questions/11921705/what-is-the-difference-between-nameerror-and-attributeerror-in-python>
+
+    * preparesite.py: Fixed the function makesetting, lots of line ends were
+      missing in the output, and some quotation marks were used the wrong
+      way.
+
+    * preparesite.py: Logging fixed.
+
+    * makesite.py: Does not work at this time, because the functions
+      makehtmlhead and makefoot are no more in the settings.py
+      automatically. They are to be moved directly into makesite.py.
+
+    * makesite.py: Created an /html folder inside the /sites/$site folder
+      because of a wrong path setting. Fixed.
+
+
+
 2018-09-15 frosch@atari-frosch.de
 
     * preparesite.py: All necessary variables and values are now imported
diff --git a/ToDo b/ToDo
index da484ff..55788c5 100644 (file)
--- a/ToDo
+++ b/ToDo
@@ -11,14 +11,6 @@ in general:
 
 preparesite.py:
 
-* LASTERROR:
-  frosch@seerose:~/prog/htmlglue$ ./preparesite.py atarifrosch
-  Traceback (most recent call last):
-    File "./preparesite.py", line 238, in <module>
-      flt.oldenc
-  AttributeError: 'module' object has no attribute 'oldenc'
-  – of course not. That's why I use try: in the line above …
-
 
 makesite.py:
 
index 0e855ee..8c1797f 100755 (executable)
@@ -209,7 +209,10 @@ else:
 targetdir = mypath + "/html/" + sitename + "/"
 if not os.path.exists(mypath + "/html"):
     os.mkdir(mypath + "/html")
-
+    os.mkdir(targetdir)
+else:
+    if not os.path.exists(targetdir):
+        os.mkdir(targetdir)
 
 # logging configuration
 
@@ -227,18 +230,18 @@ except NameError:
 else:
     loglevel = settings.makeloglevel
 
-logformat = "%(asctime)s %(levelname)s %(message)s"
-
+logformat = " %(levelname)s %(message)s"
+dateformat = "%Y-%m-%d %H:%M:%S"
 if loglevel == 5:
-    logging.basicConfig(format=logformat, filename=logfile, level=logging.DEBUG)
+    logging.basicConfig(format=logformat, datefmt=dateformat, filename=logfile, level=logging.DEBUG)
 elif loglevel == 4:
-    logging.basicConfig(format=logformat, filename=logfile, level=logging.INFO)
+    logging.basicConfig(format=logformat, datefmt=dateformat, filename=logfile, level=logging.INFO)
 elif loglevel == 3:
-    logging.basicConfig(format=logformat, filename=logfile, level=logging.WARNING)
+    logging.basicConfig(format=logformat, datefmt=dateformat, filename=logfile, level=logging.WARNING)
 elif loglevel == 2:
-    logging.basicConfig(format=logformat, filename=logfile, level=logging.ERROR)
+    logging.basicConfig(format=logformat, datefmt=dateformat, filename=logfile, level=logging.ERROR)
 elif loglevel == 1:
-    logging.basicConfig(format=logformat, filename=logfile, level=logging.CRITICAL)
+    logging.basicConfig(format=logformat, datefmt=dateformat, filename=logfile, level=logging.CRITICAL)
 
 logging.debug('Opened log file.')
 
@@ -261,12 +264,6 @@ if not os.path.exists(sitepath + "menu.py"):
     logging.critical('menu config file for the site does not exist.  Stop.')
     sys.exit()
 
-if not os.path.exists(sitepath + "html/"):
-    logging.info('HTML directory does not exist, creating it ...')
-    os.mkdir(sitepath + "html/")
-else:
-    logging.debug('HTML directory found.')
-
 # Now we can start.
 
 # In this early version the whole site will be created every time the script
index bdc6565..910687d 100755 (executable)
@@ -30,6 +30,8 @@ def checkfolder(curpath):
     return igndir
 
 def makesetting(settingsfile, flt):
+    ln = "\n"
+    qln = '"\n'
     if os.path.exists(settingsfile):
         if flt.forcemakesettings:
             os.remove(settingsfile)
@@ -41,101 +43,100 @@ def makesetting(settingsfile, flt):
     set = open(settingsfile, "w")
     logging.debug("Opened new settings file.")
 
-    set.write("#!usr/bin/env python3")
-    set.write("# -*- coding: utf8 -*-\n")
-    ln = "\n"
+    set.write("#!usr/bin/env python3" + ln)
+    set.write("# -*- coding: utf8 -*-" + ln + ln + ln)
 
-    set.write("# Folder name for the site")
-    set.write('sitename = ' + flt.sitename + ln)
+    set.write("# Folder name for the site" + ln)
+    set.write('sitename = "' + flt.sitename + qln + ln)
 
-    set.write("# File path for this site; content files with page.py files, menu.py files,")
-    set.write("# folders DEFAULTS, SNIPPETS, and CSS will be stored here.")
-    set.write("sitepath = " + flt.targetpath + ln)
+    set.write("# File path for this site; content files with page.py files, menu.py files," + ln)
+    set.write("# folders DEFAULTS, SNIPPETS, and CSS will be stored here." + ln)
+    set.write('sitepath = "' + flt.targetpath + qln + ln)
 
-    set.write("# Standard protocol of the site (one out of http, https)")
-    set.write('proto = "https"' + ln)
+    set.write("# Standard protocol of the site (one out of http, https)" + ln)
+    set.write('proto = "https"' + ln + ln)
 
-    set.write("# domain name of the site")
-    set.write('domain = ' + flt.domain + ln)
+    set.write("# domain name of the site" + ln)
+    set.write('domain = "' + flt.domain + qln + ln)
 
-    set.write("# URL of the site. Change this line ONLY if you know what you're doing!")
-    set.write('myurl = proto + "://" + domain + "/"' + ln)
+    set.write("# URL of the site. Change this line ONLY if you know what you're doing!" + ln)
+    set.write('myurl = proto + "://" + domain + "/"' + ln + ln)
 
-    set.write("# Logging is always good. But we need a name for the logfile (optional with")
-    set.write("# a path), and a log level.")
-    set.write("# Loglevels:")
-    set.write("# 1 = critical messages only")
-    set.write("# 2 = critical, and error messages")
-    set.write("# 3 = critical, error, and warning messages")
-    set.write("# 4 = critical, error, warning, and info messages")
-    set.write("# 5 = critical, error, warning, info, and debug messages (very verbose!)")
-    set.write('makelogfile = "mysite.log"')
-    set.write('makeloglevel = 4' + ln)
+    set.write("# Logging is always good. But we need a name for the logfile (optional with" + ln)
+    set.write("# a path), and a log level." + ln)
+    set.write("# Loglevels:" + ln)
+    set.write("# 1 = critical messages only" + ln)
+    set.write("# 2 = critical, and error messages" + ln)
+    set.write("# 3 = critical, error, and warning messages" + ln)
+    set.write("# 4 = critical, error, warning, and info messages" + ln)
+    set.write("# 5 = critical, error, warning, info, and debug messages (very verbose!)" + ln)
+    set.write('makelogfile = "mysite.log"' + ln)
+    set.write('makeloglevel = 4' + ln + ln)
 
     if flt.ownhtmlhead:
         logging.debug("Own function for <head> section is set.")
         if os.path.exists(flt.headfunc):
-            set.write("# Name of your own function for creating the <head> section of each page")
-            set.write('makehtmlhead = ' + flt.headfunc + ln)
+            set.write("# Name of your own function for creating the <head> section of each page" + ln)
+            set.write('makehtmlhead = "' + flt.headfunc + qln + ln)
         else:
             logging.warning("ownhtmlhead is True, but according function not found.")
     if flt.ownpagefoot:
         logging.debug("Own page foot function is set.")
         if os.path.exists(flt.footfunc):
-            set.write("# Name of your own function for creating the standard page foot")
-            set.write("makefoot = " + flt.pagefoot + ln)
+            set.write("# Name of your own function for creating the standard page foot" + ln)
+            set.write('makefoot = "' + flt.pagefoot + qln + ln)
         else:
             logging.warning("ownpagefoot is True, but according function not found.")
             
     set.write("## Standard settings for the <head> section of each page" + ln)
-    set.write("# These settings can be overwritten in each page.py")
-    set.write('language = ' + flt.language)
-    set.write("# language will also be used for DC.Language")
-    set.write('doctype = ' + flt.doctype)
-    set.write('htmlver = ' + flt.htmlver)
-    set.write('title = ' + flt.title)
-    set.write("# title will also be used for DC.Title if dctitle is not set")
-    set.write('description = ' + flt.description)
-    set.write("# description will also be used for DC.Description if dcdescription is not set")
-    set.write('robots = ' + flt.robots)
-    set.write('author = ' + flt.author)
-    set.write('# dctitle = ' + flt.title)
-    set.write('dccreator = ' + flt.dccreator)
-    set.write('dcpublisher = ' + flt.dcpublisher)
-    set.write('dcrights = ' + flt.dcrights)
-    set.write('dccoverage = ""' + ln)
-
-    set.write('favicon = ' + flt.favicon)
-    set.write('stylesheet = ' + flt.stylesheet)
-    set.write('stylesheetmedia = ' + flt.stylesheetmedia + ln)
-
-    set.write("# Position of menu: above or below content. Be reminded that this is")
-    set.write("# only the menu's position in the HTML code; where it will really be placed")
-    set.write("# within the graphical rendered page depends on your stylesheet.")
-    set.write('menupos = ' + flt.menupos + ln)
-
-    set.write("# These files, which are placed in the SNIPPETS folder in sitepath, are")
-    set.write("# usually needed in order to complete the pages. They can contain keywords")
-    set.write("# ([KEYWORD]) which are recognized by makesite.py, functions in a page.py,")
-    set.write("# or additional functions in this settings.py.")
-    set.write('snippets = {}')
-    set.write('snippets["htmlhead"] = ' + flt.snippets["htmlhead"])
-    set.write('snippets["bodytopfile"] = ' + flt.snippets["bodytopfile"])
-    set.write('snippets["logofile"] = ' + flt.snippets["logofile"])
-    set.write('snippets["menustart"] = ' + flt.snippets["menustart"])
-    set.write('snippets["menuend"] = ' + flt.snippets["menuend"])
-    set.write('snippets["endoffile"] = ' + flt.snippets["endoffile"] + ln)
-
-    set.write("# The variable addtobody is of type dict and is set here in order to be")
-    set.write("# extended in page.py files. It can be used to add htm snippets, variables,")
-    set.write("# values, and even the return of a function into the content of a page.")
-    set.write('addtobody = {}')
-    set.write('# Example with snippet: addtobody["[AKVSBODY]"] = "akvsbody.htm"')
-    set.write('# Example with variable: addtobody["[MYURI]"] = myuri')
-    set.write('# Example with value: addtobody["[APPLES]"] = 4')
-    set.write('# Example with function: addtobody["[TODAY]"] = datetime.now().strftime("%Y-%m-%d")' + ln)
-
-    set.write("## EOF")
+    set.write("# These settings can be overwritten in each page.py" + ln)
+    set.write('language = "' + flt.language + qln)
+    set.write("# language will also be used for DC.Language" + ln)
+    set.write("doctype = '" + flt.doctype + "'" + ln)
+    set.write('htmlver = "' + flt.htmlver + "'" + ln)
+    set.write('title = "' + flt.title + qln)
+    set.write("# title will also be used for DC.Title if dctitle is not set" + ln)
+    set.write('description = "' + flt.description + qln)
+    set.write("# description will also be used for DC.Description if dcdescription is not set" + ln)
+    set.write('robots = "' + flt.robots + qln)
+    set.write('author = "' + flt.author + qln)
+    set.write('# dctitle = "' + flt.title + qln)
+    set.write('dccreator = "' + flt.dccreator + qln)
+    set.write('dcpublisher = "' + flt.dcpublisher + qln)
+    set.write('dcrights = "' + flt.dcrights + qln)
+    set.write('dccoverage = ""' + ln + ln)
+
+    set.write('favicon = "' + flt.favicon + qln)
+    set.write('stylesheet = "' + flt.stylesheet + qln)
+    set.write('stylesheetmedia = "' + flt.stylesheetmedia + qln + ln)
+
+    set.write("# Position of menu: above or below content. Be reminded that this is" + ln)
+    set.write("# only the menu's position in the HTML code; where it will really be placed" + ln)
+    set.write("# within the graphical rendered page depends on your stylesheet." + ln)
+    set.write('menupos = "' + flt.menupos + qln + ln)
+
+    set.write("# These files, which are placed in the SNIPPETS folder in sitepath, are" + ln)
+    set.write("# usually needed in order to complete the pages. They can contain keywords" + ln)
+    set.write("# ([KEYWORD]) which are recognized by makesite.py, functions in a page.py," + ln)
+    set.write("# or additional functions in this settings.py." + ln)
+    set.write('snippets = {}' + ln)
+    set.write('snippets["htmlhead"] = "' + flt.snippets["htmlhead"] + qln)
+    set.write('snippets["bodytopfile"] = "' + flt.snippets["bodytopfile"] + qln)
+    set.write('snippets["logofile"] = "' + flt.snippets["logofile"] + qln)
+    set.write('snippets["menustart"] = "' + flt.snippets["menustart"] + qln)
+    set.write('snippets["menuend"] = "' + flt.snippets["menuend"] + qln)
+    set.write('snippets["endoffile"] = "' + flt.snippets["endoffile"] + qln + ln)
+
+    set.write("# The variable addtobody is of type dict and is set here in order to be" + ln)
+    set.write("# extended in page.py files. It can be used to add htm snippets, variables," + ln)
+    set.write("# values, and even the return of a function into the content of a page." + ln)
+    set.write('addtobody = {}' + ln)
+    set.write('# Example with snippet: addtobody["[AKVSBODY]"] = "akvsbody.htm"' + ln)
+    set.write('# Example with variable: addtobody["[MYURI]"] = myuri' + ln)
+    set.write('# Example with value: addtobody["[APPLES]"] = 4' + ln)
+    set.write('# Example with function: addtobody["[TODAY]"] = datetime.now().strftime("%Y-%m-%d")' + ln + ln)
+
+    set.write("## EOF" + ln)
     set.close()
 
 
@@ -167,8 +168,6 @@ except NameError:
     logfile = sitename + ".log"
 else:
     logfile = flt.logfile
-if not os.path.exists(logfile):
-    logfile = mypath + "/prepare-" + sitename + ".log"
 
 try:
     flt.loglevel
@@ -177,11 +176,10 @@ except NameError:
 else:
     loglevel = flt.loglevel
 
-logformat = "%(asctime)s %(message)s"
+logformat = "%(levelname)s %(message)s"
 dateformat = "%Y-%m-%d %H:%M:%S"
 if loglevel == 5:
     logging.basicConfig(format=logformat, datefmt=dateformat, filename=logfile, level=logging.DEBUG)
-    logging.debug('Logfile opened with level DEBUG.')
 elif loglevel == 4:
     logging.basicConfig(format=logformat, datefmt=dateformat, filename=logfile, level=logging.INFO)
 elif loglevel == 3:
@@ -194,6 +192,7 @@ else:
     logging.basicConfig(format='%(asctime)s %(message)s', datefmt=dateformat, filename=logfile,level=logging.INFO)
     logging.error('could not determine loglevel, using INFO as default')
 
+logging.debug("Opened logfile.")
 defaultsdir = targetpath + "/DEFAULTS/"
 snippetspath = targetpath + "/SNIPPETS/"
 cssdir = targetpath + "/CSS"
@@ -236,7 +235,7 @@ makesetting(settingsfile, flt)
 
 try:
     flt.oldenc
-except NameError:
+except AttributeError:
     isoldenc = False
 else:
     isoldenc = True
@@ -302,6 +301,7 @@ for dirpath, dirs, files in os.walk(origpath):
                          curfile = tmpfile
 
                 htmlfile = open(curfile, "rt")
+                print(curfile)
                 logging.debug('Successfully opened <%s> for processing.', curfile)
                 html = htmlfile.read()
                 htmlfile.close()
@@ -386,7 +386,7 @@ for dirpath, dirs, files in os.walk(origpath):
                     if flt.contentstart in curline:
                         logging.debug('Found start of content part.')
                         contentread = True
-                        htm.write(curline + ln)
+                        htm.write(curline + "\n")
                         continue
 
                     if curline.startswith('<DOCTYPE'):
@@ -406,7 +406,7 @@ for dirpath, dirs, files in os.walk(origpath):
                         lineparts = curline.split("<title>")
                         title = lineparts[1].replace("</title>", "")
                         title = title.strip()
-                        if title != settings.title:
+                        if title != flt.title:
                             outline = 'title = "' + title + lns
                             pyfile.write(outline)
 
@@ -418,10 +418,10 @@ for dirpath, dirs, files in os.walk(origpath):
                         contentpart = contentpart.replace('"', '')
                         contentpart = contentpart.strip()
                         if 'name="robots"' in curline:
-                            if contentpart != settings.robots:
+                            if contentpart != flt.robots:
                                 pyfile.write('robots = "' + contentpart + lns)
                             else:
-                                pyfile.write('robots = "' + setting.robots + lns)
+                                pyfile.write('robots = "' + flt.robots + lns)
                         elif 'http-equiv="content-language"' in curline:
                             if contentpart != flt.language:
                                 pyfile.write("contentlanguage = '" + contentpart + ln)
@@ -554,7 +554,8 @@ for dirpath, dirs, files in os.walk(origpath):
                     menu.close()
                     call(["/bin/chmod", "755", menufile])
                     logging.debug('Successfully created menu.py for <%s>.', curpath)
-                    if newenc:
+                    if os.path.exists(tmpfile):
                         os.remove(tmpfile)
                         logging.debug('Deleted temporary source file <%s>.', tmpfile)
-                
\ No newline at end of file
+
+print("Don't forget to edit settings.py and to create the contents in the files inside the SNIPPETS folder!")
index ed80cc0..5743355 100644 (file)
@@ -1,14 +1,80 @@
-#!usr/bin/env python3# -*- coding: utf8 -*-
-# Folder name for the sitesitename = atarifrosch
-# File path for this site; content files with page.py files, menu.py files,# folders DEFAULTS, SNIPPETS, and CSS will be stored here.sitepath = /home/frosch/prog/htmlglue/sites/atarifrosch/
-# Standard protocol of the site (one out of http, https)proto = "https"
-# domain name of the sitedomain = www.atari-frosch.de
-# URL of the site. Change this line ONLY if you know what you're doing!myurl = proto + "://" + domain + "/"
-# Logging is always good. But we need a name for the logfile (optional with# a path), and a log level.# Loglevels:# 1 = critical messages only# 2 = critical, and error messages# 3 = critical, error, and warning messages# 4 = critical, error, warning, and info messages# 5 = critical, error, warning, info, and debug messages (very verbose!)makelogfile = "mysite.log"makeloglevel = 4
+#!usr/bin/env python3
+# -*- coding: utf8 -*-
+
+
+# Folder name for the site
+sitename = "atarifrosch"
+
+# File path for this site; content files with page.py files, menu.py files,
+# folders DEFAULTS, SNIPPETS, and CSS will be stored here.
+sitepath = "/home/frosch/prog/htmlglue/sites/atarifrosch/"
+
+# Standard protocol of the site (one out of http, https)
+proto = "https"
+
+# domain name of the site
+domain = "www.atari-frosch.de"
+
+# URL of the site. Change this line ONLY if you know what you're doing!
+myurl = proto + "://" + domain + "/"
+
+# Logging is always good. But we need a name for the logfile (optional with
+# a path), and a log level.
+# Loglevels:
+# 1 = critical messages only
+# 2 = critical, and error messages
+# 3 = critical, error, and warning messages
+# 4 = critical, error, warning, and info messages
+# 5 = critical, error, warning, info, and debug messages (very verbose!)
+makelogfile = "atarifrosch.log"
+makeloglevel = 5
+
 ## Standard settings for the <head> section of each page
-# These settings can be overwritten in each page.pylanguage = de# language will also be used for DC.Languagedoctype = <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">htmlver = <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">title = Froschs Homepage# title will also be used for DC.Title if dctitle is not setdescription = Froschs Homepage# description will also be used for DC.Description if dcdescription is not setrobots = index,followauthor = Atari-Frosch# dctitle = Froschs Homepagedccreator = Atari-Froschdcpublisher = Atari-Froschdcrights = Sabine 'Atari-Frosch' Beckerdccoverage = ""
-favicon = favicon.icostylesheet = style.cssstylesheetmedia = all
-# Position of menu: above or below content. Be reminded that this is# only the menu's position in the HTML code; where it will really be placed# within the graphical rendered page depends on your stylesheet.menupos = above
-# These files, which are placed in the SNIPPETS folder in sitepath, are# usually needed in order to complete the pages. They can contain keywords# ([KEYWORD]) which are recognized by makesite.py, functions in a page.py,# or additional functions in this settings.py.snippets = {}snippets["htmlhead"] = htmlhead.htmsnippets["bodytopfile"] = bodytop.htmsnippets["logofile"] = logo.htmsnippets["menustart"] = menustart.htmsnippets["menuend"] = menuend.htmsnippets["endoffile"] = endoffile.htm
-# The variable addtobody is of type dict and is set here in order to be# extended in page.py files. It can be used to add htm snippets, variables,# values, and even the return of a function into the content of a page.addtobody = {}# Example with snippet: addtobody["[AKVSBODY]"] = "akvsbody.htm"# Example with variable: addtobody["[MYURI]"] = myuri# Example with value: addtobody["[APPLES]"] = 4# Example with function: addtobody["[TODAY]"] = datetime.now().strftime("%Y-%m-%d")
-## EOF
\ No newline at end of file
+# These settings can be overwritten in each page.py
+language = "de"
+# language will also be used for DC.Language
+doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
+htmlver = '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">'
+title = "Froschs Homepage"
+# title will also be used for DC.Title if dctitle is not set
+description = "Froschs Homepage"
+# description will also be used for DC.Description if dcdescription is not set
+robots = "index,follow"
+author = "Atari-Frosch"
+# dctitle = "Froschs Homepage"
+dccreator = "Atari-Frosch"
+dcpublisher = "Atari-Frosch"
+dcrights = "Sabine 'Atari-Frosch' Becker"
+dccoverage = ""
+
+favicon = "favicon.ico"
+stylesheet = "frosch.css"
+stylesheetmedia = "all"
+
+# Position of menu: above or below content. Be reminded that this is
+# only the menu's position in the HTML code; where it will really be placed
+# within the graphical rendered page depends on your stylesheet.
+menupos = "above"
+
+# These files, which are placed in the SNIPPETS folder in sitepath, are
+# usually needed in order to complete the pages. They can contain keywords
+# ([KEYWORD]) which are recognized by makesite.py, functions in a page.py,
+# or additional functions in this settings.py.
+snippets = {}
+snippets["htmlhead"] = "htmlhead.htm"
+snippets["bodytopfile"] = "bodytop.htm"
+snippets["logofile"] = "logo.htm"
+snippets["menustart"] = "menustart.htm"
+snippets["menuend"] = "menuend.htm"
+snippets["endoffile"] = "endoffile.htm"
+
+# The variable addtobody is of type dict and is set here in order to be
+# extended in page.py files. It can be used to add htm snippets, variables,
+# values, and even the return of a function into the content of a page.
+addtobody = {}
+# Example with snippet: addtobody["[AKVSBODY]"] = "akvsbody.htm"
+# Example with variable: addtobody["[MYURI]"] = myuri
+# Example with value: addtobody["[APPLES]"] = 4
+# Example with function: addtobody["[TODAY]"] = datetime.now().strftime("%Y-%m-%d")
+
+## EOF