Merge pull request #1279 from Kodiologist/pytest
Migrate from Nose to pytest
This commit is contained in:
commit
4fce884d1b
2
.gitignore
vendored
2
.gitignore
vendored
@ -8,4 +8,4 @@
|
||||
dist
|
||||
.coverage
|
||||
build/
|
||||
.noseids
|
||||
/.cache
|
||||
|
31
.travis.yml
31
.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:
|
||||
|
3
Makefile
3
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
|
||||
|
13
conftest.py
Normal file
13
conftest.py
Normal 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
|
@ -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!
|
||||
|
||||
|
@ -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):
|
||||
|
2
make.bat
2
make.bat
@ -55,7 +55,7 @@ goto :EOF
|
||||
if "%1" == "test" (
|
||||
:test
|
||||
call :venv
|
||||
nosetests -sv
|
||||
pytest -sv
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
-r requirements-travis.txt
|
||||
# test tools
|
||||
nose
|
||||
pytest
|
||||
tox
|
||||
|
||||
# documentation
|
||||
|
12
setup.cfg
12
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_*
|
||||
|
@ -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
|
@ -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)))
|
@ -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)
|
||||
|
@ -1 +0,0 @@
|
||||
from .native.quoting import * # NOQA
|
@ -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))
|
||||
|
@ -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 []
|
||||
|
@ -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"))))
|
||||
|
@ -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 []
|
||||
|
@ -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)))
|
||||
|
Loading…
Reference in New Issue
Block a user