Browse Source

Provide more informative exceptions. (Issue #204).

*   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
main
Lakshmi Vyasarajan 11 years ago
parent
commit
979ad3af8b
14 changed files with 99 additions and 61 deletions
  1. +13
    -1
      CHANGELOG.rst
  2. +1
    -1
      README.rst
  3. +5
    -4
      hyde/engine.py
  4. +7
    -1
      hyde/exceptions.py
  5. +12
    -10
      hyde/ext/plugins/css.py
  6. +5
    -2
      hyde/ext/plugins/js.py
  7. +6
    -4
      hyde/ext/plugins/meta.py
  8. +21
    -10
      hyde/ext/templates/jinja.py
  9. +10
    -7
      hyde/generator.py
  10. +9
    -11
      hyde/plugin.py
  11. +3
    -3
      hyde/server.py
  12. +1
    -1
      hyde/version.py
  13. +3
    -3
      requirements.txt
  14. +3
    -3
      setup.py

+ 13
- 1
CHANGELOG.rst View File

@@ -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 Version 0.8.7a5
============================================================ ============================================================


@@ -7,7 +19,7 @@ Version 0.8.7a4
============================================================ ============================================================


* Include project artifacts in sdist. (Issue #211) * 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" * Add "Hyde contributors to LICENSE copyright"






+ 1
- 1
README.rst View File

@@ -1,4 +1,4 @@
Version 0.8.7a5
Version 0.8.7a6


A brand new **hyde** A brand new **hyde**
==================== ====================


+ 5
- 4
hyde/engine.py View File

@@ -24,7 +24,7 @@ HYDE_LAYOUTS = "HYDE_LAYOUTS"


class Engine(Application): class Engine(Application):


def __init__(self, raise_exceptions=True):
def __init__(self, raise_exceptions=False):
logger = getLoggerWithConsoleHandler('hyde') logger = getLoggerWithConsoleHandler('hyde')
super(Engine, self).__init__( super(Engine, self).__init__(
raise_exceptions=raise_exceptions, raise_exceptions=raise_exceptions,
@@ -34,6 +34,8 @@ class Engine(Application):
@command(description='hyde - a python static website generator', @command(description='hyde - a python static website generator',
epilog='Use %(prog)s {command} -h to get help on individual commands') epilog='Use %(prog)s {command} -h to get help on individual commands')
@true('-v', '--verbose', help="Show detailed information in console") @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__) @version('--version', version='%(prog)s ' + __version__)
@store('-s', '--sitepath', default='.', help="Location of the hyde site") @store('-s', '--sitepath', default='.', help="Location of the hyde site")
def main(self, args): def main(self, args):
@@ -43,6 +45,7 @@ class Engine(Application):
like version and metadata like version and metadata
""" """
sitepath = Folder(args.sitepath).fully_expanded_path sitepath = Folder(args.sitepath).fully_expanded_path
self.raise_exceptions = args.raise_exceptions
return Folder(sitepath) return Folder(sitepath)


@subcommand('create', help='Create a new hyde site.') @subcommand('create', help='Create a new hyde site.')
@@ -94,7 +97,6 @@ class Engine(Application):
if args.regen: if args.regen:
self.logger.info("Regenerating the site...") self.logger.info("Regenerating the site...")
incremental = False incremental = False

gen.generate_all(incremental=incremental) gen.generate_all(incremental=incremental)
self.logger.info("Generation complete.") self.logger.info("Generation complete.")


@@ -147,7 +149,6 @@ class Engine(Application):
publisher.publish() publisher.publish()





def make_site(self, sitepath, config, deploy=None): def make_site(self, sitepath, config, deploy=None):
""" """
Creates a site object from the given sitepath and the config file. 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) config = Config(sitepath, config_file=config)
if deploy: if deploy:
config.deploy_root = deploy config.deploy_root = deploy
return Site(sitepath, config)
return Site(sitepath, config)

+ 7
- 1
hyde/exceptions.py View File

@@ -2,4 +2,10 @@ class HydeException(Exception):
""" """
Base class for exceptions from hyde Base class for exceptions from hyde
""" """
pass

@staticmethod
def reraise(message, exc_info):
_, _, tb = exc_info
raise HydeException(message), None, tb



+ 12
- 10
hyde/ext/plugins/css.py View File

@@ -10,6 +10,7 @@ from hyde.exceptions import HydeException
import os import os
import re import re
import subprocess import subprocess
import sys


from fswrap import File from fswrap import File


@@ -71,8 +72,7 @@ class LessCSSPlugin(CLTransformer):
afile = File(afile.path + '.less') afile = File(afile.path + '.less')
ref = self.site.content.resource_from_path(afile.path) ref = self.site.content.resource_from_path(afile.path)
if not ref: 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 ref.is_processable = False
return self.template.get_include_statement(ref.relative_path) return self.template.get_include_statement(ref.relative_path)
text = self.import_finder.sub(import_to_include, text) text = self.import_finder.sub(import_to_include, text)
@@ -114,9 +114,11 @@ class LessCSSPlugin(CLTransformer):
try: try:
self.call_app(args) self.call_app(args)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
raise self.template.exception_class(
HydeException.reraise(
"Cannot process %s. Error occurred when " "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() return target.read_all()




@@ -155,7 +157,7 @@ class StylusPlugin(CLTransformer):


def import_to_include(match): 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: if not match.lastindex:
return '' return ''
@@ -172,7 +174,7 @@ class StylusPlugin(CLTransformer):
except AttributeError: except AttributeError:
include = False include = False
if not include: if not include:
raise self.template.exception_class(
raise HydeException(
"Cannot import from path [%s]" % afile.path) "Cannot import from path [%s]" % afile.path)
else: else:
ref.is_processable = False ref.is_processable = False
@@ -225,9 +227,10 @@ class StylusPlugin(CLTransformer):
try: try:
self.call_app(args) self.call_app(args)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
raise self.template.exception_class(
HydeException.reraise(
"Cannot process %s. Error occurred when " "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() return target.read_all()




@@ -291,8 +294,7 @@ class CleverCSSPlugin(Plugin):
afile = File(afile.path + '.ccss') afile = File(afile.path + '.ccss')
ref = self.site.content.resource_from_path(afile.path) ref = self.site.content.resource_from_path(afile.path)
if not ref: 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 ref.is_processable = False
return self.template.get_include_statement(ref.relative_path) return self.template.get_include_statement(ref.relative_path)
text = import_finder.sub(import_to_include, text) text = import_finder.sub(import_to_include, text)


+ 5
- 2
hyde/ext/plugins/js.py View File

@@ -3,7 +3,9 @@
JavaScript plugins JavaScript plugins
""" """
import subprocess import subprocess
import sys


from hyde.exceptions import HydeException
from hyde.plugin import CLTransformer from hyde.plugin import CLTransformer


from fswrap import File from fswrap import File
@@ -127,9 +129,10 @@ class RequireJSPlugin(CLTransformer):
try: try:
self.call_app(args) self.call_app(args)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
raise self.template.exception_class(
HydeException.reraise(
"Cannot process %s. Error occurred when " "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() return target.read_all()




+ 6
- 4
hyde/ext/plugins/meta.py View File

@@ -8,7 +8,9 @@ from functools import partial
from itertools import ifilter from itertools import ifilter
from operator import attrgetter from operator import attrgetter
import re import re
import sys


from hyde.exceptions import HydeException
from hyde.model import Expando from hyde.model import Expando
from hyde.plugin import Plugin from hyde.plugin import Plugin
from hyde.site import Node, Resource from hyde.site import Node, Resource
@@ -248,8 +250,9 @@ def get_tagger_sort_method(site):
try: try:
walker = getattr(content, walker) walker = getattr(content, walker)
except AttributeError: 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 return walker


def walk_resources_tagged_with(node, tag): def walk_resources_tagged_with(node, tag):
@@ -370,8 +373,7 @@ class TaggerPlugin(Plugin):
Generates archives for each tag based on the given configuration. Generates archives for each tag based on the given configuration.
""" """
if not 'template' in config: 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 content = self.site.content.source_folder
source = Folder(config.get('source', '')) source = Folder(config.get('source', ''))
target = content.child_folder(config.get('target', 'tags')) target = content.child_folder(config.get('target', 'tags'))


+ 21
- 10
hyde/ext/templates/jinja.py View File

@@ -4,11 +4,13 @@ Jinja template utilties
""" """


from datetime import datetime, date from datetime import datetime, date
import itertools
import os import os
import re import re
import itertools
import sys
from urllib import quote, unquote from urllib import quote, unquote


from hyde.exceptions import HydeException
from hyde.model import Expando from hyde.model import Expando
from hyde.template import HtmlWrap, Template from hyde.template import HtmlWrap, Template
from operator import attrgetter from operator import attrgetter
@@ -599,10 +601,20 @@ class HydeLoader(FileSystemLoader):
# #
template = template.replace(os.sep, '/') template = template.replace(os.sep, '/')
logger.debug("Loading template [%s] and preprocessing" % template) 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) 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: if self.preprocessor:
resource = self.site.content.resource_from_relative_path(template) resource = self.site.content.resource_from_relative_path(template)
if resource: if resource:
@@ -736,9 +748,11 @@ class Jinja2Template(Template):
from jinja2.meta import find_referenced_templates from jinja2.meta import find_referenced_templates
try: try:
ast = self.env.parse(text) 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) tpls = find_referenced_templates(ast)
deps = list(self.env.globals['deps'].get('path', [])) deps = list(self.env.globals['deps'].get('path', []))
for dep in tpls: for dep in tpls:
@@ -818,9 +832,6 @@ class Jinja2Template(Template):
template = self.env.get_template(resource.relative_path) template = self.env.get_template(resource.relative_path)
out = template.render(context) out = template.render(context)
except: except:
out = ""
logger.debug(self.env.loader.get_source(
self.env, resource.relative_path))
raise raise
return out return out




+ 10
- 7
hyde/generator.py View File

@@ -3,8 +3,9 @@
The generator class and related utility functions. The generator class and related utility functions.
""" """


from hyde.exceptions import HydeException
from commando.util import getLoggerWithNullHandler
from fswrap import File, Folder from fswrap import File, Folder
from hyde.exceptions import HydeException
from hyde.model import Context, Dependents from hyde.model import Context, Dependents
from hyde.plugin import Plugin from hyde.plugin import Plugin
from hyde.template import Template from hyde.template import Template
@@ -12,9 +13,9 @@ from hyde.site import Resource


from contextlib import contextmanager from contextlib import contextmanager
from datetime import datetime from datetime import datetime

from shutil import copymode from shutil import copymode
from commando.util import getLoggerWithNullHandler
import sys

logger = getLoggerWithNullHandler('hyde.engine') logger = getLoggerWithNullHandler('hyde.engine')




@@ -334,10 +335,12 @@ class Generator(object):
try: try:
text = self.template.render_resource(resource, text = self.template.render_resource(resource,
context) 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: else:
text = resource.source_file.read_all() text = resource.source_file.read_all()
text = self.events.begin_text_resource(resource, text) or text text = self.events.begin_text_resource(resource, text) or text


+ 9
- 11
hyde/plugin.py View File

@@ -12,6 +12,7 @@ import fnmatch
import os import os
import re import re
import subprocess import subprocess
import sys
import traceback import traceback


from commando.util import getLoggerWithNullHandler, load_python_object from commando.util import getLoggerWithNullHandler, load_python_object
@@ -56,18 +57,19 @@ class PluginProxy(object):
def __getattr__(self, method_name): def __getattr__(self, method_name):
if hasattr(Plugin, method_name): if hasattr(Plugin, method_name):
def __call_plugins__(*args): def __call_plugins__(*args):
# logger.debug("Calling plugin method [%s]", method_name)
res = None res = None
if self.site.plugins: if self.site.plugins:
for plugin in self.site.plugins: for plugin in self.site.plugins:
if hasattr(plugin, method_name): if hasattr(plugin, method_name):
# logger.debug(
# "\tCalling plugin [%s]",
# plugin.__class__.__name__)
checker = getattr(plugin, 'should_call__' + method_name) checker = getattr(plugin, 'should_call__' + method_name)
if checker(*args): if checker(*args):
function = getattr(plugin, method_name) 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) targs = list(args)
if len(targs): if len(targs):
last = targs.pop() last = targs.pop()
@@ -356,14 +358,11 @@ class CLTransformer(Plugin):
app_path = discover_executable(app_path, self.site.sitepath) app_path = discover_executable(app_path, self.site.sitepath)


if app_path is None: 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) app = File(app_path)


if not app.exists: if not app.exists:
raise self.template.exception_class(
self.executable_not_found_message)
raise HydeException(self.executable_not_found_message)


return app return app


@@ -418,7 +417,6 @@ class CLTransformer(Plugin):
(args[0], unicode(args[1:]))) (args[0], unicode(args[1:])))
return subprocess.check_output(args) return subprocess.check_output(args)
except subprocess.CalledProcessError, error: except subprocess.CalledProcessError, error:
self.logger.error(traceback.format_exc())
self.logger.error(error.output) self.logger.error(error.output)
raise raise




+ 3
- 3
hyde/server.py View File

@@ -162,7 +162,7 @@ class HydeWebServer(HTTPServer):
except Exception, exception: except Exception, exception:
logger.error('Error occured when regenerating the site [%s]' logger.error('Error occured when regenerating the site [%s]'
% exception.message) % exception.message)
logger.error(traceback.format_exc())
logger.debug(traceback.format_exc())


def generate_node(self, node): def generate_node(self, node):
""" """
@@ -180,7 +180,7 @@ class HydeWebServer(HTTPServer):
logger.error( logger.error(
'Error [%s] occured when generating the node [%s]' 'Error [%s] occured when generating the node [%s]'
% (repr(exception), node)) % (repr(exception), node))
logger.error(traceback.format_exc())
logger.debug(traceback.format_exc())


def generate_resource(self, resource): def generate_resource(self, resource):
""" """
@@ -199,4 +199,4 @@ class HydeWebServer(HTTPServer):
logger.error( logger.error(
'Error [%s] occured when serving the resource [%s]' 'Error [%s] occured when serving the resource [%s]'
% (repr(exception), resource)) % (repr(exception), resource))
logger.error(traceback.format_exc())
logger.debug(traceback.format_exc())

+ 1
- 1
hyde/version.py View File

@@ -2,4 +2,4 @@
""" """
Handles hyde version. Handles hyde version.
""" """
__version__ = '0.8.7a5'
__version__ = '0.8.7a6'

+ 3
- 3
requirements.txt View File

@@ -1,8 +1,8 @@
fswrap==0.1.1 fswrap==0.1.1
commando==0.3.2a
commando==0.3.4
PyYAML==3.10 PyYAML==3.10
Markdown==2.3.1 Markdown==2.3.1
MarkupSafe==0.15
MarkupSafe==0.18
Pygments==1.6 Pygments==1.6
typogrify==2.0.0 typogrify==2.0.0
Jinja2==2.6
Jinja2==2.7

+ 3
- 3
setup.py View File

@@ -117,13 +117,13 @@ setup(name=PROJECT,
requires=['python (>= 2.7)'], requires=['python (>= 2.7)'],
install_requires=( install_requires=(
'fswrap==0.1.1', 'fswrap==0.1.1',
'commando==0.3.2a',
'commando==0.3.4',
'PyYAML==3.10', 'PyYAML==3.10',
'Markdown==2.3.1', 'Markdown==2.3.1',
'MarkupSafe==0.15',
'MarkupSafe==0.18',
'Pygments==1.6', 'Pygments==1.6',
'typogrify==2.0.0', 'typogrify==2.0.0',
'Jinja2==2.6'
'Jinja2==2.7'
), ),
tests_require=( tests_require=(
'nose', 'mock' 'nose', 'mock'


Loading…
Cancel
Save