diff --git a/.gitignore b/.gitignore
index f1cb8d0..503fc27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,4 @@
dist
.coverage
build/
-.noseids
+/.cache
diff --git a/.travis.yml b/.travis.yml
index bd99240..f93fb74 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,23 +1,18 @@
sudo: false
language: python
-matrix:
- include:
- - python: 3.5
- env: TOXENV=py35
- - python: 3.6-dev
- env: TOXENV=py36
-env:
- - TOXENV=py27
- - TOXENV=py33
- - TOXENV=py34
- - TOXENV=pypy
- - TOXENV=flake8
-install: pip install tox
-script: tox
-cache:
- directories:
- - .tox
- - $HOME/.cache/pip
+python:
+ - "2.7"
+ - "3.3"
+ - "3.4"
+ - "3.5"
+ - "3.6"
+ - pypy
+install:
+ - pip install --upgrade pytest
+ - pip install -r requirements-travis.txt
+ - pip install -e .
+script: pytest
+cache: pip
after_success: make coveralls
notifications:
email:
diff --git a/Makefile b/Makefile
index 7913fea..1b618a7 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,6 @@ pip_url=https://bootstrap.pypa.io/get-pip.py
python=python
pip=pip
coveralls=coveralls
-nose=nosetests
all:
@echo "No default step. Use setup.py"
@@ -41,7 +40,7 @@ endif
dev: test flake
test: venv
- nosetests -sv
+ pytest
tox: venv
tox
diff --git a/conftest.py b/conftest.py
new file mode 100644
index 0000000..72fa553
--- /dev/null
+++ b/conftest.py
@@ -0,0 +1,13 @@
+import _pytest
+import hy
+from hy._compat import PY3
+
+def pytest_collect_file(parent, path):
+ if (path.ext == ".hy"
+ and "/tests/native_tests/" in path.dirname + "/"
+ and path.basename != "__init__.hy"
+ and not ("py3_only" in path.basename and not PY3)):
+ m = _pytest.python.pytest_pycollect_makemodule(path, parent)
+ # Spoof the module name to avoid hitting an assertion in pytest.
+ m.name = m.name[:-len(".hy")] + ".py"
+ return m
diff --git a/docs/hacking.rst b/docs/hacking.rst
index 4042208..707745d 100644
--- a/docs/hacking.rst
+++ b/docs/hacking.rst
@@ -62,12 +62,11 @@ Do this:
Test!
=====
-Tests are located in ``tests/``. We use `nose
-`_.
+Tests are located in ``tests/``. We use `pytest `_.
To run the tests::
- $ nosetests
+ $ pytest
Write tests---tests are good!
diff --git a/hy/importer.py b/hy/importer.py
index 1db67e3..f49129c 100644
--- a/hy/importer.py
+++ b/hy/importer.py
@@ -30,7 +30,6 @@ import marshal
import struct
import imp
import sys
-import platform
import ast
import os
import __future__
@@ -114,17 +113,13 @@ def import_file_to_module(module_name, fpath, loader=None):
module = imp.new_module(module_name)
module.__file__ = fpath
code = ast_compile(_ast, fpath, "exec")
- if not (platform.python_implementation() == 'PyPy' and
- 'nosetests' in sys.argv[0] and
- is_package(module_name)):
- # Nose can generate spurious errors in this specific situation.
- try:
- write_code_as_pyc(fpath, code)
- except (IOError, OSError):
- # We failed to save the bytecode, probably because of a
- # permissions issue. The user only asked to import the
- # file, so don't bug them about it.
- pass
+ try:
+ write_code_as_pyc(fpath, code)
+ except (IOError, OSError):
+ # We failed to save the bytecode, probably because of a
+ # permissions issue. The user only asked to import the
+ # file, so don't bug them about it.
+ pass
eval(code, module.__dict__)
except (HyTypeError, LexException) as e:
if e.source is None:
@@ -136,9 +131,9 @@ def import_file_to_module(module_name, fpath, loader=None):
sys.modules.pop(module_name, None)
raise
sys.modules[module_name] = module
- module.__file__ = fpath
module.__name__ = module_name
+ module.__file__ = fpath
if loader:
module.__loader__ = loader
if is_package(module_name):
diff --git a/make.bat b/make.bat
index 2551ea2..1a010bc 100644
--- a/make.bat
+++ b/make.bat
@@ -55,7 +55,7 @@ goto :EOF
if "%1" == "test" (
:test
call :venv
- nosetests -sv
+ pytest -sv
goto :EOF
)
diff --git a/requirements-dev.txt b/requirements-dev.txt
index 63b9481..4e197a9 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -1,6 +1,6 @@
-r requirements-travis.txt
# test tools
-nose
+pytest
tox
# documentation
diff --git a/setup.cfg b/setup.cfg
index 31c8825..3923777 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,9 +1,3 @@
-[nosetests]
-detailed-errors=1
-with-coverage=1
-cover-package=hy
-nocapture=1
-
[wheel]
universal = 1
@@ -12,7 +6,6 @@ omit =
*/python?.?/*
*/lib-python/?.?/*.py
*/lib_pypy/_*.py
- */site-packages/nose/*
*/pypy/*
[coverage:report]
@@ -22,3 +15,8 @@ exclude_lines =
# We want ignore_errors so we don't get NoSource warnings for loading
# byte-compiled Hy modules.
ignore_errors = True
+
+[tool:pytest]
+# Be sure to include Hy test functions whose names end with "?",
+# which will be mangled to begin with "is_".
+python_functions=test_* is_test_*
diff --git a/tests/__init__.py b/tests/__init__.py
index 1fbc6c6..e69de29 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,25 +0,0 @@
-
-import hy # noqa
-from hy._compat import PY3
-from .native_tests.cons import * # noqa
-from .native_tests.defclass import * # noqa
-from .native_tests.mathematics import * # noqa
-from .native_tests.native_macros import * # noqa
-from .native_tests.quote import * # noqa
-from .native_tests.language import * # noqa
-from .native_tests.unless import * # noqa
-from .native_tests.when import * # noqa
-from .native_tests.with_decorator import * # noqa
-from .native_tests.core import * # noqa
-from .native_tests.sharp_macros import * # noqa
-from .native_tests.operators import * # noqa
-from .native_tests.with_test import * # noqa
-from .native_tests.extra.anaphoric import * # noqa
-from .native_tests.contrib.loop import * # noqa
-from .native_tests.contrib.walk import * # noqa
-from .native_tests.contrib.multi import * # noqa
-from .native_tests.contrib.sequences import * # noqa
-from .native_tests.contrib.hy_repr import * # noqa
-
-if PY3:
- from .native_tests.py3_only_tests import * # noqa
diff --git a/tests/compilers/native/__init__.hy b/tests/compilers/native/__init__.hy
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/compilers/native/quoting.hy b/tests/compilers/native/quoting.hy
deleted file mode 100644
index c74bb5a..0000000
--- a/tests/compilers/native/quoting.hy
+++ /dev/null
@@ -1,11 +0,0 @@
-;;;
-;;;
-
-(import [hy [HyExpression HySymbol HyString HyBytes]])
-
-
-(defn test-basic-quoting []
- (assert (= (type (quote (foo bar))) HyExpression))
- (assert (= (type (quote foo)) HySymbol))
- (assert (= (type (quote "string")) HyString))
- (assert (= (type (quote b"string")) HyBytes)))
diff --git a/tests/compilers/test_compiler.py b/tests/compilers/test_compiler.py
index 3f1b397..a6253b4 100644
--- a/tests/compilers/test_compiler.py
+++ b/tests/compilers/test_compiler.py
@@ -20,96 +20,85 @@
# DEALINGS IN THE SOFTWARE.
import ast
-import sys
from hy import compiler
from hy.models import HyExpression, HyList, HySymbol, HyInteger
from hy._compat import PY3
-if sys.version_info[0] <= 2 and sys.version_info[1] <= 6:
- import unittest2 as unittest
-else:
- import unittest
+
+def test_builds_with_dash():
+ assert callable(compiler.builds("foobar"))
+ assert callable(compiler.builds("foo_bar"))
+ assert callable(compiler.builds("-"))
+ try:
+ compiler.builds("foobar-with-dash-")
+ except TypeError as e:
+ assert "*post* translated strings" in str(e)
+ else:
+ assert False
-class CompilerTest(unittest.TestCase):
-
- def test_builds_with_dash(self):
- self.assert_(callable(compiler.builds("foobar")))
- self.assert_(callable(compiler.builds("foo_bar")))
- self.assert_(callable(compiler.builds("-")))
- self.assertRaisesRegexp(TypeError,
- r"\*post\* translated strings",
- compiler.builds, "foobar-with-dash-")
+def make_expression(*args):
+ h = HyExpression(args)
+ h.start_line = 1
+ h.end_line = 1
+ h.start_column = 1
+ h.end_column = 1
+ return h.replace(h)
-class HyASTCompilerTest(unittest.TestCase):
+def test_compiler_bare_names():
+ """
+ Check that the compiler doesn't drop bare names from code branches
+ """
+ e = make_expression(HySymbol("do"),
+ HySymbol("a"),
+ HySymbol("b"),
+ HySymbol("c"))
+ ret = compiler.HyASTCompiler('test').compile(e)
- @staticmethod
- def _make_expression(*args):
- h = HyExpression(args)
- h.start_line = 1
- h.end_line = 1
- h.start_column = 1
- h.end_column = 1
- return h.replace(h)
+ # We expect two statements and a final expr.
- def setUp(self):
- self.c = compiler.HyASTCompiler('test')
+ assert len(ret.stmts) == 2
+ for stmt, symbol in zip(ret.stmts, "ab"):
+ assert isinstance(stmt, ast.Expr)
+ assert isinstance(stmt.value, ast.Name)
+ assert stmt.value.id == symbol
- def test_compiler_bare_names(self):
- """
- Check that the compiler doesn't drop bare names from code branches
- """
- ret = self.c.compile(self._make_expression(HySymbol("do"),
- HySymbol("a"),
- HySymbol("b"),
- HySymbol("c")))
+ assert isinstance(ret.expr, ast.Name)
+ assert ret.expr.id == "c"
- # We expect two statements and a final expr.
- self.assertEqual(len(ret.stmts), 2)
- stmt = ret.stmts[0]
- self.assertIsInstance(stmt, ast.Expr)
- self.assertIsInstance(stmt.value, ast.Name)
- self.assertEqual(stmt.value.id, "a")
- stmt = ret.stmts[1]
- self.assertIsInstance(stmt, ast.Expr)
- self.assertIsInstance(stmt.value, ast.Name)
- self.assertEqual(stmt.value.id, "b")
- expr = ret.expr
- self.assertIsInstance(expr, ast.Name)
- self.assertEqual(expr.id, "c")
- def test_compiler_yield_return(self):
- """
- Check that the compiler correctly generates return statements for
- a generator function. In Python versions prior to 3.3, the return
- statement in a generator can't take a value, so the final expression
- should not generate a return statement. From 3.3 onwards a return
- value should be generated.
- """
- ret = self.c.compile_function_def(
- self._make_expression(HySymbol("fn"),
- HyList(),
- HyExpression([HySymbol("yield"),
- HyInteger(2)]),
- HyExpression([HySymbol("+"),
- HyInteger(1),
- HyInteger(1)])))
+def test_compiler_yield_return():
+ """
+ Check that the compiler correctly generates return statements for
+ a generator function. In Python versions prior to 3.3, the return
+ statement in a generator can't take a value, so the final expression
+ should not generate a return statement. From 3.3 onwards a return
+ value should be generated.
+ """
+ e = make_expression(HySymbol("fn"),
+ HyList(),
+ HyExpression([HySymbol("yield"),
+ HyInteger(2)]),
+ HyExpression([HySymbol("+"),
+ HyInteger(1),
+ HyInteger(1)]))
+ ret = compiler.HyASTCompiler('test').compile_function_def(e)
- self.assertEqual(len(ret.stmts), 1)
- stmt = ret.stmts[0]
- self.assertIsInstance(stmt, ast.FunctionDef)
- body = stmt.body
- self.assertEquals(len(body), 2)
- self.assertIsInstance(body[0], ast.Expr)
- self.assertIsInstance(body[0].value, ast.Yield)
+ assert len(ret.stmts) == 1
+ stmt, = ret.stmts
+ assert isinstance(stmt, ast.FunctionDef)
+ body = stmt.body
+ assert len(body) == 2
+ assert isinstance(body[0], ast.Expr)
+ assert isinstance(body[0].value, ast.Yield)
- if PY3:
- # From 3.3+, the final statement becomes a return value
- self.assertIsInstance(body[1], ast.Return)
- self.assertIsInstance(body[1].value, ast.BinOp)
- else:
- # In earlier versions, the expression is not returned
- self.assertIsInstance(body[1], ast.Expr)
- self.assertIsInstance(body[1].value, ast.BinOp)
+ if PY3:
+ # From 3.3+, the final statement becomes a return value
+ assert isinstance(body[1], ast.Return)
+ assert isinstance(body[1].value, ast.BinOp)
+ else:
+ # In earlier versions, the expression is not returned
+ assert isinstance(body[1], ast.Expr)
+ assert isinstance(body[1].value, ast.BinOp)
diff --git a/tests/compilers/test_quoting.py b/tests/compilers/test_quoting.py
deleted file mode 100644
index fb83d8d..0000000
--- a/tests/compilers/test_quoting.py
+++ /dev/null
@@ -1 +0,0 @@
-from .native.quoting import * # NOQA
diff --git a/tests/native_tests/extra/reserved.hy b/tests/native_tests/extra/reserved.hy
index cfe236f..7990c6b 100644
--- a/tests/native_tests/extra/reserved.hy
+++ b/tests/native_tests/extra/reserved.hy
@@ -1,4 +1,4 @@
-(import [hy.extra.reserved [names] hy._compat [PY3]])
+(import [hy.extra.reserved [names]] [hy._compat [PY3]])
(defn test-reserved []
(assert (is (type (names)) frozenset))
diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy
index 704bd5d..fbf7ce4 100644
--- a/tests/native_tests/language.hy
+++ b/tests/native_tests/language.hy
@@ -2,7 +2,8 @@
[os.path [exists isdir isfile]]
[sys :as systest]
[operator [or_]]
- [hy.errors [HyTypeError]])
+ [hy.errors [HyTypeError]]
+ pytest)
(import sys)
(import [hy._compat [PY3 PY34 PY35]])
@@ -686,20 +687,6 @@
(assert (= (cut [1 2 3 4 5]) [1 2 3 4 5])))
-(defn test-take []
- "NATIVE: test take"
- (assert (= (take 0 [2 3]) []))
- (assert (= (take 1 [2 3]) [2]))
- (assert (= (take 2 [2 3]) [2 3])))
-
-
-(defn test-drop []
- "NATIVE: test drop"
- (assert (= (list (drop 0 [2 3])) [2 3]))
- (assert (= (list (drop 1 [2 3])) [3]))
- (assert (= (list (drop 2 [2 3])) [])))
-
-
(defn test-rest []
"NATIVE: test rest"
(assert (= (list (rest [1 2 3 4 5])) [2 3 4 5]))
@@ -1175,7 +1162,7 @@
(defn test-try-except-return []
- "NATIVE: test we can return from in a try except"
+ "NATIVE: test that we can return from an `except` form"
(assert (= ((fn [] (try xxx (except [NameError] (+ 1 1))))) 2))
(setv foo (try xxx (except [NameError] (+ 1 1))))
(assert (= foo 2))
@@ -1183,6 +1170,21 @@
(assert (= foo 4)))
+#@(pytest.mark.xfail
+(defn test-try-else-return []
+ "NATIVE: test that we can return from the `else` clause of a `try`"
+ ; https://github.com/hylang/hy/issues/798
+ (assert (= "ef" ((fn []
+ (try (+ "a" "b")
+ (except [NameError] (+ "c" "d"))
+ (else (+ "e" "f")))))))
+ (setv foo
+ (try (+ "A" "B")
+ (except [NameError] (+ "C" "D"))
+ (else (+ "E" "F"))))
+ (assert (= foo "EF"))))
+
+
(defn test-require []
"NATIVE: test requiring macros from python code"
(try (qplah 1 2 3 4)
@@ -1252,13 +1254,6 @@
(assert (= "test" (:foo {:foo "test"}))))
-(defn test-take []
- "NATIVE: test the take operator"
- (assert (= [1 2 3] (list (take 3 [1 2 3]))))
- (assert (= [1 2 3] (list (take 4 [1 2 3]))))
- (assert (= [1 2] (list (take 2 [1 2 4])))))
-
-
(defn test-break-breaking []
"NATIVE: test checking if break actually breaks"
(defn holy-grail [] (for [x (range 10)] (if (= x 5) (break))) x)
@@ -1309,6 +1304,13 @@
(assert (= (macroexpand '(-> (a b) (-> (c d) (e f))))
'(e (c (a b) d) f))))
+#@(pytest.mark.xfail
+(defn test-macroexpand-with-named-import []
+ ; https://github.com/hylang/hy/issues/1207
+ (defmacro m-with-named-import []
+ (import [math [pow]])
+ (pow 2 3))
+ (assert (= (macroexpand '(m-with-named-import)) (** 2 3)))))
(defn test-macroexpand-1 []
"Test macroexpand-1 on ->"
@@ -1336,8 +1338,7 @@
(defn test-calling-module-name []
"NATIVE: Test the calling-module-name function"
- (assert (= (calling-module-name -1) "hy.core.language"))
- (assert (= (calling-module-name 0) "tests.native_tests.language")))
+ (assert (= (calling-module-name -1) "hy.core.language")))
(defn test-disassemble []
diff --git a/tests/native_tests/operators.hy b/tests/native_tests/operators.hy
index 1f60650..9ee5c12 100644
--- a/tests/native_tests/operators.hy
+++ b/tests/native_tests/operators.hy
@@ -1,4 +1,4 @@
-(import [hy._compat [PY35]])
+(import pytest [hy._compat [PY35]])
(defmacro op-and-shadow-test [op &rest body]
; Creates two tests with the given `body`, one where all occurrences
@@ -284,3 +284,8 @@
(assert (is (f 3 [1 2]) (!= f-name "in")))
(assert (is (f 2 [1 2]) (= f-name "in")))
(forbid (f 2 [1 2] [3 4])))
+
+#@(pytest.mark.xfail
+(defn test-apply-op []
+ ; https://github.com/hylang/hy/issues/647
+ (assert (= (eval '(apply + ["a" "b" "c"])) "abc"))))
diff --git a/tests/native_tests/py3_only_tests.hy b/tests/native_tests/py3_only_tests.hy
index 6c577b4..365a4fe 100644
--- a/tests/native_tests/py3_only_tests.hy
+++ b/tests/native_tests/py3_only_tests.hy
@@ -1,8 +1,5 @@
;; Tests where the emitted code relies on Python 3.
-;; Conditionally included in nosetests runs.
-
-(import [hy.errors [HyCompileError]])
-
+;; conftest.py skips this file when running on Python 2.
(defn test-exception-cause []
diff --git a/tests/native_tests/quote.hy b/tests/native_tests/quote.hy
index 617de5d..8cd6a07 100644
--- a/tests/native_tests/quote.hy
+++ b/tests/native_tests/quote.hy
@@ -1,4 +1,4 @@
-(import hy)
+(import [hy [HyExpression HySymbol HyString HyBytes]])
(defn test-quote []
@@ -8,6 +8,13 @@
(assert (= q [(quote a) (quote b) (quote c)])))
+(defn test-basic-quoting []
+ (assert (= (type (quote (foo bar))) HyExpression))
+ (assert (= (type (quote foo)) HySymbol))
+ (assert (= (type (quote "string")) HyString))
+ (assert (= (type (quote b"string")) HyBytes)))
+
+
(defn test-quoted-hoistable []
"NATIVE: check whether quote works on hoisted things"
(setv f (quote (if True True True)))
diff --git a/tox.ini b/tox.ini
index a4ab4f0..6f0d909 100644
--- a/tox.ini
+++ b/tox.ini
@@ -5,7 +5,7 @@ skipsdist = True
[testenv]
commands =
pip install --allow-all-external -e .
- nosetests
+ pytest
passenv =
TERM
deps =