
* Module files now are generated using a template engine refers #2902 #3173 jinja2 has been hooked into Spack. The python module `modules.py` has been splitted into several modules under the python package `spack/modules`. Unit tests stressing module file generation have been refactored accordingly. The module file generator for Lmod has been extended to multi-providers and deeper hierarchies. * Improved the support for templates in module files. Added an entry in `config.yaml` (`template_dirs`) to list all the directories where Spack could find templates for `jinja2`. Module file generators have a simple override mechanism to override template selection ('modules.yaml' beats 'package.py' beats 'default'). * Added jinja2 and MarkupSafe to vendored packages. * Spec.concretize() sets mutual spec-package references The correct place to set the mutual references between spec and package objects at the end of concretization. After a call to concretize we should now be ensured that spec is the same object as spec.package.spec. Code in `build_environment.py` that was performing the same operation has been turned into an assertion to be defensive on the new behavior. * Improved code and data layout for modules and related tests. Common fixtures related to module file generation have been extracted in `conftest.py`. All the mock configurations for module files have been extracted from python code and have been put into their own yaml file. Added a `context_property` decorator for the template engine, to make it easy to define dictionaries out of properties. The default for `verbose` in `modules.yaml` is now False instead of True. * Extendable module file contexts + short description from docstring The contexts that are used in conjunction with `jinja2` templates to generate module files can now be extended from package.py and modules.yaml. Module files generators now infer the short description from package.py docstring (and as you may expect it's the first paragraph) * 'module refresh' regenerates all modules by default `module refresh` without `--module-type` specified tries to regenerate all known module types. The same holds true for `module rm` Configure options used at build time are extracted and written into the module files where possible. * Fixed python3 compatibility, tests for Lmod and Tcl. Added test for exceptional paths of execution when generating Lmod module files. Fixed a few compatibility issues with python3. Fixed a bug in Tcl with naming_scheme and autoload + unit tests * Updated module file tutorial docs. Fixed a few typos in docstrings. The reference section for module files has been reorganized. The idea is to have only three topics at the highest level: - shell support + spack load/unload use/unuse - module file generation (a.k.a. APIs + modules.yaml) - module file maintenance (spack module refresh/rm) Module file generation will cover the entries in modules.yaml Also: - Licenses have been updated to include NOTICE and extended to 2017 - docstrings have been reformatted according to Google style * Removed redundant arguments to RPackage and WafPackage. All the callbacks in `RPackage` and `WafPackage` that are not build phases have been modified not to accept a `spec` and a `prefix` argument. This permits to leverage the common `configure_args` signature to insert by default the configuration arguments into the generated module files. I think it's preferable to handling those packages differently than `AutotoolsPackage`. Besides only one package seems to override one of these methods. * Fixed broken indentation + improved resiliency of refresh Fixed broken indentation in `spack module refresh` (probably a rebase gone silently wrong?). Filter the writers for blacklisted specs before searching for name clashes. An error with a single writer will not stop regeneration, but instead will print a warning and continue the command.
147 lines
4.3 KiB
Python
147 lines
4.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
jinja2.exceptions
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
Jinja exceptions.
|
|
|
|
:copyright: (c) 2017 by the Jinja Team.
|
|
:license: BSD, see LICENSE for more details.
|
|
"""
|
|
from jinja2._compat import imap, text_type, PY2, implements_to_string
|
|
|
|
|
|
class TemplateError(Exception):
|
|
"""Baseclass for all template errors."""
|
|
|
|
if PY2:
|
|
def __init__(self, message=None):
|
|
if message is not None:
|
|
message = text_type(message).encode('utf-8')
|
|
Exception.__init__(self, message)
|
|
|
|
@property
|
|
def message(self):
|
|
if self.args:
|
|
message = self.args[0]
|
|
if message is not None:
|
|
return message.decode('utf-8', 'replace')
|
|
|
|
def __unicode__(self):
|
|
return self.message or u''
|
|
else:
|
|
def __init__(self, message=None):
|
|
Exception.__init__(self, message)
|
|
|
|
@property
|
|
def message(self):
|
|
if self.args:
|
|
message = self.args[0]
|
|
if message is not None:
|
|
return message
|
|
|
|
|
|
@implements_to_string
|
|
class TemplateNotFound(IOError, LookupError, TemplateError):
|
|
"""Raised if a template does not exist."""
|
|
|
|
# looks weird, but removes the warning descriptor that just
|
|
# bogusly warns us about message being deprecated
|
|
message = None
|
|
|
|
def __init__(self, name, message=None):
|
|
IOError.__init__(self)
|
|
if message is None:
|
|
message = name
|
|
self.message = message
|
|
self.name = name
|
|
self.templates = [name]
|
|
|
|
def __str__(self):
|
|
return self.message
|
|
|
|
|
|
class TemplatesNotFound(TemplateNotFound):
|
|
"""Like :class:`TemplateNotFound` but raised if multiple templates
|
|
are selected. This is a subclass of :class:`TemplateNotFound`
|
|
exception, so just catching the base exception will catch both.
|
|
|
|
.. versionadded:: 2.2
|
|
"""
|
|
|
|
def __init__(self, names=(), message=None):
|
|
if message is None:
|
|
message = u'none of the templates given were found: ' + \
|
|
u', '.join(imap(text_type, names))
|
|
TemplateNotFound.__init__(self, names and names[-1] or None, message)
|
|
self.templates = list(names)
|
|
|
|
|
|
@implements_to_string
|
|
class TemplateSyntaxError(TemplateError):
|
|
"""Raised to tell the user that there is a problem with the template."""
|
|
|
|
def __init__(self, message, lineno, name=None, filename=None):
|
|
TemplateError.__init__(self, message)
|
|
self.lineno = lineno
|
|
self.name = name
|
|
self.filename = filename
|
|
self.source = None
|
|
|
|
# this is set to True if the debug.translate_syntax_error
|
|
# function translated the syntax error into a new traceback
|
|
self.translated = False
|
|
|
|
def __str__(self):
|
|
# for translated errors we only return the message
|
|
if self.translated:
|
|
return self.message
|
|
|
|
# otherwise attach some stuff
|
|
location = 'line %d' % self.lineno
|
|
name = self.filename or self.name
|
|
if name:
|
|
location = 'File "%s", %s' % (name, location)
|
|
lines = [self.message, ' ' + location]
|
|
|
|
# if the source is set, add the line to the output
|
|
if self.source is not None:
|
|
try:
|
|
line = self.source.splitlines()[self.lineno - 1]
|
|
except IndexError:
|
|
line = None
|
|
if line:
|
|
lines.append(' ' + line.strip())
|
|
|
|
return u'\n'.join(lines)
|
|
|
|
|
|
class TemplateAssertionError(TemplateSyntaxError):
|
|
"""Like a template syntax error, but covers cases where something in the
|
|
template caused an error at compile time that wasn't necessarily caused
|
|
by a syntax error. However it's a direct subclass of
|
|
:exc:`TemplateSyntaxError` and has the same attributes.
|
|
"""
|
|
|
|
|
|
class TemplateRuntimeError(TemplateError):
|
|
"""A generic runtime error in the template engine. Under some situations
|
|
Jinja may raise this exception.
|
|
"""
|
|
|
|
|
|
class UndefinedError(TemplateRuntimeError):
|
|
"""Raised if a template tries to operate on :class:`Undefined`."""
|
|
|
|
|
|
class SecurityError(TemplateRuntimeError):
|
|
"""Raised if a template tries to do something insecure if the
|
|
sandbox is enabled.
|
|
"""
|
|
|
|
|
|
class FilterArgumentError(TemplateRuntimeError):
|
|
"""This error is raised if a filter was called with inappropriate
|
|
arguments
|
|
"""
|