* Better exception handling. (Issue #204) - Hyde now propagates exceptions - Hyde does not raise exceptions by default. `-x` flag is required for raising exceptions on error. - Traceback is available in the `verbose` mode * Upgraded to commando 0.3.4 * Upgraded to Jinja 2.7main
| @@ -1,3 +1,15 @@ | |||
| Version 0.8.7a6 | |||
| ============================================================ | |||
| * Better exception handling. (Issue #204) | |||
| - Hyde now propagates exceptions | |||
| - Hyde does not raise exceptions by default. `-x` flag is required | |||
| for raising exceptions on error. | |||
| - Traceback is available in the `verbose` mode | |||
| * Upgraded to commando 0.3.4 | |||
| * Upgraded to Jinja 2.7 | |||
| Version 0.8.7a5 | |||
| ============================================================ | |||
| @@ -7,7 +19,7 @@ Version 0.8.7a4 | |||
| ============================================================ | |||
| * Include project artifacts in sdist. (Issue #211) | |||
| - Add LICENSE, AUTHORS and CHANGELOG to MANIFEST.in | |||
| - Add LICENSE, AUTHORS and CHANGELOG to MANIFEST.in | |||
| * Add "Hyde contributors to LICENSE copyright" | |||
| @@ -1,4 +1,4 @@ | |||
| Version 0.8.7a5 | |||
| Version 0.8.7a6 | |||
| A brand new **hyde** | |||
| ==================== | |||
| @@ -24,7 +24,7 @@ HYDE_LAYOUTS = "HYDE_LAYOUTS" | |||
| class Engine(Application): | |||
| def __init__(self, raise_exceptions=True): | |||
| def __init__(self, raise_exceptions=False): | |||
| logger = getLoggerWithConsoleHandler('hyde') | |||
| super(Engine, self).__init__( | |||
| raise_exceptions=raise_exceptions, | |||
| @@ -34,6 +34,8 @@ class Engine(Application): | |||
| @command(description='hyde - a python static website generator', | |||
| epilog='Use %(prog)s {command} -h to get help on individual commands') | |||
| @true('-v', '--verbose', help="Show detailed information in console") | |||
| @true('-x', '--raise-exceptions', default=False, | |||
| help="Don't handle exceptions.") | |||
| @version('--version', version='%(prog)s ' + __version__) | |||
| @store('-s', '--sitepath', default='.', help="Location of the hyde site") | |||
| def main(self, args): | |||
| @@ -43,6 +45,7 @@ class Engine(Application): | |||
| like version and metadata | |||
| """ | |||
| sitepath = Folder(args.sitepath).fully_expanded_path | |||
| self.raise_exceptions = args.raise_exceptions | |||
| return Folder(sitepath) | |||
| @subcommand('create', help='Create a new hyde site.') | |||
| @@ -94,7 +97,6 @@ class Engine(Application): | |||
| if args.regen: | |||
| self.logger.info("Regenerating the site...") | |||
| incremental = False | |||
| gen.generate_all(incremental=incremental) | |||
| self.logger.info("Generation complete.") | |||
| @@ -147,7 +149,6 @@ class Engine(Application): | |||
| publisher.publish() | |||
| def make_site(self, sitepath, config, deploy=None): | |||
| """ | |||
| Creates a site object from the given sitepath and the config file. | |||
| @@ -155,4 +156,4 @@ class Engine(Application): | |||
| config = Config(sitepath, config_file=config) | |||
| if deploy: | |||
| config.deploy_root = deploy | |||
| return Site(sitepath, config) | |||
| return Site(sitepath, config) | |||
| @@ -2,4 +2,10 @@ class HydeException(Exception): | |||
| """ | |||
| Base class for exceptions from hyde | |||
| """ | |||
| pass | |||
| @staticmethod | |||
| def reraise(message, exc_info): | |||
| _, _, tb = exc_info | |||
| raise HydeException(message), None, tb | |||
| @@ -10,6 +10,7 @@ from hyde.exceptions import HydeException | |||
| import os | |||
| import re | |||
| import subprocess | |||
| import sys | |||
| from fswrap import File | |||
| @@ -71,8 +72,7 @@ class LessCSSPlugin(CLTransformer): | |||
| afile = File(afile.path + '.less') | |||
| ref = self.site.content.resource_from_path(afile.path) | |||
| if not ref: | |||
| raise self.template.exception_class( | |||
| "Cannot import from path [%s]" % afile.path) | |||
| raise HydeException("Cannot import from path [%s]" % afile.path) | |||
| ref.is_processable = False | |||
| return self.template.get_include_statement(ref.relative_path) | |||
| text = self.import_finder.sub(import_to_include, text) | |||
| @@ -114,9 +114,11 @@ class LessCSSPlugin(CLTransformer): | |||
| try: | |||
| self.call_app(args) | |||
| except subprocess.CalledProcessError: | |||
| raise self.template.exception_class( | |||
| HydeException.reraise( | |||
| "Cannot process %s. Error occurred when " | |||
| "processing [%s]" % (self.app.name, resource.source_file)) | |||
| "processing [%s]" % (self.app.name, resource.source_file), | |||
| sys.exc_info()) | |||
| return target.read_all() | |||
| @@ -155,7 +157,7 @@ class StylusPlugin(CLTransformer): | |||
| def import_to_include(match): | |||
| """ | |||
| Converts a css import statement to include statemnt. | |||
| Converts a css import statement to include statement. | |||
| """ | |||
| if not match.lastindex: | |||
| return '' | |||
| @@ -172,7 +174,7 @@ class StylusPlugin(CLTransformer): | |||
| except AttributeError: | |||
| include = False | |||
| if not include: | |||
| raise self.template.exception_class( | |||
| raise HydeException( | |||
| "Cannot import from path [%s]" % afile.path) | |||
| else: | |||
| ref.is_processable = False | |||
| @@ -225,9 +227,10 @@ class StylusPlugin(CLTransformer): | |||
| try: | |||
| self.call_app(args) | |||
| except subprocess.CalledProcessError: | |||
| raise self.template.exception_class( | |||
| HydeException.reraise( | |||
| "Cannot process %s. Error occurred when " | |||
| "processing [%s]" % (stylus.name, resource.source_file)) | |||
| "processing [%s]" % (stylus.name, resource.source_file), | |||
| sys.exc_info()) | |||
| return target.read_all() | |||
| @@ -291,8 +294,7 @@ class CleverCSSPlugin(Plugin): | |||
| afile = File(afile.path + '.ccss') | |||
| ref = self.site.content.resource_from_path(afile.path) | |||
| if not ref: | |||
| raise self.template.exception_class( | |||
| "Cannot import from path [%s]" % afile.path) | |||
| raise HydeException("Cannot import from path [%s]" % afile.path) | |||
| ref.is_processable = False | |||
| return self.template.get_include_statement(ref.relative_path) | |||
| text = import_finder.sub(import_to_include, text) | |||
| @@ -3,7 +3,9 @@ | |||
| JavaScript plugins | |||
| """ | |||
| import subprocess | |||
| import sys | |||
| from hyde.exceptions import HydeException | |||
| from hyde.plugin import CLTransformer | |||
| from fswrap import File | |||
| @@ -127,9 +129,10 @@ class RequireJSPlugin(CLTransformer): | |||
| try: | |||
| self.call_app(args) | |||
| except subprocess.CalledProcessError: | |||
| raise self.template.exception_class( | |||
| HydeException.reraise( | |||
| "Cannot process %s. Error occurred when " | |||
| "processing [%s]" % (self.app.name, resource.source_file)) | |||
| "processing [%s]" % (self.app.name, resource.source_file), | |||
| sys.exc_info()) | |||
| return target.read_all() | |||
| @@ -8,7 +8,9 @@ from functools import partial | |||
| from itertools import ifilter | |||
| from operator import attrgetter | |||
| import re | |||
| import sys | |||
| from hyde.exceptions import HydeException | |||
| from hyde.model import Expando | |||
| from hyde.plugin import Plugin | |||
| from hyde.site import Node, Resource | |||
| @@ -248,8 +250,9 @@ def get_tagger_sort_method(site): | |||
| try: | |||
| walker = getattr(content, walker) | |||
| except AttributeError: | |||
| raise self.template.exception_class( | |||
| "Cannot find the sorter: %s" % sorter) | |||
| HydeException.reraise( | |||
| "Cannot find the sorter: %s" % sorter, | |||
| sys.exc_info()) | |||
| return walker | |||
| def walk_resources_tagged_with(node, tag): | |||
| @@ -370,8 +373,7 @@ class TaggerPlugin(Plugin): | |||
| Generates archives for each tag based on the given configuration. | |||
| """ | |||
| if not 'template' in config: | |||
| raise self.template.exception_class( | |||
| "No Template specified in tagger configuration.") | |||
| raise HydeException("No Template specified in tagger configuration.") | |||
| content = self.site.content.source_folder | |||
| source = Folder(config.get('source', '')) | |||
| target = content.child_folder(config.get('target', 'tags')) | |||
| @@ -4,11 +4,13 @@ Jinja template utilties | |||
| """ | |||
| from datetime import datetime, date | |||
| import itertools | |||
| import os | |||
| import re | |||
| import itertools | |||
| import sys | |||
| from urllib import quote, unquote | |||
| from hyde.exceptions import HydeException | |||
| from hyde.model import Expando | |||
| from hyde.template import HtmlWrap, Template | |||
| from operator import attrgetter | |||
| @@ -599,10 +601,20 @@ class HydeLoader(FileSystemLoader): | |||
| # | |||
| template = template.replace(os.sep, '/') | |||
| logger.debug("Loading template [%s] and preprocessing" % template) | |||
| (contents, | |||
| filename, | |||
| date) = super(HydeLoader, self).get_source( | |||
| try: | |||
| (contents, | |||
| filename, | |||
| date) = super(HydeLoader, self).get_source( | |||
| environment, template) | |||
| except UnicodeDecodeError: | |||
| HydeException.reraise( | |||
| "Unicode error when processing %s" % template, sys.exc_info()) | |||
| except TemplateError, exc: | |||
| HydeException.reraise('Error when processing %s: %s' % ( | |||
| template, | |||
| unicode(exc) | |||
| ), sys.exc_info()) | |||
| if self.preprocessor: | |||
| resource = self.site.content.resource_from_relative_path(template) | |||
| if resource: | |||
| @@ -736,9 +748,11 @@ class Jinja2Template(Template): | |||
| from jinja2.meta import find_referenced_templates | |||
| try: | |||
| ast = self.env.parse(text) | |||
| except: | |||
| logger.error("Error parsing[%s]" % path) | |||
| raise | |||
| except Exception, e: | |||
| HydeException.reraise( | |||
| "Error processing %s: \n%s" % (path, unicode(e)), | |||
| sys.exc_info()) | |||
| tpls = find_referenced_templates(ast) | |||
| deps = list(self.env.globals['deps'].get('path', [])) | |||
| for dep in tpls: | |||
| @@ -818,9 +832,6 @@ class Jinja2Template(Template): | |||
| template = self.env.get_template(resource.relative_path) | |||
| out = template.render(context) | |||
| except: | |||
| out = "" | |||
| logger.debug(self.env.loader.get_source( | |||
| self.env, resource.relative_path)) | |||
| raise | |||
| return out | |||
| @@ -3,8 +3,9 @@ | |||
| The generator class and related utility functions. | |||
| """ | |||
| from hyde.exceptions import HydeException | |||
| from commando.util import getLoggerWithNullHandler | |||
| from fswrap import File, Folder | |||
| from hyde.exceptions import HydeException | |||
| from hyde.model import Context, Dependents | |||
| from hyde.plugin import Plugin | |||
| from hyde.template import Template | |||
| @@ -12,9 +13,9 @@ from hyde.site import Resource | |||
| from contextlib import contextmanager | |||
| from datetime import datetime | |||
| from shutil import copymode | |||
| from commando.util import getLoggerWithNullHandler | |||
| import sys | |||
| logger = getLoggerWithNullHandler('hyde.engine') | |||
| @@ -334,10 +335,12 @@ class Generator(object): | |||
| try: | |||
| text = self.template.render_resource(resource, | |||
| context) | |||
| except Exception: | |||
| logger.error("Error occurred when" | |||
| " processing template: [%s]" % resource) | |||
| raise | |||
| except Exception, e: | |||
| HydeException.reraise("Error occurred when" | |||
| " processing template: [%s]: %s" % | |||
| (resource, repr(e)), | |||
| sys.exc_info() | |||
| ) | |||
| else: | |||
| text = resource.source_file.read_all() | |||
| text = self.events.begin_text_resource(resource, text) or text | |||
| @@ -12,6 +12,7 @@ import fnmatch | |||
| import os | |||
| import re | |||
| import subprocess | |||
| import sys | |||
| import traceback | |||
| from commando.util import getLoggerWithNullHandler, load_python_object | |||
| @@ -56,18 +57,19 @@ class PluginProxy(object): | |||
| def __getattr__(self, method_name): | |||
| if hasattr(Plugin, method_name): | |||
| def __call_plugins__(*args): | |||
| # logger.debug("Calling plugin method [%s]", method_name) | |||
| res = None | |||
| if self.site.plugins: | |||
| for plugin in self.site.plugins: | |||
| if hasattr(plugin, method_name): | |||
| # logger.debug( | |||
| # "\tCalling plugin [%s]", | |||
| # plugin.__class__.__name__) | |||
| checker = getattr(plugin, 'should_call__' + method_name) | |||
| if checker(*args): | |||
| function = getattr(plugin, method_name) | |||
| res = function(*args) | |||
| try: | |||
| res = function(*args) | |||
| except: | |||
| HydeException.reraise( | |||
| 'Error occured when calling %s' % | |||
| plugin.plugin_name, sys.exc_info()) | |||
| targs = list(args) | |||
| if len(targs): | |||
| last = targs.pop() | |||
| @@ -356,14 +358,11 @@ class CLTransformer(Plugin): | |||
| app_path = discover_executable(app_path, self.site.sitepath) | |||
| if app_path is None: | |||
| raise self.template.exception_class( | |||
| self.executable_not_found_message) | |||
| raise HydeException(self.executable_not_found_message) | |||
| app = File(app_path) | |||
| if not app.exists: | |||
| raise self.template.exception_class( | |||
| self.executable_not_found_message) | |||
| raise HydeException(self.executable_not_found_message) | |||
| return app | |||
| @@ -418,7 +417,6 @@ class CLTransformer(Plugin): | |||
| (args[0], unicode(args[1:]))) | |||
| return subprocess.check_output(args) | |||
| except subprocess.CalledProcessError, error: | |||
| self.logger.error(traceback.format_exc()) | |||
| self.logger.error(error.output) | |||
| raise | |||
| @@ -162,7 +162,7 @@ class HydeWebServer(HTTPServer): | |||
| except Exception, exception: | |||
| logger.error('Error occured when regenerating the site [%s]' | |||
| % exception.message) | |||
| logger.error(traceback.format_exc()) | |||
| logger.debug(traceback.format_exc()) | |||
| def generate_node(self, node): | |||
| """ | |||
| @@ -180,7 +180,7 @@ class HydeWebServer(HTTPServer): | |||
| logger.error( | |||
| 'Error [%s] occured when generating the node [%s]' | |||
| % (repr(exception), node)) | |||
| logger.error(traceback.format_exc()) | |||
| logger.debug(traceback.format_exc()) | |||
| def generate_resource(self, resource): | |||
| """ | |||
| @@ -199,4 +199,4 @@ class HydeWebServer(HTTPServer): | |||
| logger.error( | |||
| 'Error [%s] occured when serving the resource [%s]' | |||
| % (repr(exception), resource)) | |||
| logger.error(traceback.format_exc()) | |||
| logger.debug(traceback.format_exc()) | |||
| @@ -2,4 +2,4 @@ | |||
| """ | |||
| Handles hyde version. | |||
| """ | |||
| __version__ = '0.8.7a5' | |||
| __version__ = '0.8.7a6' | |||
| @@ -1,8 +1,8 @@ | |||
| fswrap==0.1.1 | |||
| commando==0.3.2a | |||
| commando==0.3.4 | |||
| PyYAML==3.10 | |||
| Markdown==2.3.1 | |||
| MarkupSafe==0.15 | |||
| MarkupSafe==0.18 | |||
| Pygments==1.6 | |||
| typogrify==2.0.0 | |||
| Jinja2==2.6 | |||
| Jinja2==2.7 | |||
| @@ -117,13 +117,13 @@ setup(name=PROJECT, | |||
| requires=['python (>= 2.7)'], | |||
| install_requires=( | |||
| 'fswrap==0.1.1', | |||
| 'commando==0.3.2a', | |||
| 'commando==0.3.4', | |||
| 'PyYAML==3.10', | |||
| 'Markdown==2.3.1', | |||
| 'MarkupSafe==0.15', | |||
| 'MarkupSafe==0.18', | |||
| 'Pygments==1.6', | |||
| 'typogrify==2.0.0', | |||
| 'Jinja2==2.6' | |||
| 'Jinja2==2.7' | |||
| ), | |||
| tests_require=( | |||
| 'nose', 'mock' | |||