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
.coverage
build/
.noseids
/.cache

View File

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

View File

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

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!
=====
Tests are located in ``tests/``. We use `nose
<https://nose.readthedocs.io/en/latest/>`_.
Tests are located in ``tests/``. We use `pytest <http://pytest.org>`_.
To run the tests::
$ nosetests
$ pytest
Write tests---tests are good!

View File

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

View File

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

View File

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

View File

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

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

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 []
(assert (is (type (names)) frozenset))

View File

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

View File

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

View File

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

View File

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

View File

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