summaryrefslogtreecommitdiff
path: root/pagetemplatefile.py
diff options
context:
space:
mode:
Diffstat (limited to 'pagetemplatefile.py')
-rw-r--r--pagetemplatefile.py119
1 files changed, 119 insertions, 0 deletions
diff --git a/pagetemplatefile.py b/pagetemplatefile.py
new file mode 100644
index 0000000..3517f5f
--- /dev/null
+++ b/pagetemplatefile.py
@@ -0,0 +1,119 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Filesystem Page Template module
+
+Zope object encapsulating a Page Template from the filesystem.
+
+$Id$
+"""
+
+__all__ = ("PageTemplateFile",)
+
+import os
+import sys
+import re
+import logging
+
+from zope.pagetemplate.pagetemplate import PageTemplate
+
+from typesniffer import sniff_type
+from typesniffer import XML_PREFIX_MAX_LENGTH
+
+DEFAULT_ENCODING = "utf-8"
+
+meta_pattern = re.compile(
+ r'\s*<meta\s+http-equiv=["\']?Content-Type["\']?'
+ r'\s+content=["\']?([^;]+);\s*charset=([^"\']+)["\']?\s*>\s*',
+ re.IGNORECASE)
+
+def package_home(gdict):
+ filename = gdict["__file__"]
+ return os.path.dirname(filename)
+
+class PageTemplateFile(PageTemplate):
+ "Zope wrapper for filesystem Page Template using TAL, TALES, and METAL"
+
+ _v_last_read = 0
+
+ def __init__(self, filename, _prefix=None):
+ path = self.get_path_from_prefix(_prefix)
+ self.filename = os.path.join(path, filename)
+ if not os.path.isfile(self.filename):
+ raise ValueError("No such file", self.filename)
+
+ def get_path_from_prefix(self, _prefix):
+ if isinstance(_prefix, str):
+ path = _prefix
+ else:
+ if _prefix is None:
+ _prefix = sys._getframe(2).f_globals
+ path = package_home(_prefix)
+ return path
+
+ def _prepare_html(self, text):
+ match = meta_pattern.search(text)
+ if match is not None:
+ type, encoding = match.groups()
+ # TODO: Shouldn't <meta>/<?xml?> stripping
+ # be in PageTemplate.__call__()?
+ text = meta_pattern.sub("", text)
+ else:
+ type = None
+ encoding = DEFAULT_ENCODING
+ return unicode(text, encoding), type
+
+ def _read_file(self):
+ __traceback_info__ = self.filename
+ f = open(self.filename, "rb")
+ try:
+ text = f.read(XML_PREFIX_MAX_LENGTH)
+ except:
+ f.close()
+ raise
+ type_ = sniff_type(text)
+ if type_ == "text/xml":
+ text += f.read()
+ else:
+ # For HTML, we really want the file read in text mode:
+ f.close()
+ f = open(self.filename)
+ text = f.read()
+ text, type_ = self._prepare_html(text)
+ f.close()
+ return text, type_
+
+ def _cook_check(self):
+ if self._v_last_read and not __debug__:
+ return
+ __traceback_info__ = self.filename
+ try:
+ mtime = os.path.getmtime(self.filename)
+ except OSError:
+ mtime = 0
+ if self._v_program is not None and mtime == self._v_last_read:
+ return
+ text, type = self._read_file()
+ self.pt_edit(text, type)
+ self._cook()
+ if self._v_errors:
+ logging.error('PageTemplateFile: Error in template: %s',
+ '\n'.join(self._v_errors))
+ return
+ self._v_last_read = mtime
+
+ def pt_source_file(self):
+ return self.filename
+
+ def __getstate__(self):
+ raise TypeError("non-picklable object")