Importing or executing a Hy file now loads the byte-compiled version if it exists and is up to date, and if not, the source is byte-compiled after it's parsed.
This change can speed up Hy a lot. Here are some examples comparing run times of the current master (491b474e) to this commit, on my laptop with Python 3.6:
- `nosetests --exclude='test_bin'` goes from 3.8 s to 0.7 s (a 5-fold speedup)
- `hy -c '(print "hello world")` goes from 0.47 s to 0.20 s (a 2-fold speedup)
- Rogue TV's startup goes from 3.6 s to 0.4 s (a 9-fold speedup)
Accompanying changes include:
- `setup.py` now creates and installs bytecode for `hy.core`, `hy.contrib`, and `hy.extra`.
- The `hyc` command under Python 3 now creates bytecode in `__pycache__`, as usual for Python 3, instead of putting the `.pyc` right next to the source file like Python 2 does.
I've removed a test of `hy.extra.anaphoric.a-if` that triggers #1268 when the test file is byte-compiled and then hits some weird `macroexpand` bug or something when I try to work around that—Nose crashes when trying to produce an error message, and I can't seem to replicate the bug without Nose.
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.
Currently '.replace' method is used to replace hy objects. This is not
safe when we are not sure if the 'obj' in 'obj.replace(other)' is an
instance of HyObject.
In these cases, we can use function 'replace_hy_obj(obj, other)'
instead. This function will try to wrap 'obj' if it's not an instance of
HyObject.
This also means that we need a wrapping function in hy.models'. Hence I
moved the '_wrap_value' function from hy.macros into hy.models. To avoid
circular importing, the wrapper functions are provided individually by
each model type's own file.
Our MetaImporter was being inserted at the end of sys.meta_path.
For Python prior to 3.3, this was fine since sys.meta_path
was empty by default. As of the completion of PEP 302 in Py3.3 and
later, there are several importers registered by default. One of
these was trying (and failing) to import simple Hy modules,
resulting in a failure to import anything inside __init__.hy.
This change simply inserts the Hy-specific importer at the front
of the list.
This was noted in issue #620 (great catch @algernon)
This version is much simpler.
At the point that the exception is raised, we don't have access to
the actual source, just the current expression. but as the
exception percolates up, we can intercept it, add the source and
the re-raise it.
Then at the final point, in the cmdline handler, we can choose to
let the entire traceback print, or just the simpler, direct error
message.
And even with the full traceback, the last bit is nicely formatted
just like the shorter, simpler message.
The error message is colored if clint is installed, but to avoid
yet another dependency, you get monochrome without clint.
I'm sure there is a better way to do the markup, the current method
is kludgy but works.
I wish there was more shared code between HyTypeError and LexException
but they are kind of different in some fundamental ways.
This doesn't work (yet) with runtime errors generated from Python,
like NameError, but I have a method that can catch NameError and turn it
into a more pleasing output.
Finally, there is no obvious way to raise HyTypeError from pure Hy code,
so methods in core/language.hy throw ugly TypeError/ValueError.
There was a couple of duplicate imports and type checkings in the
codebase. So I added a new module to unify all Python 2 and 3
compatibility codes.
Also, this is a somewhat common pattern in Python. See Jinja2 for
example:
https://github.com/mitsuhiko/jinja2/blob/master/jinja2/_compat.py
A macro is available in the module where it was defined and
in any module that does a require of the defining module.
Only macros defined in hy.core are globally available.
Fixes#181
We compile the evaluated operand, separating the body (statements)
from the expression. We then eval() those separately, and return
the evaluated expression.
Fixes#106
Note: This is implemented by replacing all calls to Python's
builtin "compile" function by calls to hy.importer.compile_,
which adds the "future division" flag. Anyone using "compile"
in future work will have to remember this.
We can know use any amount and type of bytes to build a HyString, meaning we
can use Unicode and UTF-8 for our function and variables.
Eat that, snake!
Signed-off-by: Julien Danjou <julien@danjou.info>