Merge pull request #1279 from Kodiologist/pytest

Migrate from Nose to pytest
This commit is contained in:
Kodi Arfer 2017-04-26 14:27:17 -07:00
commit 4fce884d1b
20 changed files with 154 additions and 193 deletions

2
.gitignore vendored
View File

@ -8,4 +8,4 @@
dist dist
.coverage .coverage
build/ build/
.noseids /.cache

View File

@ -1,23 +1,18 @@
sudo: false sudo: false
language: python language: python
matrix: python:
include: - "2.7"
- python: 3.5 - "3.3"
env: TOXENV=py35 - "3.4"
- python: 3.6-dev - "3.5"
env: TOXENV=py36 - "3.6"
env: - pypy
- TOXENV=py27 install:
- TOXENV=py33 - pip install --upgrade pytest
- TOXENV=py34 - pip install -r requirements-travis.txt
- TOXENV=pypy - pip install -e .
- TOXENV=flake8 script: pytest
install: pip install tox cache: pip
script: tox
cache:
directories:
- .tox
- $HOME/.cache/pip
after_success: make coveralls after_success: make coveralls
notifications: notifications:
email: email:

View File

@ -2,7 +2,6 @@ pip_url=https://bootstrap.pypa.io/get-pip.py
python=python python=python
pip=pip pip=pip
coveralls=coveralls coveralls=coveralls
nose=nosetests
all: all:
@echo "No default step. Use setup.py" @echo "No default step. Use setup.py"
@ -41,7 +40,7 @@ endif
dev: test flake dev: test flake
test: venv test: venv
nosetests -sv pytest
tox: venv tox: venv
tox tox

13
conftest.py Normal file
View File

@ -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

View File

@ -62,12 +62,11 @@ Do this:
Test! Test!
===== =====
Tests are located in ``tests/``. We use `nose Tests are located in ``tests/``. We use `pytest <http://pytest.org>`_.
<https://nose.readthedocs.io/en/latest/>`_.
To run the tests:: To run the tests::
$ nosetests $ pytest
Write tests---tests are good! Write tests---tests are good!

View File

@ -30,7 +30,6 @@ import marshal
import struct import struct
import imp import imp
import sys import sys
import platform
import ast import ast
import os import os
import __future__ import __future__
@ -114,17 +113,13 @@ def import_file_to_module(module_name, fpath, loader=None):
module = imp.new_module(module_name) module = imp.new_module(module_name)
module.__file__ = fpath module.__file__ = fpath
code = ast_compile(_ast, fpath, "exec") code = ast_compile(_ast, fpath, "exec")
if not (platform.python_implementation() == 'PyPy' and try:
'nosetests' in sys.argv[0] and write_code_as_pyc(fpath, code)
is_package(module_name)): except (IOError, OSError):
# Nose can generate spurious errors in this specific situation. # We failed to save the bytecode, probably because of a
try: # permissions issue. The user only asked to import the
write_code_as_pyc(fpath, code) # file, so don't bug them about it.
except (IOError, OSError): pass
# 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__) eval(code, module.__dict__)
except (HyTypeError, LexException) as e: except (HyTypeError, LexException) as e:
if e.source is None: 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) sys.modules.pop(module_name, None)
raise raise
sys.modules[module_name] = module sys.modules[module_name] = module
module.__file__ = fpath
module.__name__ = module_name module.__name__ = module_name
module.__file__ = fpath
if loader: if loader:
module.__loader__ = loader module.__loader__ = loader
if is_package(module_name): if is_package(module_name):

View File

@ -55,7 +55,7 @@ goto :EOF
if "%1" == "test" ( if "%1" == "test" (
:test :test
call :venv call :venv
nosetests -sv pytest -sv
goto :EOF goto :EOF
) )

View File

@ -1,6 +1,6 @@
-r requirements-travis.txt -r requirements-travis.txt
# test tools # test tools
nose pytest
tox tox
# documentation # documentation

View File

@ -1,9 +1,3 @@
[nosetests]
detailed-errors=1
with-coverage=1
cover-package=hy
nocapture=1
[wheel] [wheel]
universal = 1 universal = 1
@ -12,7 +6,6 @@ omit =
*/python?.?/* */python?.?/*
*/lib-python/?.?/*.py */lib-python/?.?/*.py
*/lib_pypy/_*.py */lib_pypy/_*.py
*/site-packages/nose/*
*/pypy/* */pypy/*
[coverage:report] [coverage:report]
@ -22,3 +15,8 @@ exclude_lines =
# We want ignore_errors so we don't get NoSource warnings for loading # We want ignore_errors so we don't get NoSource warnings for loading
# byte-compiled Hy modules. # byte-compiled Hy modules.
ignore_errors = True 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_*

View File

@ -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

View File

@ -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)))

View File

@ -20,96 +20,85 @@
# DEALINGS IN THE SOFTWARE. # DEALINGS IN THE SOFTWARE.
import ast import ast
import sys
from hy import compiler from hy import compiler
from hy.models import HyExpression, HyList, HySymbol, HyInteger from hy.models import HyExpression, HyList, HySymbol, HyInteger
from hy._compat import PY3 from hy._compat import PY3
if sys.version_info[0] <= 2 and sys.version_info[1] <= 6:
import unittest2 as unittest def test_builds_with_dash():
else: assert callable(compiler.builds("foobar"))
import unittest 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 make_expression(*args):
h = HyExpression(args)
def test_builds_with_dash(self): h.start_line = 1
self.assert_(callable(compiler.builds("foobar"))) h.end_line = 1
self.assert_(callable(compiler.builds("foo_bar"))) h.start_column = 1
self.assert_(callable(compiler.builds("-"))) h.end_column = 1
self.assertRaisesRegexp(TypeError, return h.replace(h)
r"\*post\* translated strings",
compiler.builds, "foobar-with-dash-")
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 # We expect two statements and a final expr.
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)
def setUp(self): assert len(ret.stmts) == 2
self.c = compiler.HyASTCompiler('test') 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): assert isinstance(ret.expr, ast.Name)
""" assert ret.expr.id == "c"
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")))
# 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): def test_compiler_yield_return():
""" """
Check that the compiler correctly generates return statements for Check that the compiler correctly generates return statements for
a generator function. In Python versions prior to 3.3, the return 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 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 should not generate a return statement. From 3.3 onwards a return
value should be generated. value should be generated.
""" """
ret = self.c.compile_function_def( e = make_expression(HySymbol("fn"),
self._make_expression(HySymbol("fn"), HyList(),
HyList(), HyExpression([HySymbol("yield"),
HyExpression([HySymbol("yield"), HyInteger(2)]),
HyInteger(2)]), HyExpression([HySymbol("+"),
HyExpression([HySymbol("+"), HyInteger(1),
HyInteger(1), HyInteger(1)]))
HyInteger(1)]))) ret = compiler.HyASTCompiler('test').compile_function_def(e)
self.assertEqual(len(ret.stmts), 1) assert len(ret.stmts) == 1
stmt = ret.stmts[0] stmt, = ret.stmts
self.assertIsInstance(stmt, ast.FunctionDef) assert isinstance(stmt, ast.FunctionDef)
body = stmt.body body = stmt.body
self.assertEquals(len(body), 2) assert len(body) == 2
self.assertIsInstance(body[0], ast.Expr) assert isinstance(body[0], ast.Expr)
self.assertIsInstance(body[0].value, ast.Yield) assert isinstance(body[0].value, ast.Yield)
if PY3: if PY3:
# From 3.3+, the final statement becomes a return value # From 3.3+, the final statement becomes a return value
self.assertIsInstance(body[1], ast.Return) assert isinstance(body[1], ast.Return)
self.assertIsInstance(body[1].value, ast.BinOp) assert isinstance(body[1].value, ast.BinOp)
else: else:
# In earlier versions, the expression is not returned # In earlier versions, the expression is not returned
self.assertIsInstance(body[1], ast.Expr) assert isinstance(body[1], ast.Expr)
self.assertIsInstance(body[1].value, ast.BinOp) assert isinstance(body[1].value, ast.BinOp)

View File

@ -1 +0,0 @@
from .native.quoting import * # NOQA

View File

@ -1,4 +1,4 @@
(import [hy.extra.reserved [names] hy._compat [PY3]]) (import [hy.extra.reserved [names]] [hy._compat [PY3]])
(defn test-reserved [] (defn test-reserved []
(assert (is (type (names)) frozenset)) (assert (is (type (names)) frozenset))

View File

@ -2,7 +2,8 @@
[os.path [exists isdir isfile]] [os.path [exists isdir isfile]]
[sys :as systest] [sys :as systest]
[operator [or_]] [operator [or_]]
[hy.errors [HyTypeError]]) [hy.errors [HyTypeError]]
pytest)
(import sys) (import sys)
(import [hy._compat [PY3 PY34 PY35]]) (import [hy._compat [PY3 PY34 PY35]])
@ -686,20 +687,6 @@
(assert (= (cut [1 2 3 4 5]) [1 2 3 4 5]))) (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 [] (defn test-rest []
"NATIVE: test rest" "NATIVE: test rest"
(assert (= (list (rest [1 2 3 4 5])) [2 3 4 5])) (assert (= (list (rest [1 2 3 4 5])) [2 3 4 5]))
@ -1175,7 +1162,7 @@
(defn test-try-except-return [] (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)) (assert (= ((fn [] (try xxx (except [NameError] (+ 1 1))))) 2))
(setv foo (try xxx (except [NameError] (+ 1 1)))) (setv foo (try xxx (except [NameError] (+ 1 1))))
(assert (= foo 2)) (assert (= foo 2))
@ -1183,6 +1170,21 @@
(assert (= foo 4))) (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 [] (defn test-require []
"NATIVE: test requiring macros from python code" "NATIVE: test requiring macros from python code"
(try (qplah 1 2 3 4) (try (qplah 1 2 3 4)
@ -1252,13 +1254,6 @@
(assert (= "test" (:foo {:foo "test"})))) (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 [] (defn test-break-breaking []
"NATIVE: test checking if break actually breaks" "NATIVE: test checking if break actually breaks"
(defn holy-grail [] (for [x (range 10)] (if (= x 5) (break))) x) (defn holy-grail [] (for [x (range 10)] (if (= x 5) (break))) x)
@ -1309,6 +1304,13 @@
(assert (= (macroexpand '(-> (a b) (-> (c d) (e f)))) (assert (= (macroexpand '(-> (a b) (-> (c d) (e f))))
'(e (c (a b) d) 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 [] (defn test-macroexpand-1 []
"Test macroexpand-1 on ->" "Test macroexpand-1 on ->"
@ -1336,8 +1338,7 @@
(defn test-calling-module-name [] (defn test-calling-module-name []
"NATIVE: Test the calling-module-name function" "NATIVE: Test the calling-module-name function"
(assert (= (calling-module-name -1) "hy.core.language")) (assert (= (calling-module-name -1) "hy.core.language")))
(assert (= (calling-module-name 0) "tests.native_tests.language")))
(defn test-disassemble [] (defn test-disassemble []

View File

@ -1,4 +1,4 @@
(import [hy._compat [PY35]]) (import pytest [hy._compat [PY35]])
(defmacro op-and-shadow-test [op &rest body] (defmacro op-and-shadow-test [op &rest body]
; Creates two tests with the given `body`, one where all occurrences ; 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 3 [1 2]) (!= f-name "in")))
(assert (is (f 2 [1 2]) (= f-name "in"))) (assert (is (f 2 [1 2]) (= f-name "in")))
(forbid (f 2 [1 2] [3 4]))) (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"))))

View File

@ -1,8 +1,5 @@
;; Tests where the emitted code relies on Python 3. ;; Tests where the emitted code relies on Python 3.
;; Conditionally included in nosetests runs. ;; conftest.py skips this file when running on Python 2.
(import [hy.errors [HyCompileError]])
(defn test-exception-cause [] (defn test-exception-cause []

View File

@ -1,4 +1,4 @@
(import hy) (import [hy [HyExpression HySymbol HyString HyBytes]])
(defn test-quote [] (defn test-quote []
@ -8,6 +8,13 @@
(assert (= q [(quote a) (quote b) (quote c)]))) (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 [] (defn test-quoted-hoistable []
"NATIVE: check whether quote works on hoisted things" "NATIVE: check whether quote works on hoisted things"
(setv f (quote (if True True True))) (setv f (quote (if True True True)))

View File

@ -5,7 +5,7 @@ skipsdist = True
[testenv] [testenv]
commands = commands =
pip install --allow-all-external -e . pip install --allow-all-external -e .
nosetests pytest
passenv = passenv =
TERM TERM
deps = deps =