Page MenuHomec4science

template.py
No OneTemporary

File Metadata

Created
Tue, May 14, 21:00

template.py

## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
"""CDS Invenio templating framework."""
__revision__ = "$Id$"
import os, sys, inspect
try:
# This tool can be run before Invenio is installed:
# invenio files might then not exist.
from invenio.config import \
CFG_WEBSTYLE_TEMPLATE_SKIN, \
CFG_PREFIX
CFG_WEBSTYLE_PYLIBDIR = CFG_PREFIX + os.sep + 'lib' + os.sep + 'python'
except ImportError:
CFG_WEBSTYLE_PYLIBDIR = None
# List of deprecated functions
# Eg. {'webstyle': {'tmpl_records_format_other':"Replaced by .."}}
CFG_WEBSTYLE_DEPRECATED_FUNCTIONS = {'webstyle': \
{'tmpl_records_format_other': "Replaced by " + \
"tmpl_detailed_record_metadata(..), " + \
"tmpl_detailed_record_references(..), " + \
"tmpl_get_comments(..), " + \
"tmpl_detailed_record_statistics(..), " + \
"tmpl_filelist(..), tmpl_mini_review(..)," + \
"HDFILE + HDACT + HDREF output formats"
}
}
# List of deprecated parameter
# Eg. {'webstyle': {'get_page':{'header': "replaced by 'title'"}}}
CFG_WEBSTYLE_DEPRECATED_PARAMETERS = {}
def load(module=''):
""" Load and returns a template class, given a module name (like
'websearch', 'webbasket',...). The module corresponding to
the currently selected template model (see config.wml,
variable CFG_TEMPLATE_SKIN) is tried first. In case it does
not exist, it returns the default template for that module.
"""
local = {}
# load the right template based on the CFG_WEBSTYLE_TEMPLATE_SKIN and the specified module
if CFG_WEBSTYLE_TEMPLATE_SKIN == "default":
mymodule = __import__("invenio.%s_templates" % (module), local, local,
["invenio.templates.%s" % (module)])
else:
try:
mymodule = __import__("invenio.%s_templates_%s" % (module, CFG_WEBSTYLE_TEMPLATE_SKIN), local, local,
["invenio.templates.%s_%s" % (module, CFG_WEBSTYLE_TEMPLATE_SKIN)])
except ImportError:
mymodule = __import__("invenio.%s_templates" % (module), local, local,
["invenio.templates.%s" % (module)])
return mymodule.Template()
# Functions to check that customized templates functions conform to
# the default templates functions
##
def check():
"""
Check that installed customized templates are conform to the
default templates interfaces.
Result of the analysis is reported back in 'messages' object
(see 'messages' structure description in print_messages(..) docstring)
"""
messages = []
if CFG_WEBSTYLE_PYLIBDIR is None:
# Nothing to check, since Invenio has not been installed
messages.append(('C', "Nothing to check. Run 'make install' first.",
'',
None,
0))
return messages
# Iterage over all customized templates
for (default_template_path, custom_template_path) in \
get_custom_templates(get_default_templates()):
# Load the custom and default templates
default_tpl_path, default_tpl_name = os.path.split(default_template_path)
if default_tpl_path not in sys.path:
sys.path.append(default_tpl_path)
custom_tpl_path, custom_tpl_name = os.path.split(custom_template_path)
if custom_tpl_path not in sys.path:
sys.path.append(custom_tpl_path)
default_template = __import__(default_tpl_name[:-3],
globals(),
locals(),
[''])
custom_template = __import__(custom_tpl_name[:-3],
globals(),
locals(),
[''])
# Check if Template class is in the file
classes = inspect.getmembers(custom_template, inspect.isclass)
if 'Template' not in [possible_class[0] for possible_class in classes]:
messages.append(('E', "'Template' class missing",
custom_template.__name__,
None,
0))
continue
# Check customized functions parameters
for (default_function_name, default_function) in \
inspect.getmembers(default_template.Template, inspect.isroutine):
if custom_template.Template.__dict__.has_key(default_function_name):
# Customized function exists
custom_function = custom_template.Template.__dict__[default_function_name]
(deft_args, deft_varargs, deft_varkw, deft_defaults) = \
inspect.getargspec(default_function.im_func)
(cust_args, cust_varargs, cust_varkw, cust_defaults) = \
inspect.getargspec(custom_function)
deft_args.reverse()
if deft_defaults is not None:
deft_defaults_list = list(deft_defaults)
deft_defaults_list.reverse()
else:
deft_defaults_list = []
cust_args.reverse()
if cust_defaults is not None:
cust_defaults_list = list(cust_defaults)
cust_defaults_list.reverse()
else:
cust_defaults_list = []
arg_errors = False
# Check for presence of missing parameters in custom template
for deft_arg in deft_args:
if deft_arg not in cust_args:
arg_errors = True
messages.append(('E', "missing '%s' parameter" % \
deft_arg,
custom_tpl_name,
default_function_name,
inspect.getsourcelines(custom_function)[1]))
# Check for presence of additional parameters in custom template
for cust_arg in cust_args:
if cust_arg not in deft_args:
arg_errors = True
messages.append(('E', "unknown parameter '%s'" % \
cust_arg,
custom_tpl_name,
custom_function.__name__,
inspect.getsourcelines(custom_function)[1]))
# If parameter is deprecated, report it
module_name = default_tpl_name.split("_")[0]
if CFG_WEBSTYLE_DEPRECATED_PARAMETERS.has_key(module_name) and \
CFG_WEBSTYLE_DEPRECATED_PARAMETERS[module_name].has_key(default_function_name) and \
CFG_WEBSTYLE_DEPRECATED_PARAMETERS[module_name][default_function_name].has_key(cust_arg):
messages.append(('C', CFG_WEBSTYLE_DEPRECATED_PARAMETERS[module_name][default_function_name][cust_arg],
custom_tpl_name,
custom_function.__name__,
inspect.getsourcelines(custom_function)[1]))
# Check for same ordering of parameters.
# Only raise warning if previous parameter tests did
# not generate errors
if not arg_errors:
for cust_arg, deft_arg in map(None, cust_args, deft_args):
if deft_arg != cust_arg:
arg_errors = True
messages.append(('W', "order of parameters is not respected",
custom_tpl_name,
custom_function.__name__,
inspect.getsourcelines(custom_function)[1]))
break
# Check for equality of default parameters values
# Only raise warning if previous parameter tests did
# not generate errors or warnings
if not arg_errors:
i = 0
for cust_default, deft_default in \
map(None, cust_defaults_list, deft_defaults_list):
if deft_default != cust_default:
messages.append(('W', "default value for parameter '%s' is not respected" % \
cust_args[i],
custom_tpl_name,
default_function_name,
inspect.getsourcelines(custom_function)[1]))
i += 1
else:
# Function is not in custom template. Generate warning?
pass
# Check for presence of additional functions in custom template
for (custom_function_name, custom_function) in \
inspect.getmembers(custom_template.Template, inspect.isroutine):
if not default_template.Template.__dict__.has_key(custom_function_name):
messages.append(('W', "unknown function",
custom_tpl_name,
custom_function_name,
inspect.getsourcelines(custom_function)[1]))
# If the function was deprecated, report it
module_name = default_tpl_name.split("_")[0]
if CFG_WEBSTYLE_DEPRECATED_FUNCTIONS.has_key(module_name) and \
CFG_WEBSTYLE_DEPRECATED_FUNCTIONS[module_name].has_key(custom_function_name):
messages.append(('C', CFG_WEBSTYLE_DEPRECATED_FUNCTIONS[module_name][custom_function_name],
custom_tpl_name,
custom_function_name,
inspect.getsourcelines(custom_function)[1]))
return messages
# Utility functions
##
def get_default_templates(base_dir=None):
"""
Returns the paths to all default Invenio templates.
base_dir - path to where templates should be recursively searched
"""
# If base_dir is not specified we assume that this template.py
# file is located in $INVENIO$/modules/webstyle/lib, which allows
# us to guess where base $Invenio$/modules dir is.
# Note that by luck it also works if file is installed
# in /lib/python/invenio/
if base_dir is None:
# Retrieve path to Invenio 'modules' dir
this_pathname = os.path.abspath(sys.argv[0])
#this_pathname = inspect.getsourcefile(get_default_templates)
this_dir, this_name = os.path.split(this_pathname)
base_dir = this_dir + os.sep + os.pardir + \
os.sep + os.pardir
else:
base_dir = os.path.abspath(base_dir)
templates_path = []
for (dirpath, dirnames, filenames) in os.walk(base_dir):
for filename in filenames:
if filename.endswith("_templates.py"):
templates_path.append(os.path.join(dirpath, filename))
return templates_path
def get_custom_templates(default_templates_paths):
"""
Returns the paths to customized templates among the given list of
templates paths.
"""
return [(default, get_custom_template(default)) \
for default in default_templates_paths \
if get_custom_template(default) is not None]
def get_custom_template(default_template_path):
"""
Returns the path to the customized template of the default
template given as parameter. Returns None if customized does not
exist.
"""
default_tpl_path, default_tpl_name = os.path.split(default_template_path)
custom_path = CFG_WEBSTYLE_PYLIBDIR + \
os.sep + "invenio" + os.sep + \
default_tpl_name[:-3] + '_' + \
CFG_WEBSTYLE_TEMPLATE_SKIN + '.py'
if os.path.exists(custom_path):
return custom_path
else:
return None
def print_messages(messages,
verbose=3):
"""
Report errors and warnings to user.
messages - list of tuples (type, message, template, function, line)
where: - type : One of the strings:
- 'E': Error
- 'W': Warning
- 'C': Comment
- message : The string message
- template : template name where message occurred
- function : function name where message occurred
- line : line number where message occurred
verbose - int specifying the verbosity of the output.
0 - summary only
1 - summary + errors
2 - summary + errors + warnings
3 - summary + errors + warnings + comments
"""
last_template = '' # Remember last considered template in order to
# print separator between templates
for message in messages:
if message[0] == 'F' and verbose >= 0 or \
message[0] == 'E' and verbose >= 1 or \
message[0] == 'W' and verbose >= 2 or \
message[0] == 'C' and verbose >= 3:
# Print separator if we have moved to another template
if last_template != message[2]:
print "************* Template %s" % message[2]
last_template = message[2]
print '%s:%s:%s%s' % \
(message[0],
message[4],
# message[2].endswith('.py') and message[2][:-3] or \
# message[2],
message[3] and ("%s(): " % message[3]) or ' ',
message[1])
# Print summary
if verbose >= 0:
nb_errors = len([message for message in messages \
if message[0] == 'E'])
nb_warnings = len([message for message in messages \
if message[0] == 'W'])
nb_comments = len([message for message in messages \
if message[0] == 'C'])
if len(messages) > 0:
print '\nFAILED'
else:
print '\nOK'
print "%i error%s, %i warning%s, %i comment%s." % \
(nb_errors, nb_errors > 1 and 's' or '',
nb_warnings, nb_warnings > 1 and 's' or '',
nb_comments, nb_comments > 1 and 's' or '')
if __name__ == "__main__" and \
'--check-custom-templates' in sys.argv:
messages_ = check()
print_messages(messages_)

Event Timeline