From 4bea6dc59eeab5643f68b2640a8e73d3049aff26 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Mon, 16 Feb 2015 14:27:18 -0800 Subject: [PATCH] distinguish IOError when loading file from that raised by program itself Previously, Hy scripts that raised a subclass of IOError would be caught by code intended to deal with IOErrors raised when Hy couldn't import the script itself, resulting in either a misleading "Can't open file" error message, or a misleading TypeError traceback from not being able to format the "Can't open file" message (for IOErrors for which the errno attribute was None). This commit (a straightforward implementation of the idea proposed by @slimetree in #714) introduces a new HyIOError class, raises that when `import_file_to_hst` can't open the file path, and catches it in the `cmdline_handler`. This is believed to fix #513, #714, and #727. --- hy/cmdline.py | 8 +++++--- hy/errors.py | 8 ++++++++ hy/importer.py | 8 ++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/hy/cmdline.py b/hy/cmdline.py index 507773a..f4cb94e 100644 --- a/hy/cmdline.py +++ b/hy/cmdline.py @@ -43,6 +43,8 @@ from hy.importer import (ast_compile, import_buffer_to_module, from hy.completer import completion from hy.completer import Completer +from hy.errors import HyIOError + from hy.macros import macro, require from hy.models.expression import HyExpression from hy.models.string import HyString @@ -324,10 +326,10 @@ def cmdline_handler(scriptname, argv): # User did "hy " try: return run_file(options.args[0]) - except IOError as x: + except HyIOError as e: sys.stderr.write("hy: Can't open file '%s': [Errno %d] %s\n" % - (x.filename, x.errno, x.strerror)) - sys.exit(x.errno) + (e.filename, e.errno, e.strerror)) + sys.exit(e.errno) # User did NOTHING! return run_repl(spy=options.spy) diff --git a/hy/errors.py b/hy/errors.py index 5f8e562..e8bc2a8 100644 --- a/hy/errors.py +++ b/hy/errors.py @@ -111,3 +111,11 @@ class HyTypeError(TypeError): class HyMacroExpansionError(HyTypeError): pass + + +class HyIOError(HyError, IOError): + """ + Trivial subclass of IOError and HyError, to distinguish between + IOErrors thrown by Hy itself as opposed to Hy programs. + """ + pass diff --git a/hy/importer.py b/hy/importer.py index a81d27b..b12fb8b 100644 --- a/hy/importer.py +++ b/hy/importer.py @@ -22,6 +22,7 @@ from hy.compiler import hy_compile, HyTypeError from hy.models import HyObject from hy.lex import tokenize, LexException +from hy.errors import HyIOError from io import open import marshal @@ -49,8 +50,11 @@ def import_buffer_to_hst(buf): def import_file_to_hst(fpath): """Import content from fpath and return an Hy AST.""" - with open(fpath, 'r', encoding='utf-8') as f: - return import_buffer_to_hst(f.read()) + try: + with open(fpath, 'r', encoding='utf-8') as f: + return import_buffer_to_hst(f.read()) + except IOError as e: + raise HyIOError(e.errno, e.strerror, e.filename) def import_buffer_to_ast(buf, module_name):