Merge pull request #1500 from vodik/deprecations
Deal with some deprecation and resource warnings / fix (return) semantics
This commit is contained in:
commit
c1e5c3e48c
2
Makefile
2
Makefile
@ -64,7 +64,7 @@ ifeq (Python 2.6,$(findstring Python 2.6,$(shell python -V 2>&1)))
|
||||
endif
|
||||
$(pip) install -r requirements-travis.txt
|
||||
$(pip) install coveralls
|
||||
$(pip) install --allow-all-external -e .
|
||||
$(pip) install -e .
|
||||
|
||||
coveralls:
|
||||
$(coveralls)
|
||||
|
7
NEWS.rst
7
NEWS.rst
@ -1,5 +1,12 @@
|
||||
.. default-role:: code
|
||||
|
||||
Unreleased
|
||||
==============================
|
||||
|
||||
Bug Fixes
|
||||
------------------------------
|
||||
* Fix `(return)` so it works correctly to exit a Python 2 generator
|
||||
|
||||
0.14.0
|
||||
==============================
|
||||
|
||||
|
@ -16,6 +16,7 @@ from hy._compat import (
|
||||
raise_empty)
|
||||
from hy.macros import require, macroexpand, tag_macroexpand
|
||||
import hy.importer
|
||||
import hy.inspect
|
||||
|
||||
import traceback
|
||||
import importlib
|
||||
@ -24,7 +25,6 @@ import ast
|
||||
import sys
|
||||
import keyword
|
||||
import copy
|
||||
import inspect
|
||||
|
||||
from collections import defaultdict
|
||||
from cmath import isnan
|
||||
@ -441,10 +441,11 @@ class HyASTCompiler(object):
|
||||
# _compile_table[atom_type] is a method for compiling this
|
||||
# type of atom, so call it. If it has an extra parameter,
|
||||
# pass in `atom_type`.
|
||||
arity = len(inspect.getargspec(_compile_table[atom_type])[0])
|
||||
ret = (_compile_table[atom_type](self, atom, atom_type)
|
||||
atom_compiler = _compile_table[atom_type]
|
||||
arity = hy.inspect.get_arity(atom_compiler)
|
||||
ret = (atom_compiler(self, atom, atom_type)
|
||||
if arity == 3
|
||||
else _compile_table[atom_type](self, atom))
|
||||
else atom_compiler(self, atom))
|
||||
if not isinstance(ret, Result):
|
||||
ret = Result() + ret
|
||||
return ret
|
||||
@ -2040,8 +2041,10 @@ class HyASTCompiler(object):
|
||||
@checkargs(max=1)
|
||||
def compile_return(self, expr):
|
||||
ret = Result()
|
||||
if len(expr) > 1:
|
||||
ret += self.compile(expr[1])
|
||||
if len(expr) == 1:
|
||||
return asty.Return(expr, value=None)
|
||||
|
||||
ret += self.compile(expr[1])
|
||||
return ret + asty.Return(expr, value=ret.force_expr)
|
||||
|
||||
@builds("defclass")
|
||||
|
@ -29,15 +29,15 @@
|
||||
(try (while True
|
||||
(yield (get self index))
|
||||
(setv index (inc index)))
|
||||
(except [_ IndexError]
|
||||
(raise StopIteration))))
|
||||
(except [IndexError]
|
||||
(return))))
|
||||
--len-- (fn [self]
|
||||
"length of the sequence, dangerous for infinite sequences"
|
||||
(setv index (. self high-water))
|
||||
(try (while True
|
||||
(get self index)
|
||||
(setv index (inc index)))
|
||||
(except [_ IndexError]
|
||||
(except [IndexError]
|
||||
(len (. self cache)))))
|
||||
max-items-in-repr 10
|
||||
--str-- (fn [self]
|
||||
|
@ -422,7 +422,10 @@ Raises ValueError for (not (pos? n))."
|
||||
(for* [val citer]
|
||||
(yield val)
|
||||
(for* [_ (range skip)]
|
||||
(next citer))))
|
||||
(try
|
||||
(next citer)
|
||||
(except [StopIteration]
|
||||
(return))))))
|
||||
|
||||
(defn zero? [n]
|
||||
"Check if `n` equals 0."
|
||||
|
@ -2,6 +2,8 @@
|
||||
# This file is part of Hy, which is free software licensed under the Expat
|
||||
# license. See the LICENSE.
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from hy.compiler import hy_compile, HyTypeError
|
||||
from hy.models import HyObject, HyExpression, HySymbol, replace_hy_obj
|
||||
from hy.lex import tokenize, LexException
|
||||
|
37
hy/inspect.py
Normal file
37
hy/inspect.py
Normal file
@ -0,0 +1,37 @@
|
||||
# Copyright 2018 the authors.
|
||||
# This file is part of Hy, which is free software licensed under the Expat
|
||||
# license. See the LICENSE.
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import inspect
|
||||
|
||||
try:
|
||||
# Check if we have the newer inspect.signature available.
|
||||
# Otherwise fallback to the legacy getargspec.
|
||||
inspect.signature # noqa
|
||||
except AttributeError:
|
||||
def get_arity(fn):
|
||||
return len(inspect.getargspec(fn)[0])
|
||||
|
||||
def has_kwargs(fn):
|
||||
argspec = inspect.getargspec(fn)
|
||||
return argspec.keywords is not None
|
||||
|
||||
def format_args(fn):
|
||||
argspec = inspect.getargspec(fn)
|
||||
return inspect.formatargspec(*argspec)
|
||||
|
||||
else:
|
||||
def get_arity(fn):
|
||||
parameters = inspect.signature(fn).parameters
|
||||
return sum(1 for param in parameters.values()
|
||||
if param.kind == param.POSITIONAL_OR_KEYWORD)
|
||||
|
||||
def has_kwargs(fn):
|
||||
parameters = inspect.signature(fn).parameters
|
||||
return any(param.kind == param.VAR_KEYWORD
|
||||
for param in parameters.values())
|
||||
|
||||
def format_args(fn):
|
||||
return str(inspect.signature(fn))
|
10
hy/macros.py
10
hy/macros.py
@ -2,9 +2,8 @@
|
||||
# This file is part of Hy, which is free software licensed under the Expat
|
||||
# license. See the LICENSE.
|
||||
|
||||
from inspect import getargspec, formatargspec
|
||||
import hy.inspect
|
||||
from hy.models import replace_hy_obj, HyExpression, HySymbol
|
||||
|
||||
from hy.errors import HyTypeError, HyMacroExpansionError
|
||||
|
||||
from collections import defaultdict
|
||||
@ -36,8 +35,7 @@ def macro(name):
|
||||
def _(fn):
|
||||
fn.__name__ = '({})'.format(name)
|
||||
try:
|
||||
argspec = getargspec(fn)
|
||||
fn._hy_macro_pass_compiler = argspec.keywords is not None
|
||||
fn._hy_macro_pass_compiler = hy.inspect.has_kwargs(fn)
|
||||
except Exception:
|
||||
# An exception might be raised if fn has arguments with
|
||||
# names that are invalid in Python.
|
||||
@ -136,9 +134,7 @@ def make_empty_fn_copy(fn):
|
||||
# can continue running. Unfortunately, the error message that might get
|
||||
# raised later on while expanding a macro might not make sense at all.
|
||||
|
||||
argspec = getargspec(fn)
|
||||
formatted_args = formatargspec(*argspec)
|
||||
|
||||
formatted_args = hy.inspect.format_args(fn)
|
||||
fn_str = 'lambda {}: None'.format(
|
||||
formatted_args.lstrip('(').rstrip(')'))
|
||||
empty_fn = eval(fn_str)
|
||||
|
@ -20,3 +20,6 @@ ignore_errors = True
|
||||
# Be sure to include Hy test functions whose names end with "?",
|
||||
# which will be mangled to begin with "is_".
|
||||
python_functions=test_* is_test_*
|
||||
filterwarnings =
|
||||
once::DeprecationWarning
|
||||
once::PendingDeprecationWarning
|
||||
|
@ -8,7 +8,7 @@ from __future__ import unicode_literals
|
||||
from hy import HyString
|
||||
from hy.models import HyObject
|
||||
from hy.compiler import hy_compile
|
||||
from hy.importer import import_buffer_to_hst
|
||||
from hy.importer import hy_eval, import_buffer_to_hst
|
||||
from hy.errors import HyCompileError, HyTypeError
|
||||
from hy.lex.exceptions import LexException
|
||||
from hy._compat import PY3
|
||||
@ -30,6 +30,10 @@ def can_compile(expr):
|
||||
return hy_compile(import_buffer_to_hst(expr), "__main__")
|
||||
|
||||
|
||||
def can_eval(expr):
|
||||
return hy_eval(import_buffer_to_hst(expr))
|
||||
|
||||
|
||||
def cant_compile(expr):
|
||||
try:
|
||||
hy_compile(import_buffer_to_hst(expr), "__main__")
|
||||
@ -664,3 +668,8 @@ def test_ast_good_yield_from():
|
||||
def test_ast_bad_yield_from():
|
||||
"Make sure AST can't compile invalid yield-from"
|
||||
cant_compile("(yield-from)")
|
||||
|
||||
|
||||
def test_eval_generator_with_return():
|
||||
"""Ensure generators with a return statement works."""
|
||||
can_eval("(fn [] (yield 1) (yield 2) (return))")
|
||||
|
@ -37,19 +37,9 @@ def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False):
|
||||
universal_newlines=True,
|
||||
shell=False,
|
||||
env=env)
|
||||
if stdin_data is not None:
|
||||
p.stdin.write(stdin_data)
|
||||
p.stdin.flush()
|
||||
p.stdin.close()
|
||||
# Read stdout and stderr otherwise if the PIPE buffer is full, we might
|
||||
# wait for ever…
|
||||
stdout = ""
|
||||
stderr = ""
|
||||
while p.poll() is None:
|
||||
stdout += p.stdout.read()
|
||||
stderr += p.stderr.read()
|
||||
assert p.returncode == expect
|
||||
return stdout, stderr
|
||||
output = p.communicate(input=stdin_data)
|
||||
assert p.wait() == expect
|
||||
return output
|
||||
|
||||
|
||||
def rm(fpath):
|
||||
|
@ -304,11 +304,11 @@ def test_nospace():
|
||||
|
||||
def test_escapes():
|
||||
""" Ensure we can escape things """
|
||||
entry = tokenize("(foo \"foo\\n\")")[0]
|
||||
entry = tokenize(r"""(foo "foo\n")""")[0]
|
||||
assert entry[1] == "foo\n"
|
||||
|
||||
entry = tokenize("(foo \"foo\\s\")")[0]
|
||||
assert entry[1] == "foo\\s"
|
||||
entry = tokenize(r"""(foo r"foo\s")""")[0]
|
||||
assert entry[1] == r"foo\s"
|
||||
|
||||
|
||||
def test_unicode_escapes():
|
||||
|
Loading…
Reference in New Issue
Block a user