diff --git a/.testlooper/collect_pytest_tests.py b/.testlooper/collect_pytest_tests.py new file mode 100755 index 000000000..a9fd4debd --- /dev/null +++ b/.testlooper/collect_pytest_tests.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +""" +Runs pytest collection and format the results. + +Passes any arguments to pytest. +""" +import os +import subprocess +import sys + +import yaml + +from typing import Optional + + +def run_pytest_collect(args) -> Optional[str]: + """Run custom collection that includes markers. + + Normal collection only uses the test names. In order to get + tests/ in the PYTHONPATH, and use our collector plugin, + we must call using python -m pytest. + """ + command = [ + sys.executable, + "-m", + "pytest", + "-p", + "typed_python.marker_collector_plugin", + "--collect-tests-and-markers", + "-q", + ] + args + try: + output = subprocess.check_output(command, text=True, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + output = e.output + print(f"Error occurred: {e}") + return None + return output + + +def parse_to_yaml(pytest_output: str) -> str: + """ + Convert the pytest output into yaml of the form: + - unique_test_name: + path: str + labels: List[str] + + + Assumes that if its a three-part tuple, with the first part being a path, then its + test output. (Needed because some versions of pytest output arbitrary lines that don't + follow this format.) + """ + + output = [line.strip().split("::") for line in pytest_output.split("\n")[:-4]] + parsed_output = {} + + for line in output: + try: + path, name, markers = line + if not os.path.exists(path): + continue + if markers: + parsed_output[name] = {"path": path, "labels": markers.split("|")} + else: + parsed_output[name] = {"path": path} + except ValueError: + continue + return yaml.dump(parsed_output) + + +def main(): + args = sys.argv[1:] + output = run_pytest_collect(args) + if output: + parsed_output = parse_to_yaml(output) + print(parsed_output) + + +if __name__ == "__main__": + main() diff --git a/.testlooper/config.yaml b/.testlooper/config.yaml new file mode 100644 index 000000000..b7fcce878 --- /dev/null +++ b/.testlooper/config.yaml @@ -0,0 +1,12 @@ +version: 1.0 +name: typedpython +primary-branch: will-testlooper +image: + docker: + dockerfile: .testlooper/environments/Dockerfile.setup + +variables: + PYTHONPATH: ${REPO_ROOT} + +command: + python .testlooper/generate_test_plan.py --output ${TEST_PLAN_OUTPUT} diff --git a/.testlooper/environments/Dockerfile.linux-pytest b/.testlooper/environments/Dockerfile.linux-pytest new file mode 100644 index 000000000..f356362d2 --- /dev/null +++ b/.testlooper/environments/Dockerfile.linux-pytest @@ -0,0 +1,16 @@ +# used for generating the container that runs and lists the python tests. Docker is smart enough to +# invalidate the cache when pyproject.toml changes. +FROM python:3.10 + +WORKDIR /app + +COPY requirements.txt . + +# install the dependencies +RUN pip install -r requirements.txt +# RUN pip install toml && \ +# python -c "import toml; deps = toml.load('pyproject.toml')['project']['dependencies']; print('\n'.join(deps))" > requirements.txt \ +# && pip install --no-cache-dir -r requirements.txt + + +ENTRYPOINT ["/bin/bash", "-c"] diff --git a/.testlooper/environments/Dockerfile.setup b/.testlooper/environments/Dockerfile.setup new file mode 100644 index 000000000..01d2308b6 --- /dev/null +++ b/.testlooper/environments/Dockerfile.setup @@ -0,0 +1,9 @@ +# used for generating the test plan - requires only access to the repo and Python 3.10 stdlib +# TODO - we don't need the whole directory. +FROM python:3.10 + +WORKDIR /app + +COPY . /app + +ENTRYPOINT ["/bin/bash", "-c"] diff --git a/.testlooper/generate_test_plan.py b/.testlooper/generate_test_plan.py new file mode 100644 index 000000000..8ff5f44cf --- /dev/null +++ b/.testlooper/generate_test_plan.py @@ -0,0 +1,49 @@ +"""generate_test_plan.py + +Currently returns a static YAML file. +""" +import argparse + + +TEST_PLAN = """ +version: 1 +environments: + # linux docker container for running our pytest unit-tests + linux-pytest: + image: + docker: + dockerfile: .testlooper/environments/Dockerfile.linux-pytest + variables: + PYTHONPATH: ${REPO_ROOT} + min-ram-gb: 10 +builds: + # skip +suites: + group_one: + kind: unit + environment: linux-pytest + dependencies: + list-tests: | + python .testlooper/collect_pytest_tests.py -m 'group_one' + run-tests: | + python .testlooper/run_pytest_tests.py -m 'group_one' + timeout: 30 + + group_two: + kind: unit + environment: linux-pytest + dependencies: + list-tests: | + python .testlooper/collect_pytest_tests.py -m 'group_two' + run-tests: | + python .testlooper/run_pytest_tests.py -m 'group_two' + timeout: 30 +""" + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Generate a test plan.") + parser.add_argument("--output", type=str, default="test_plan.yaml") + args = parser.parse_args() + + with open(args.output, "w") as f: + f.write(TEST_PLAN) diff --git a/.testlooper/run_pytest_tests.py b/.testlooper/run_pytest_tests.py new file mode 100755 index 000000000..8f3616525 --- /dev/null +++ b/.testlooper/run_pytest_tests.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +""" +Runs pytest and generates a json report. + +Passes any arguments to pytest. +""" +import os +import subprocess +import sys +from typing import Optional + + +def run_pytest_json_report(args) -> subprocess.CompletedProcess: + test_output = os.environ.get("TEST_OUTPUT") + test_input = os.environ.get("TEST_INPUT") + + command = [sys.executable, "-m", "pytest", "--json-report"] + + if test_output: + command.extend(["--json-report-file", test_output]) + + if test_input: + # we expect a test on each line, with the format path_to_file::test_name + with open(test_input, "r") as flines: + test_cases = [ + line.strip() + for line in flines.readlines() + if line and not line.startswith("#") + ] + command.extend(test_cases) + + command.extend(args) + output = subprocess.run(command, capture_output=True, text=True) + return output + + +def main(): + args = sys.argv[1:] + output = run_pytest_json_report(args) + print(output.stdout) + print(output.stderr, file=sys.stderr) + + +if __name__ == "__main__": + main() diff --git a/mark_all_tests.sh b/mark_all_tests.sh new file mode 100755 index 000000000..4ecefd1b5 --- /dev/null +++ b/mark_all_tests.sh @@ -0,0 +1,29 @@ +#!/bin/bash + + +# Step 1: Identify Target Files +files=$(find typed_python/ -name "*_test.py") + +# Step 2: Iterate Over Each File +for file in $files; do + # Make a backup before modifying + cp "$file" "${file}.bak" + + # Step 3 and 4: Random Logic for Grouping and Apply Text Transformation + awk ' + { + if ($0 ~ /^[ \t]*def test_/) { + match($0, /^[ \t]*/); + indent = substr($0, RSTART, RLENGTH); + srand(); + rand_num = int(rand() * 2 + 1); + if (rand_num == 1) { + print indent "@pytest.mark.group_one"; + } else { + print indent "@pytest.mark.group_two"; + } + } + print $0; + } + ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" +done diff --git a/requirements.txt b/requirements.txt index 85bf284e8..0f85f0b4f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,8 @@ llvmlite==0.38 numpy psutil pytz +pytest +pyyaml +pytest-json-report sortedcontainers +toml diff --git a/typed_python/Codebase_test.py b/typed_python/Codebase_test.py index 4a199696f..30a7eb192 100644 --- a/typed_python/Codebase_test.py +++ b/typed_python/Codebase_test.py @@ -19,6 +19,7 @@ class CodebaseTest(unittest.TestCase): + @pytest.mark.group_one def test_instantiated_codebase(self): codebase = Codebase.FromFileMap({ 'codebase_test_test_module/__init__.py': '', @@ -46,6 +47,7 @@ def test_instantiated_codebase(self): with self.assertRaisesRegex(Exception, "Module codebase_test_test_module is"): codebaseAlternativeCode.instantiate() + @pytest.mark.group_one def test_grab_native_codebase(self): codebase = Codebase.FromRootlevelModule(typed_python) diff --git a/typed_python/__init__.py b/typed_python/__init__.py index 6c4d70706..ca8495770 100644 --- a/typed_python/__init__.py +++ b/typed_python/__init__.py @@ -79,8 +79,6 @@ from typed_python.lib.map import map # noqa from typed_python.lib.pmap import pmap # noqa from typed_python.lib.reduce import reduce # noqa -from typed_python.lib.timestamp import Timestamp # noqa -from typed_python.lib.datetime.date_time import UTC, NYC, TimeOfDay, DateTime, Date, PytzTimezone # noqa _types.initializeGlobalStatics() diff --git a/typed_python/_runtime.cpp b/typed_python/_runtime.cpp index 9351f18e9..6a0d8cddd 100644 --- a/typed_python/_runtime.cpp +++ b/typed_python/_runtime.cpp @@ -1021,16 +1021,14 @@ extern "C" { return PythonObjectOfType::createLayout(p); } - void np_initialize_exception(PythonObjectOfType::layout_type* layout) { + // set the python exception state and return (without throwing) + void setExceptionState(PyObject* exception, PyObject* cause) { PyEnsureGilAcquired getTheGil; - PyObject* prevType; - PyObject* prevValue; - PyObject* prevTraceback; - PyErr_GetExcInfo(&prevType, &prevValue, &prevTraceback); - - if (layout) { - PyTypeObject* tp = layout->pyObj->ob_type; + // check if the exception is actually an exception. If not, + // we can't even raise it. + if (exception) { + PyTypeObject* tp = exception->ob_type; bool hasBaseE = false; while (tp) { @@ -1044,24 +1042,38 @@ extern "C" { PyErr_Format( PyExc_TypeError, "exceptions must derive from BaseException, not %S", - (PyObject*)layout->pyObj->ob_type + (PyObject*)exception->ob_type ); return; } + } + + if (exception && cause) { + // if we have an exception and a cause, just raise directly + PyException_SetCause(exception, incref(cause)); + PyErr_Restore((PyObject*)incref(exception->ob_type), incref(exception), nullptr); + } + else if (exception) { + PyObject* prevType; + PyObject* prevValue; + PyObject* prevTraceback; + PyErr_GetExcInfo(&prevType, &prevValue, &prevTraceback); if (prevValue) { - PyException_SetContext(layout->pyObj, prevValue); + PyException_SetContext(exception, prevValue); } decref(prevType); decref(prevTraceback); - PyErr_SetObject( - (PyObject*)layout->pyObj->ob_type, - layout->pyObj - ); + PyErr_SetObject((PyObject*)exception->ob_type, exception); } else { + PyObject* prevType; + PyObject* prevValue; + PyObject* prevTraceback; + PyErr_GetExcInfo(&prevType, &prevValue, &prevTraceback); + if (!prevValue) { decref(prevType); decref(prevValue); @@ -1069,56 +1081,25 @@ extern "C" { PyErr_SetString(PyExc_RuntimeError, "No active exception to reraise"); throw PythonExceptionSet(); } + if (cause) { + PyException_SetCause(prevValue, incref(cause)); + } PyErr_Restore(prevType, prevValue, prevTraceback); } } + void np_initialize_exception(PythonObjectOfType::layout_type* layout) { + setExceptionState(layout ? layout->pyObj : nullptr, nullptr); + } + void np_initialize_exception_w_cause( PythonObjectOfType::layout_type* layoutExc, PythonObjectOfType::layout_type* layoutCause ) { - PyEnsureGilAcquired getTheGil; - - if (layoutExc) { - PyTypeObject* tp = layoutExc->pyObj->ob_type; - bool hasBaseE = false; - - while (tp) { - if (tp == (PyTypeObject*)PyExc_BaseException) { - hasBaseE = true; - } - tp = tp->tp_base; - } - - if (!hasBaseE) { - PyErr_Format( - PyExc_TypeError, - "exceptions must derive from BaseException, not %S", - (PyObject*)layoutExc->pyObj->ob_type - ); - - return; - } - - PyException_SetCause(layoutExc->pyObj, layoutCause ? incref(layoutCause->pyObj) : NULL); - PyErr_Restore((PyObject*)incref(layoutExc->pyObj->ob_type), incref(layoutExc->pyObj), nullptr); - } - else { - PyObject* prevType; - PyObject* prevValue; - PyObject* prevTraceback; - PyErr_GetExcInfo(&prevType, &prevValue, &prevTraceback); - - if (!prevValue) { - decref(prevType); - decref(prevValue); - decref(prevTraceback); - PyErr_SetString(PyExc_RuntimeError, "No active exception to reraise"); - throw PythonExceptionSet(); - } - PyException_SetCause(prevValue, layoutCause ? incref(layoutCause->pyObj) : NULL); - PyErr_Restore(prevType, prevValue, prevTraceback); - } + setExceptionState( + layoutExc ? layoutExc->pyObj : nullptr, + layoutCause ? layoutCause->pyObj : nullptr + ); } void np_clear_exception() { @@ -1353,6 +1334,58 @@ extern "C" { return PythonObjectOfType::stealToCreateLayout(res); } + void nativepython_runtime_call_pyobj_and_raise( + int argCount, + int kwargCount, + ... + ) { + PyEnsureGilAcquired getTheGil; + + // each of 'argCount' arguments is a PyObject* followed by a const char* + va_list va_args; + va_start(va_args, kwargCount); + + PyObjectHolder toCall; + + PyObjectStealer args(PyTuple_New(argCount - 1)); + PyObjectStealer kwargs(PyDict_New()); + + for (int i = 0; i < argCount; ++i) { + instance_ptr data = va_arg(va_args, instance_ptr); + Type* typ = va_arg(va_args, Type*); + + if (i == 0) { + toCall.steal( + PyInstance::extractPythonObject(data, typ) + ); + } else { + PyTuple_SetItem((PyObject*)args, i - 1, PyInstance::extractPythonObject(data, typ)); + } + } + + for (int i = 0; i < kwargCount; ++i) { + instance_ptr data = va_arg(va_args, instance_ptr); + Type* typ = va_arg(va_args, Type*); + const char* kwargName = va_arg(va_args, const char*); + + PyObjectStealer kwargVal(PyInstance::extractPythonObject(data, typ)); + + PyDict_SetItemString((PyObject*)kwargs, kwargName, (PyObject*)kwargVal); + } + + va_end(va_args); + + PyObjectStealer res(PyObject_Call((PyObject*)toCall, args, kwargs)); + + if (!res) { + throw PythonExceptionSet(); + } + + setExceptionState((PyObject*)res, nullptr); + + throw PythonExceptionSet(); + } + PythonObjectOfType::layout_type* nativepython_runtime_call_pyobj( PythonObjectOfType::layout_type* toCall, int argCount, diff --git a/typed_python/array/array_test.py b/typed_python/array/array_test.py index 2edc1e45b..d8dec0305 100644 --- a/typed_python/array/array_test.py +++ b/typed_python/array/array_test.py @@ -23,6 +23,7 @@ from typed_python import Entrypoint +@pytest.mark.group_one def test_float_array_addition(): x = Array(float)([1, 2, 3]) @@ -47,6 +48,7 @@ def test_float_array_addition(): assert y[0] == 8 +@pytest.mark.group_one def test_float_array_subtraction(): x = Array(float)([1, 2, 3]) @@ -67,6 +69,7 @@ def test_float_array_subtraction(): assert y[0] == -4 +@pytest.mark.group_one def test_float_array_multiplication(): x = Array(float)([1, 2, 3]) @@ -91,6 +94,7 @@ def test_float_array_multiplication(): assert y[1] == 128 +@pytest.mark.group_one def test_float_array_addition_wrong_size(): x = Array(float).ones(3) x2 = Array(float).zeros(4) @@ -102,6 +106,7 @@ def test_float_array_addition_wrong_size(): x += x2 +@pytest.mark.group_one def test_basic_matrix_ops(): m = Matrix(float).identity(10) @@ -115,6 +120,7 @@ def test_basic_matrix_ops(): @flaky(max_runs=3, min_passes=1) +@pytest.mark.group_one def test_matrix_speed(): # this test requires parallelism, and the machines we're using in travis # don't always have free cores, so we get false negatives. @@ -170,6 +176,7 @@ def manyAdds(m, count): assert tpSlowdown < SLOWDOWN_THRESHOLD, tpSlowdown +@pytest.mark.group_one def test_square_matrix_vector_multiply(): m = Matrix(float).identity(3) @@ -187,6 +194,7 @@ def test_square_matrix_vector_multiply(): assert (m @ a).toList() == [1, 11, 21] +@pytest.mark.group_one def test_rectangular_matrix_vector_multiply(): m = Matrix(float).zeros(8, 4) @@ -211,6 +219,7 @@ def test_rectangular_matrix_vector_multiply(): assert (a2 @ m).toList() == m[0].toList() +@pytest.mark.group_one def test_matrix_multiply(): m = Matrix(float).identity(4) m2 = Matrix(float).identity(4) @@ -233,6 +242,7 @@ def test_matrix_multiply(): assert (m @ m2)[1][3] == 1 +@pytest.mark.group_one def test_rectangular_matrix_multiply(): m = Matrix(float).zeros(5, 2) m2 = Matrix(float).zeros(2, 4) @@ -249,6 +259,7 @@ def l1norm(m): return m.flatten().abs().sum() +@pytest.mark.group_one def test_invert(): m = Matrix(float).identity(10) * 2 @@ -259,24 +270,28 @@ def test_invert(): assert l1norm((m @ ~m) - Matrix(float).identity(10)) < 1e-10 +@pytest.mark.group_one def test_create_matrix(): m = Matrix(float).make(10, 10, lambda row, col: row * 20 - col) assert m[3][4] == 3 * 20 - 4 +@pytest.mark.group_one def test_negate_matrix(): m = Matrix(float).identity(10) assert l1norm(+m + -m) < 1e-10 +@pytest.mark.group_one def test_matrix_cos_and_sin(): m = Matrix(float).make(10, 10, lambda x, y: x**2 - y**2) assert l1norm(m.cos() ** 2 + m.sin() ** 2 - 1) < 1e-10 +@pytest.mark.group_one def test_increment_matrix_diagonal(): m = Matrix(float).zeros(10, 10) d = m.diagonal() @@ -285,6 +300,7 @@ def test_increment_matrix_diagonal(): assert m.get(2, 2) == 1 +@pytest.mark.group_one def test_assign_matrix_row(): m = Matrix(float).identity(10) @@ -296,6 +312,7 @@ def test_assign_matrix_row(): assert m.get(4, 4) == m.get(3, 4) +@pytest.mark.group_one def test_matrix_product_with_transpose(): def checkEqual(a, b): assert l1norm(a - b) < 1e-10 diff --git a/typed_python/class_types_test.py b/typed_python/class_types_test.py index 6ed3a271d..b772755cb 100644 --- a/typed_python/class_types_test.py +++ b/typed_python/class_types_test.py @@ -89,11 +89,13 @@ def f(self, y) -> str: # noqa: F811 class NativeClassTypesTests(unittest.TestCase): + @pytest.mark.group_one def test_class_name(self): assert ClassWithInit.__name__ == 'ClassWithInit' assert ClassWithInit.__module__ == 'typed_python.class_types_test' assert ClassWithInit.__qualname__ == 'ClassWithInit' + @pytest.mark.group_one def test_member_default_value(self): c = DefaultVal() @@ -112,6 +114,7 @@ def test_member_default_value(self): self.assertEqual(c.s0, "") self.assertEqual(c.s1, "abc") + @pytest.mark.group_one def test_class_dispatch_by_name(self): c = ClassWithComplexDispatch(x=200) @@ -119,6 +122,7 @@ def test_class_dispatch_by_name(self): self.assertEqual(c.f(x=10), 'x') self.assertEqual(c.f(y=10), 'y') + @pytest.mark.group_one def test_class_with_uninitializable(self): c = ClassWithInit() @@ -132,6 +136,7 @@ def test_class_with_uninitializable(self): self.assertEqual(c.cwi.x, 10) + @pytest.mark.group_one def test_implied_init_fun(self): self.assertEqual(Interior().x, 0) self.assertEqual(Interior().y, 0) @@ -156,6 +161,7 @@ def executeInLoop(self, f, duration=.25): gc.collect() self.assertLess(currentMemUsageMb() - memUsage, 1.0) + @pytest.mark.group_one def test_typed_function_call_doesnt_leak(self): @Function def f(x, y): @@ -163,6 +169,7 @@ def f(x, y): self.executeInLoop(lambda: f(1, 2)) + @pytest.mark.group_one def test_typed_function_call_with_star_args_doesnt_leak(self): @Function def f(*args): @@ -170,13 +177,16 @@ def f(*args): self.executeInLoop(lambda: f(1, 2)) + @pytest.mark.group_one def test_class_create_doesnt_leak(self): self.executeInLoop(lambda: ClassWithInit(cwi=ClassWithInit())) + @pytest.mark.group_one def test_class_member_access_doesnt_leak(self): x = ClassWithInit(cwi=ClassWithInit()) self.executeInLoop(lambda: x.cwi.z) + @pytest.mark.group_one def test_class(self): with self.assertRaises(TypeError): class A0(Class): @@ -204,6 +214,7 @@ def f(self): self.assertEqual(a.x, 10) + @pytest.mark.group_one def test_class_holding_class(self): e = Exterior() @@ -216,10 +227,12 @@ def test_class_holding_class(self): anI2.x = 10 self.assertEqual(e.iTup.x.x, 10) + @pytest.mark.group_one def test_class_stringification(self): self.assertEqual(Interior.__qualname__, "Interior") self.assertEqual(str(Interior()), "Interior(x=0, y=0)") + @pytest.mark.group_one def test_class_functions_work(self): class C(Class, Final): x = Member(int) @@ -233,6 +246,7 @@ def setX(self, x): self.assertEqual(c.x, 20) + @pytest.mark.group_one def test_class_functions_return_types(self): class C(Class, Final): def returnsInt(self, x) -> int: @@ -252,6 +266,7 @@ def returnsFloat(self, x) -> float: # this should throw because we are happy to convert int to float c.returnsFloat(1) + @pytest.mark.group_one def test_class_function_dispatch_on_arity(self): class C(Class, Final): def f(self): @@ -276,6 +291,7 @@ def f(self, i, i2, *args): # noqa: F811 self.assertEqual(c.f(1, 2), 2) self.assertEqual(c.f(1, 2, 3), 3) + @pytest.mark.group_one def test_class_function_exceptions(self): class C(Class, Final): def g(self, a, b): @@ -289,6 +305,7 @@ def f(self, a, b): with self.assertRaises(AssertionError): c.g(1, 2) + @pytest.mark.group_one def test_class_function_sends_args_to_right_place(self): def g(a, b, c=10, d=20, *args, **kwargs): return (a, b, d, args, kwargs) @@ -315,6 +332,7 @@ def assertSame(takesCallable): assertSame(lambda formOfG: formOfG(1, 2, 3, 4, 5, 6)) assertSame(lambda formOfG: formOfG(1, 2, 3, 4, 5, 6, q=20)) + @pytest.mark.group_one def test_class_function_type_dispatch(self): class C(Class, Final): def f(self, a: float): @@ -341,6 +359,7 @@ def f(self, **kwargs: TupleOf(int)): # noqa: F811 C().f(1, "hi") self.assertEqual(C().f(x=(1, 2)), "named tuple of ints") + @pytest.mark.group_one def test_class_members_accessible(self): class C(Class, Final): x = 10 @@ -360,6 +379,7 @@ class C(Class, Final): self.assertEqual(C.x, 10) self.assertEqual(C.y, Member(int)) + @pytest.mark.group_one def test_static_methods(self): class C(Class, Final): @staticmethod @@ -391,6 +411,7 @@ def f(**kwargs: TupleOf(int)): # noqa: F811 thing.f(1, "hi") self.assertEqual(thing.f(x=(1, 2)), "named tuple of ints") + @pytest.mark.group_one def test_python_objects_in_classes(self): class NormalPyClass: pass @@ -462,6 +483,7 @@ def f(self, x): # noqa: F811 self.assertEqual(x.f(NormalPyClass()), "NormalPyClass") self.assertEqual(x.f(10), "object") + @pytest.mark.group_one def test_class_with_getitem(self): class WithGetitem(Class, Final): def __getitem__(self, x: int): @@ -476,6 +498,7 @@ def __getitem__(self, x: str): # noqa: F811 with self.assertRaises(TypeError): WithGetitem()[None] + @pytest.mark.group_one def test_class_with_len(self): class WithLen(Class, Final): x = Member(int) @@ -495,6 +518,7 @@ def __len__(self): with self.assertRaises(ValueError): len(WithLen(-2)) + @pytest.mark.group_one def test_class_unary_operators(self): class WithLotsOfOperators(Class, Final): def __neg__(self): @@ -528,6 +552,7 @@ def __index__(self): self.assertEqual(float(c), 123.5) self.assertEqual([1, 2, 3][c], 3) + @pytest.mark.group_one def test_class_binary_operators(self): class WithLotsOfOperators(Class, Final): def __add__(self, other): @@ -581,6 +606,7 @@ def __matmul__(self, other): self.assertEqual(c^0, (c, "xor", 0)) self.assertEqual(c@0, (c, "matmul", 0)) + @pytest.mark.group_one def test_class_binary_operators_reverse(self): class WithLotsOfOperators(Class, Final): def __radd__(self, other): @@ -634,6 +660,7 @@ def __rmatmul__(self, other): self.assertEqual(0^c, (c, "xor", 0)) self.assertEqual(0@c, (c, "matmul", 0)) + @pytest.mark.group_one def test_class_binary_inplace_operators(self): class WithLotsOfOperators(Class, Final): def __iadd__(self, other): @@ -687,6 +714,7 @@ def __imatmul__(self, other): self.assertEqual(operator.ixor(c, 0), (c, "ixor", 0)) self.assertEqual(operator.imatmul(c, 0), (c, "imatmul", 0)) + @pytest.mark.group_one def test_class_dispatch_on_tuple_vs_list(self): class WithTwoFunctions(Class, Final): def f(self, x: TupleOf(int)): @@ -699,6 +727,7 @@ def f(self, x: ListOf(int)): # noqa: F811 self.assertEqual(c.f(TupleOf(int)((1, 2, 3))), "Tuple") self.assertEqual(c.f(ListOf(int)((1, 2, 3))), "List") + @pytest.mark.group_one def test_class_comparison_operators(self): class ClassWithComparisons(Class, Final): x = Member(int) @@ -751,6 +780,7 @@ def __ge__(self, other): i != j ) + @pytest.mark.group_one def test_class_comparison_subclassing(self): class ClassWithComparisons(Class): x = Member(int) @@ -771,6 +801,7 @@ def __lt__(self, other): SubclassWithComparisons(x=10) ) + @pytest.mark.group_one def test_class_repr_and_str_and_hash(self): class ClassWithReprAndStr(Class, Final): def __repr__(self): @@ -786,6 +817,7 @@ def __hash__(self): self.assertEqual(repr(ClassWithReprAndStr()), "repr") self.assertEqual(str(ClassWithReprAndStr()), "str") + @pytest.mark.group_one def test_class_missing_inplace_operators_fallback(self): class ClassWithoutInplaceOp(Class, Final): @@ -868,6 +900,7 @@ def __xor__(self, other): c ^= 10 self.assertEqual(c, "worked") + @pytest.mark.group_one def test_class_with_property(self): class ClassWithProperty(Class, Final): _x = Member(int) @@ -881,6 +914,7 @@ def x(self): self.assertEqual(ClassWithProperty(10).x, 11) + @pytest.mark.group_one def test_class_with_bound_methods(self): class SomeClass: pass @@ -907,6 +941,7 @@ def increment(self, y): self.assertEqual(c.x.x, 2000000) + @pytest.mark.group_one def test_class_inheritance_basic(self): class BaseClass(Class): x = Member(int) @@ -930,6 +965,7 @@ def f(self, add) -> object: self.assertEqual(c.y, 20) self.assertEqual(c.f(100), 130) + @pytest.mark.group_one def test_class_inheritance_and_containers(self): class BaseClass(Class): pass @@ -948,6 +984,7 @@ class Child2(BaseClass): self.assertIsInstance(clsList[0], Child1) self.assertIsInstance(clsList[1], Child2) + @pytest.mark.group_one def test_class_multiple_inheritence(self): class BaseA(Class): def f(self, x: int) -> str: @@ -975,6 +1012,7 @@ class BaseBoth(BaseA, BaseB): # get "BaseA" first. self.assertEqual(x.g(), "BaseA") + @pytest.mark.group_one def test_multiple_inheritance_with_members_in_both_children_fails(self): class BaseA(Class): x = Member(int) @@ -1001,6 +1039,7 @@ def g(self) -> str: class BaseBoth(BaseA, BaseB): pass + @pytest.mark.group_one def test_member_order(self): class BaseClass(Class): x = Member(int) @@ -1011,6 +1050,7 @@ class ChildClass(BaseClass): self.assertEqual(ChildClass.MemberNames, ('x', 'y', 'z')) + @pytest.mark.group_one def test_final_classes(self): class BaseClass(Class): pass @@ -1025,6 +1065,7 @@ class ChildClass(Class, Final): class BadClass(ChildClass): pass + @pytest.mark.group_one def test_callable_class(self): class CallableClass(Class, Final): x = Member(int) @@ -1055,6 +1096,7 @@ def call(self, x): with self.assertRaises(TypeError): obj() + @pytest.mark.group_one def test_recursive_classes_repr(self): A0 = Forward("A0") @@ -1071,6 +1113,7 @@ class ASelfRecursiveClass(Class, Final): print(repr(a)) + @pytest.mark.group_one def test_dispatch_tries_without_conversion_first(self): class ClassWithForcedConversion(Class, Final): def f(self, x: float): @@ -1109,6 +1152,7 @@ def f(self, x: float): # noqa: F811 self.assertEqual(ClassWithBoth2().f(10.5), "float") self.assertEqual(ClassWithBoth2().f(True), "bool") + @pytest.mark.group_one def test_class_magic_methods(self): class AClass(Class, Final): @@ -1205,6 +1249,7 @@ def __init__(self, n=""): d = dir(AClass()) self.assertGreater(len(d), 50) + @pytest.mark.group_one def test_class_magic_methods_attr(self): A_attrs = {"q": "value-q", "z": "value-z"} @@ -1258,6 +1303,7 @@ class AClass2(Class, Final): AClass2()[123] = 7 self.assertEqual(AClass2()[123], 7) + @pytest.mark.group_one def test_class_magic_methods_iter(self): class A_iter(): @@ -1293,6 +1339,7 @@ class AClass(Class, Final): self.assertEqual([x for x in AClass()], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) self.assertEqual([x for x in reversed(AClass())], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]) + @pytest.mark.group_one def test_class_magic_methods_as_iterator(self): class B_iter(): @@ -1321,6 +1368,7 @@ class Iterator(Class, Final): self.assertEqual([x for x in A.a()], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) self.assertEqual([x for x in A.a()], []) + @pytest.mark.group_one def test_class_magic_methods_with(self): depth = 0 @@ -1345,6 +1393,7 @@ class AClass(Class, Final): self.assertEqual(depth, 2) self.assertEqual(depth, 0) + @pytest.mark.group_one def test_class_comparison_methods(self): class C(Class, Final): x = Member(int) @@ -1372,6 +1421,7 @@ class C(Class, Final): self.assertEqual(C(x=2) >= C(x=7), True) self.assertEqual(C(x=0) >= C(x=1), False) + @pytest.mark.group_one def test_class_reverse_operators(self): class C(Class, Final): __radd__ = lambda lhs, rhs: "radd" + str(rhs) @@ -1432,6 +1482,7 @@ class C(Class, Final): with self.assertRaises(TypeError): C() | v + @pytest.mark.group_one def test_class_default_constructible(self): # classes without 'init' are always default constructible, # and we'll initialize any non-class members that are default @@ -1454,6 +1505,7 @@ def __init__(self): self.assertFalse(is_default_constructible(NotDC)) + @pytest.mark.group_one def test_class_isinstance(self): class BaseClass(Class): pass @@ -1472,6 +1524,7 @@ def check(): check() Entrypoint(check)() + @pytest.mark.group_one def test_class_delitem(self): class C(Class, Final): deleted = Member(int) @@ -1484,6 +1537,7 @@ def __delitem__(self, k): assert c.deleted == 10 + @pytest.mark.group_one def test_class_len_leak(self): class C(Class, Final): def __len__(self): @@ -1507,6 +1561,7 @@ def __len__(self): t1 = time.time() assert currentMemUsageMb() - m0 < 10.0 + @pytest.mark.group_one def test_class_inquiry_method_exception_resolution(self): class C(Class, Final): def __len__(self): @@ -1538,6 +1593,7 @@ def __setitem__(self, ix, thing): with self.assertRaisesRegex(Exception, "Cannot construct the value None from an instance of bool"): c[10] = 20 + @pytest.mark.group_one def test_class_delattr(self): class C(Class, Final): x = Member(str) @@ -1557,6 +1613,7 @@ class C(Class, Final): assert c.x == "bye" + @pytest.mark.group_one def test_class_nonempty(self): class CNonempty(Class, Final): x = Member(str, nonempty=True) @@ -1588,6 +1645,7 @@ def __init__(self): cE.x = "hihi" assert hasattr(cE, 'x') + @pytest.mark.group_one def test_class_nonempty_forces_construction(self): class SomeOtherClass(Class): pass @@ -1607,6 +1665,7 @@ def __init__(self): assert hasattr(CNonempty(), 'x') assert not hasattr(CEmpty(), 'x') + @pytest.mark.group_one def test_class_mro_index_is_zero_for_self(self): class BaseClass(Class): pass @@ -1618,6 +1677,7 @@ class ChildClass(BaseClass, Final): assert _types.classGetDispatchIndex(BaseClass, BaseClass) == 0 assert _types.classGetDispatchIndex(ChildClass, ChildClass) == 0 + @pytest.mark.group_one def test_method_return_type_overrides_are_sensible(self): def makeClassReturning(Base, T, value): if not T: @@ -1674,6 +1734,7 @@ def assertSequenceInvalid(*typesAndValues): assertSequenceInvalid((int, 0), (None, 0), (float, 1.0)) assertSequenceInvalid((int, 0), (int, 0), (float, 1.0)) + @pytest.mark.group_one def test_method_return_types_depend_on_specialization(self): class BaseClass(Class): def f(self, x: OneOf(int, None)) -> int: @@ -1690,6 +1751,7 @@ def f(self, x: OneOf(str, None)) -> str: with self.assertRaisesRegex(TypeError, "promise"): ChildClass().f(None) + @pytest.mark.group_one def test_compiled_dispatch_on_class(self): class A(Class): pass @@ -1737,6 +1799,7 @@ def f(self, x: Both): assert callItAs(TestClass)(Subclass(), B()) == "B" assert callItAs(TestClass)(Subclass(), Both()) == "Both" + @pytest.mark.group_one def test_dispatch_on_class_infers_type_correctly(self): class A(Class): pass @@ -1762,6 +1825,7 @@ def callIt(c, x): assert callIt.resultTypeFor(TestClass, B).typeRepresentation is OneOf(float, int) assert callIt.resultTypeFor(TestClass, C).typeRepresentation is OneOf(float, int) + @pytest.mark.group_one def test_cant_override_class_members(self): class A(Class): X = int @@ -1770,6 +1834,7 @@ class A(Class): class B(A): X = float + @pytest.mark.group_one def test_mro_equivalent_to_python_diamond(self): def makeClasses(base): class B(base): @@ -1794,6 +1859,7 @@ class E(C, D): assert mroPy == mroTP + @pytest.mark.group_one def test_super(self): class B(Class): def f(self, x): @@ -1805,6 +1871,7 @@ def f(self, x): assert C().f(10) == 11 + @pytest.mark.group_one def test_classmethod_has_methodOf(self): class B(Class): @classmethod @@ -1818,6 +1885,7 @@ def staticMeth(x) -> int: assert B.method.__func__.overloads[0].methodOf.Class is B assert B.staticMeth.overloads[0].methodOf.Class is B + @pytest.mark.group_one def test_decorating_class_with_generator(self): class C(Class): def __iter__(self) -> Generator(int): diff --git a/typed_python/compiler/compiler_cache_test.py b/typed_python/compiler/compiler_cache_test.py index 81ad2f12f..ba39bf182 100644 --- a/typed_python/compiler/compiler_cache_test.py +++ b/typed_python/compiler/compiler_cache_test.py @@ -25,6 +25,7 @@ def f(x): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_compiler_cache_populates(): with tempfile.TemporaryDirectory() as compilerCacheDir: assert evaluateExprInFreshProcess({'x.py': MAIN_MODULE}, 'x.f(10)', compilerCacheDir) == 11 @@ -38,6 +39,7 @@ def test_compiler_cache_populates(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_compiler_cache_can_handle_conflicting_versions_of_the_same_code(): with tempfile.TemporaryDirectory() as compilerCacheDir: assert evaluateExprInFreshProcess({'x.py': MAIN_MODULE}, 'x.f(10)', compilerCacheDir) == 11 @@ -51,6 +53,7 @@ def test_compiler_cache_can_handle_conflicting_versions_of_the_same_code(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_compiler_cache_can_detect_invalidation_through_modules(): xmodule = "\n".join([ "def f(x):", @@ -78,6 +81,7 @@ def test_compiler_cache_can_detect_invalidation_through_modules(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_compiler_cache_robust_to_irrelevant_module_changes(): xmodule = "\n".join([ "# this is a comment", @@ -103,6 +107,7 @@ def test_compiler_cache_robust_to_irrelevant_module_changes(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_compiler_cache_understands_type_changes(): xmodule = "\n".join([ "G = Dict(int, int)({1: 2})", @@ -136,6 +141,7 @@ def test_compiler_cache_understands_type_changes(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_compiler_cache_handles_exceptions_properly(): xmodule = "\n".join([ "@Entrypoint", @@ -157,6 +163,7 @@ def test_compiler_cache_handles_exceptions_properly(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_compiler_cache_understands_granular_module_accesses(): xmodule = "\n".join([ "@Entrypoint", @@ -186,6 +193,7 @@ def test_compiler_cache_understands_granular_module_accesses(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_load_dependent_modules(): xmodule = "\n".join([ "@Entrypoint", @@ -217,6 +225,7 @@ def test_load_dependent_modules(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_reference_existing_function_twice(): xmodule = "\n".join([ "@Entrypoint", @@ -257,6 +266,7 @@ def test_reference_existing_function_twice(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_compiler_cache_handles_class_destructors_correctly(): xmodule = "\n".join([ "class C(Class):", @@ -283,6 +293,7 @@ def test_compiler_cache_handles_class_destructors_correctly(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_compiler_cache_handles_classes(): xmodule = "\n".join([ "class C(Class):", @@ -309,6 +320,7 @@ def test_compiler_cache_handles_classes(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_compiler_cache_handles_references_to_globals(): xmodule = "\n".join([ "aList = []", @@ -330,6 +342,7 @@ def test_compiler_cache_handles_references_to_globals(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_compiler_cache_handles_changed_types(): xmodule1 = "\n".join([ "@Entrypoint", @@ -371,6 +384,7 @@ def test_compiler_cache_handles_changed_types(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_ordering_is_stable_under_code_change(): # check that the order of functions in a MutuallyRecursiveTypeGroup is # stable even if we change the code underneath it. diff --git a/typed_python/compiler/expression_conversion_context.py b/typed_python/compiler/expression_conversion_context.py index c4af7b40d..926315960 100644 --- a/typed_python/compiler/expression_conversion_context.py +++ b/typed_python/compiler/expression_conversion_context.py @@ -108,7 +108,7 @@ def getTypePointer(self, t): raise Exception(f"Can't give a type pointer to {t} because its not a type") return native_ast.Expression.GlobalVariable( - name="type_pointer_" + str(id(t)) + "_" + str(t)[:20], + name="type_pointer_" + str(id(t)) + "_" + t.__name__[:50], type=native_ast.VoidPtr, metadata=GlobalVariableMetadata.RawTypePointer( value=t @@ -1286,53 +1286,44 @@ def pushException(self, excType, *args, **kwargs): Returns: None """ - if len(args) == 0 and isinstance(excType, type): - self.pushEffect( - runtime_functions.np_raise_exception_str.call( - self.constantPyObject(excType).nonref_expr.cast(native_ast.VoidPtr), - native_ast.UInt8.pointer().zero(), - ) - ) - return None - - if len(args) == 1 and isinstance(args[0], str) and isinstance(excType, type): - # this is the most common pathway - self.pushEffect( - runtime_functions.np_raise_exception_str.call( - self.constantPyObject(excType).nonref_expr.cast(native_ast.VoidPtr), - native_ast.const_utf8_cstr(args[0]), - ) - ) - return None - def toTyped(x): if isinstance(x, TypedExpression): return x return self.constant(x) - origExcType = excType - excType = toTyped(excType) - args = [toTyped(x) for x in args] + args = [toTyped(excType)] + [toTyped(x) for x in args] kwargs = {k: toTyped(v) for k, v in kwargs.items()} - if len(args) == 1 and isinstance(args[0].constantValue, str) and isinstance(origExcType, type): - self.pushEffect( - runtime_functions.np_raise_exception_str.call( - self.constantPyObject(origExcType).nonref_expr.cast(native_ast.VoidPtr), - native_ast.const_utf8_cstr(args[0].constantValue), - ) - ) - return None + args = [a.demasquerade() for a in args] + kwargs = {k: v.demasquerade() for k, v in kwargs.items()} - if excType is None: - return None + # we converted everything to python objects. We need to pass this + # ensemble to the interpreter. We use c-style variadic arguments here + # since everything is a pointer. + arguments = [] + kwarguments = [] - exceptionVal = excType.convert_call(args, kwargs) + for a in args: + a = a.ensureIsReference() - if exceptionVal is None: - return None + arguments.append(a.expr.cast(native_ast.VoidPtr)) + arguments.append(self.getTypePointer(a.expr_type.typeRepresentation)) - return self.pushExceptionObject(exceptionVal) + for kwargName, kwargVal in kwargs.items(): + kwargVal = kwargVal.ensureIsReference() + + kwarguments.append(kwargVal.expr.cast(native_ast.VoidPtr)) + kwarguments.append(self.getTypePointer(kwargVal.expr_type.typeRepresentation)) + kwarguments.append(native_ast.const_utf8_cstr(kwargName)) + + return self.pushEffect( + runtime_functions.call_pyobj_and_raise.call( + native_ast.const_int_expr(len(args)), + native_ast.const_int_expr(len(kwargs)), + *arguments, + *kwarguments, + ) + ) def pushExceptionClear(self): nativeExpr = ( @@ -1368,8 +1359,7 @@ def pushExceptionObjectWithCause(self, exceptionObject, causeObject, deferred=Fa if exceptionObject is None: exceptionObject = self.zero(object) - if causeObject.expr_type.typeRepresentation is type(None): # noqa - causeObject = self.zero(object) + causeObject = causeObject.toPyObj() nativeExpr = ( runtime_functions.initialize_exception_w_cause.call( diff --git a/typed_python/compiler/function_conversion_context.py b/typed_python/compiler/function_conversion_context.py index e4d89798b..abf858853 100644 --- a/typed_python/compiler/function_conversion_context.py +++ b/typed_python/compiler/function_conversion_context.py @@ -1950,6 +1950,32 @@ def _convert_statement_ast(self, ast, variableStates: FunctionStackState, contro if ast.exc is None: toThrow = None # means reraise else: + if ( + ast.exc.matches.Call + and len(ast.exc.args) == 1 + and not ast.exc.keywords + and not ast.exc.args[0].matches.Starred + and ast.cause is None + ): + exceptionT = expr_context.convert_expression_ast(ast.exc.func) + if exceptionT is None: + return ( + expr_context.finalize(None, exceptionsTakeFrom=None if ast.exc is None else ast), False + ) + + exceptionArg = expr_context.convert_expression_ast(ast.exc.args[0]) + if exceptionArg is None: + return ( + expr_context.finalize(None, exceptionsTakeFrom=None if ast.exc is None else ast), False + ) + + expr_context.pushException( + exceptionT, + exceptionArg + ) + + return expr_context.finalize(None, exceptionsTakeFrom=None if ast.exc is None else ast), False + toThrow = expr_context.convert_expression_ast(ast.exc) if toThrow is None: diff --git a/typed_python/compiler/llvm_compiler_test.py b/typed_python/compiler/llvm_compiler_test.py index e10f94533..ede697d79 100644 --- a/typed_python/compiler/llvm_compiler_test.py +++ b/typed_python/compiler/llvm_compiler_test.py @@ -24,6 +24,7 @@ import ctypes +@pytest.mark.group_one def test_global_variable_pointers(): readGlobalVarFunc = Function( args=[], @@ -94,6 +95,7 @@ def test_global_variable_pointers(): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_create_binary_shared_object(): f = Function( args=[], diff --git a/typed_python/compiler/merge_type_wrappers_test.py b/typed_python/compiler/merge_type_wrappers_test.py index 5d691b584..624fe14e4 100644 --- a/typed_python/compiler/merge_type_wrappers_test.py +++ b/typed_python/compiler/merge_type_wrappers_test.py @@ -10,6 +10,7 @@ class Child(Base): pass +@pytest.mark.group_one def test_merge_types(): assert mergeTypes([float, int]) == OneOf(float, int) assert mergeTypes([float, Value(1)]) == OneOf(1, float) diff --git a/typed_python/compiler/native_ast_to_llvm.py b/typed_python/compiler/native_ast_to_llvm.py index 830814b4d..4850ed959 100644 --- a/typed_python/compiler/native_ast_to_llvm.py +++ b/typed_python/compiler/native_ast_to_llvm.py @@ -849,7 +849,7 @@ def _convert(self, expr): for i in range(len(exprs)): value = self.builder.insert_value(value, exprs[i], i) - return TypedLLVMValue(value, native_ast.Type.Struct(names_and_types)) + return TypedLLVMValue(value, native_ast.Type.Struct(element_types=names_and_types)) if expr.matches.StructElementByIndex: val = self.convert(expr.left) diff --git a/typed_python/compiler/native_ast_to_llvm_test.py b/typed_python/compiler/native_ast_to_llvm_test.py index e2430d511..d8600d0eb 100644 --- a/typed_python/compiler/native_ast_to_llvm_test.py +++ b/typed_python/compiler/native_ast_to_llvm_test.py @@ -36,6 +36,7 @@ def externalCallTarget(name, output, *inputs): class TestNativeAstToLlvm(unittest.TestCase): + @pytest.mark.group_one def test_teardowns(self): converter = native_ast_to_llvm.Converter() diff --git a/typed_python/compiler/python_ast_analysis_test.py b/typed_python/compiler/python_ast_analysis_test.py index dca23170e..13923920a 100644 --- a/typed_python/compiler/python_ast_analysis_test.py +++ b/typed_python/compiler/python_ast_analysis_test.py @@ -35,11 +35,13 @@ def freeVarCheck(self, func, readVars, assignedVars): set(readVars) ) + @pytest.mark.group_one def test_free_vars_basic(self): self.freeVarCheck(lambda: x, ['x'], []) # noqa self.freeVarCheck(lambda: x + y, ['x', 'y'], []) # noqa self.freeVarCheck(lambda: f(*args), ['f', 'args'], []) # noqa + @pytest.mark.group_one def test_assignment_shows_up(self): def f(): x = 10 @@ -47,6 +49,7 @@ def f(): self.freeVarCheck(f, ['x'], ['x']) + @pytest.mark.group_one def test_assigned_only_once(self): def f(): x = 10 @@ -80,6 +83,7 @@ def h1(): self.assertEqual(sorted(assignedOnce), ["g", "h", "h1", "y"]) self.assertEqual(assignmentCount, dict(x=2, y=1, f=2, g=1, h=1, h1=1)) + @pytest.mark.group_one def test_read_by_closures(self): def f(): def f1(): @@ -101,6 +105,7 @@ def y(): self.assertEqual(sorted(readByClosures), ["x", "y", "z"]) + @pytest.mark.group_one def test_func_def_masking_self(self): def f(): class C: @@ -113,12 +118,14 @@ def func(self): self.assertEqual(sorted(readByClosures), ["func"]) + @pytest.mark.group_one def test_multi_assignment_shows_up(self): def f(): x, y = (1, 2) # noqa self.freeVarCheck(f, [], ['x', 'y']) + @pytest.mark.group_one def test_for_loops(self): def f(): for i in 10: @@ -126,6 +133,7 @@ def f(): self.freeVarCheck(f, [], ['i']) + @pytest.mark.group_one def test_function_defs(self): def f(): def aFun(x): @@ -136,6 +144,7 @@ def aFun2(*args, **kwargs): self.freeVarCheck(f, ['y'], ['aFun', 'aFun2']) + @pytest.mark.group_one def test_class_defs(self): def f(): class AClass: @@ -147,6 +156,7 @@ def f(x): self.freeVarCheck(f, ['z'], ['AClass']) + @pytest.mark.group_one def test_function_default_args(self): SomeVar = None @@ -156,6 +166,7 @@ def someFunc(x=SomeVar()): self.freeVarCheck(f, ['SomeVar'], ['someFunc']) + @pytest.mark.group_one def test_function_annotations(self): Something = None @@ -177,6 +188,7 @@ def someFunc(**x: Something): self.freeVarCheck(f, ['Something'], ['someFunc']) + @pytest.mark.group_one def test_iterators_in_generators_not_assigned(self): something = None z = None @@ -186,6 +198,7 @@ def f(): self.freeVarCheck(f, ['something', 'z'], ['x']) + @pytest.mark.group_one def test_iterators_in_generators_masking(self): # this does read from 'y' even though it masks the 'y' inside y = None @@ -216,6 +229,7 @@ def f(): self.freeVarCheck(f, ['something', 'z'], ['x']) + @pytest.mark.group_one def test_import_aliases(self): def f(): import a.b # noqa @@ -225,6 +239,7 @@ def f(): assert python_ast_analysis.computeAssignedVariables(pyast.body) == {'a', 'blah'} + @pytest.mark.group_one def test_variables_read_perf(self): evaluator = CodeEvaluator() diff --git a/typed_python/compiler/python_to_native_converter.py b/typed_python/compiler/python_to_native_converter.py index 787321203..c9bb2748a 100644 --- a/typed_python/compiler/python_to_native_converter.py +++ b/typed_python/compiler/python_to_native_converter.py @@ -916,20 +916,19 @@ def _installInflightFunctions(self, name): self._currentlyConverting = None for identifier, functionConverter in self._inflight_function_conversions.items(): + outboundTargets = [] + for outboundFuncId in self._dependencies.getNamesDependedOn(identifier): + name = self._link_name_for_identity[outboundFuncId] + outboundTargets.append(self._targets[name]) + + nativeFunction, actual_output_type = self._inflight_definitions.get(identifier) + if identifier in self._identifier_to_pyfunc: for v in self._visitors: - funcName, funcCode, funcGlobals, closureVars, input_types, output_type, conversionType = ( self._identifier_to_pyfunc[identifier] ) - nativeFunction, actual_output_type = self._inflight_definitions.get(identifier) - - outboundTargets = [] - for outboundFuncId in self._dependencies.getNamesDependedOn(identifier): - name = self._link_name_for_identity[outboundFuncId] - outboundTargets.append(self._targets[name]) - try: v.onNewFunction( identifier, @@ -948,6 +947,15 @@ def _installInflightFunctions(self, name): ) except Exception: logging.exception("event handler %s threw an unexpected exception", v.onNewFunction) + else: + for v in self._visitors: + v.onNewNonpythonFunction( + identifier, + self._link_name_for_identity[identifier], + functionConverter, + nativeFunction, + outboundTargets + ) if identifier not in self._inflight_definitions: raise Exception( diff --git a/typed_python/compiler/runtime.py b/typed_python/compiler/runtime.py index ef31062a4..8621147a0 100644 --- a/typed_python/compiler/runtime.py +++ b/typed_python/compiler/runtime.py @@ -61,6 +61,16 @@ def onNewFunction( ): pass + def onNewNonpythonFunction( + self, + identifier, + linkName, + functionConverter, + nativeFunction, + outboundTargets + ): + pass + def __enter__(self): Runtime.singleton().addEventVisitor(self) return self @@ -134,6 +144,30 @@ def onNewFunction( for callTarget in calledFunctions: print(" ", callTarget) + def onNewNonpythonFunction( + self, + identifier, + linkName, + functionConverter, + nativeFunction, + calledFunctions + ): + if self.short: + print( + f"[complexity={len(str(nativeFunction)):8d}] ", + linkName + ) + else: + print("compiling ", linkName) + print(" identifier ", identifier) + print(" inputs: ", functionConverter.getInputTypes()) + print(" output: ", functionConverter.knownOutputType()) + + if calledFunctions: + print(" calls:") + for callTarget in calledFunctions: + print(" ", callTarget) + class CountCompilationsVisitor(RuntimeEventVisitor): def __init__(self): diff --git a/typed_python/compiler/tests/alternative_compilation_test.py b/typed_python/compiler/tests/alternative_compilation_test.py index 61fc71390..2a76c8522 100644 --- a/typed_python/compiler/tests/alternative_compilation_test.py +++ b/typed_python/compiler/tests/alternative_compilation_test.py @@ -28,6 +28,7 @@ class TestAlternativeCompilation(unittest.TestCase): + @pytest.mark.group_one def test_could_be_instance_of(self): A = Alternative("A", A=dict(x=int), B=dict(x=int)) B = Alternative("A", A=dict(x=int), B=dict(x=int)) @@ -45,6 +46,7 @@ def test_could_be_instance_of(self): assert classCouldBeInstanceOf(A.A, A) == True # noqa assert classCouldBeInstanceOf(A.A, A.A) == True # noqa + @pytest.mark.group_one def test_default_constructor(self): @Entrypoint def setIt(d, x): @@ -56,6 +58,7 @@ def setIt(d, x): assert setIt(Dict(int, Simple)(), 10).matches.A assert setIt(Dict(int, Complex)(), 10).matches.A + @pytest.mark.group_one def test_simple_alternative_passing(self): Simple = Alternative("Simple", A={}, B={}, C={}) @@ -68,6 +71,7 @@ def f(s: Simple): self.assertEqual(f(Simple.B()), Simple.B()) self.assertEqual(f(Simple.C()), Simple.C()) + @pytest.mark.group_one def test_complex_alternative_passing(self): Complex = Forward("Complex") Complex = Complex.define(Alternative( @@ -91,6 +95,7 @@ def f(c: Complex): self.assertEqual(_types.refcount(c), 2) self.assertEqual(_types.refcount(c2), 1) + @pytest.mark.group_one def test_construct_alternative(self): A = Alternative("A", X={'x': int}) @@ -101,6 +106,7 @@ def f(): self.assertTrue(f().matches.X) self.assertEqual(f().x, 10) + @pytest.mark.group_one def test_alternative_matches(self): A = Alternative("A", X={'x': int}, Y={'x': int}) @@ -111,6 +117,7 @@ def f(x: A): self.assertTrue(f(A.X())) self.assertFalse(f(A.Y())) + @pytest.mark.group_one def test_alternative_member_homogenous(self): A = Alternative("A", X={'x': int}, Y={'x': int}) @@ -121,6 +128,7 @@ def f(x: A): self.assertEqual(f(A.X(x=10)), 10) self.assertEqual(f(A.Y(x=10)), 10) + @pytest.mark.group_one def test_alternative_member_diverse(self): A = Alternative("A", X={'x': int}, Y={'x': float}) @@ -131,6 +139,7 @@ def f(x: A): self.assertEqual(f(A.X(x=10)), 10) self.assertEqual(f(A.Y(x=10.5)), 10.5) + @pytest.mark.group_one def test_alternative_member_distinct(self): A = Alternative("A", X={'x': int}, Y={'y': float}) @@ -144,6 +153,7 @@ def f(x: A): self.assertEqual(f(A.X(x=10)), 10) self.assertEqual(f(A.Y(y=10.5)), 10.5) + @pytest.mark.group_one def test_matching_recursively(self): @TypeFunction def Tree(T): @@ -184,6 +194,7 @@ def buildTree(depth: int, offset: int) -> Tree(int): speedup = (t1-t0)/(t2-t1) self.assertGreater(speedup, 20) # I get about 50 + @pytest.mark.group_one def test_compile_alternative_magic_methods(self): A = Alternative("A", a={'a': int}, b={'b': str}, @@ -380,6 +391,7 @@ def f_ipow(x: A): print("mismatch") self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_alternative_reverse_methods(self): A = Alternative("A", a={'a': int}, b={'b': str}, @@ -449,6 +461,7 @@ def f_ror(v: T, x: A): r2 = compiled_f(v, A.a()) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_alternative_format(self): A1 = Alternative("A1", a={'a': int}, b={'b': str}) A2 = Alternative("A2", a={'a': int}, b={'b': str}, @@ -501,6 +514,7 @@ def specialized_format(x): r2 = specialized_format(v) self.assertEqual(r1, r2, type(v)) + @pytest.mark.group_one def test_compile_alternative_bytes(self): A = Alternative("A", a={'a': int}, b={'b': str}, __bytes__=lambda self: b'my bytes' @@ -515,6 +529,7 @@ def f_bytes(x: A): r2 = c_f(v) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_alternative_attr(self): def A_getattr(self, n): @@ -618,6 +633,7 @@ def f_delattr2(x: A): with self.assertRaises(KeyError): c_getattr2(v) + @pytest.mark.group_one def test_compile_alternative_float_methods(self): # if __float__ is defined, then floor() and ceil() are based off this conversion, # when __floor__ and __ceil__ are not defined @@ -676,6 +692,7 @@ def f_ceil(x: B): r2 = compiled_f(B.a()) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_alternative_dir(self): # The interpreted dir() calls __dir__() and sorts the result. # I expected the compiled dir() to do the same thing, but it doesn't sort. @@ -724,6 +741,7 @@ def f_dir(x: A): self.assertTrue(finalMem < initMem + 2) + @pytest.mark.group_one def test_compile_alternative_comparison_defaults(self): B = Alternative("B", a={'a': int}, b={'b': str}) @@ -766,6 +784,7 @@ def f_hash(x: B): r2 = compiled_f(v) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_alternative_comparison_methods(self): C = Alternative("C", a={'a': int}, b={'b': str}, @@ -807,6 +826,7 @@ def f_hash(x: C): r2 = compiled_f(C.a()) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_alternative_getsetitem(self): def A2_getitem(self, i): @@ -844,6 +864,7 @@ def f_setitem(a: A2, i: int, v: int): self.assertEqual(f_getitem(a, i), i + 200) self.assertEqual(c_getitem(a, i), i + 200) + @pytest.mark.group_one def test_compile_simple_alternative_magic_methods(self): A = Alternative("A", a={}, b={}, @@ -1040,6 +1061,7 @@ def f_ipow(x: A): r2 = compiled_f(A.a()) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_simple_alternative_reverse_methods(self): A = Alternative("A", a={}, b={}, @@ -1109,6 +1131,7 @@ def f_ror(v: T, x: A): r2 = compiled_f(v, A.a()) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_simple_alternative_format(self): A1 = Alternative("A1", a={}, b={}) A2 = Alternative("A2", a={}, b={}, @@ -1161,6 +1184,7 @@ def specialized_format(x): r2 = specialized_format(v) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_simple_alternative_bytes(self): A = Alternative("A", a={}, b={}, __bytes__=lambda self: b'my bytes' @@ -1178,6 +1202,7 @@ def f_bytes(x: A): # I think this would require nonlocal data @pytest.mark.skip(reason="not supported") + @pytest.mark.group_one def test_compile_simple_alternative_attr(self): def A_getattr(self, n): return self.d[n] @@ -1280,6 +1305,7 @@ def f_delattr2(x: A): with self.assertRaises(TypeError): c_getattr2(v) + @pytest.mark.group_one def test_compile_simple_alternative_float_methods(self): # if __float__ is defined, then floor() and ceil() are based off this conversion, # when __floor__ and __ceil__ are not defined @@ -1338,6 +1364,7 @@ def f_ceil(x: B): r2 = compiled_f(B.a()) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_simple_dir(self): # The interpreted dir() calls __dir__() and sorts the result. # I expected the compiled dir() to do the same thing, but it doesn't sort. @@ -1386,6 +1413,7 @@ def f_dir(x: A): self.assertTrue(finalMem < initMem + 2) + @pytest.mark.group_one def test_compile_simple_alternative_comparison_defaults(self): B = Alternative("B", a={}, b={}) @@ -1428,6 +1456,7 @@ def f_hash(x: B): r2 = compiled_f(v) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_simple_alternative_comparison_methods(self): C = Alternative("C", a={}, b={}, __eq__=lambda self, other: True, @@ -1468,6 +1497,7 @@ def f_hash(x: C): r2 = compiled_f(C.a()) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_alternative_float_conv(self): A0 = Alternative("A0", a={}, b={}, @@ -1497,6 +1527,7 @@ def g(x: int): with self.assertRaises(TypeError): c_g(A0.a()) + @pytest.mark.group_one def test_compile_alternative_missing_inplace_fallback(self): def A_add(self, other): return A.b(" add" + other.b) @@ -1588,6 +1619,7 @@ def inplace(x: A): r2 = Compiled(inplace)(v) self.assertEqual(r2, expected) + @pytest.mark.group_one def test_compile_alternative_methods(self): def method(self, x): return self.y + x @@ -1615,6 +1647,7 @@ def callMethod2(a: A.Y, x): ) @pytest.mark.skip(reason="not supported") + @pytest.mark.group_one def test_context_manager(self): def A_enter(self): @@ -1676,6 +1709,7 @@ def g(x: int) -> ListOf(str): r1 = c_fn(v) self.assertEqual(r0, r1) + @pytest.mark.group_one def test_matches_on_alternative(self): A = Alternative("A", X=dict(x=int)) @@ -1685,6 +1719,7 @@ def checkMatchesX(x): assert checkMatchesX(A.X()) + @pytest.mark.group_one def test_matches_on_oneof_alternative(self): A = Alternative("A", X=dict(x=int)) B = Alternative("B", Y=dict(y=int)) @@ -1696,6 +1731,7 @@ def checkMatchesX(x: OneOf(A, B, int)): assert checkMatchesX(A.X()) assert not checkMatchesX(B.Y()) + @pytest.mark.group_one def test_can_cast_simple_alternative_down(self): A = Alternative("A", X=dict()) @@ -1711,6 +1747,7 @@ def g(x: A): assert g(A.X()) == 1 + @pytest.mark.group_one def test_can_cast_alternative_down(self): A = Alternative("A", X=dict(x=int)) @@ -1726,12 +1763,14 @@ def g(x: A): assert g(A.X(x=10)) == 10 + @pytest.mark.group_one def test_alternative_hashing(self): A = Alternative("A", A=dict(a=int)) assert NativeHash.callHash(A.A, A.A(a=12)) == hash(A.A(a=12)) assert NativeHash.callHash(A, A.A(a=12)) == hash(A.A(a=12)) + @pytest.mark.group_one def test_alternative_equality(self): AB = Alternative("AB", A=dict(a=int), B=dict(b=str)) @@ -1755,6 +1794,7 @@ def eq(a1: AB, a2: AB): assert eqMixed(AB.A(a=1), AB.A(a=1)) assert eqConcrete(AB.A(a=1), AB.A(a=1)) + @pytest.mark.group_one def test_compiled_attribute_access(self): A = Alternative( "A", diff --git a/typed_python/compiler/tests/any_all_compilation_test.py b/typed_python/compiler/tests/any_all_compilation_test.py index 366d14bdd..1d1c8cbff 100644 --- a/typed_python/compiler/tests/any_all_compilation_test.py +++ b/typed_python/compiler/tests/any_all_compilation_test.py @@ -15,6 +15,7 @@ from typed_python import Entrypoint, TupleOf +@pytest.mark.group_one def test_compiles_any_and_all(): @Entrypoint def callAny(x): diff --git a/typed_python/compiler/tests/arithmetic_compilation_test.py b/typed_python/compiler/tests/arithmetic_compilation_test.py index 60dc37762..28afa5bc7 100644 --- a/typed_python/compiler/tests/arithmetic_compilation_test.py +++ b/typed_python/compiler/tests/arithmetic_compilation_test.py @@ -107,6 +107,7 @@ def neq(x: In, y: In) -> Out: class TestArithmeticCompilation(unittest.TestCase): + @pytest.mark.group_one def test_compile_simple(self): @Compiled def f(x: int) -> int: @@ -115,6 +116,7 @@ def f(x: int) -> int: self.assertEqual(f(20), 60) self.assertEqual(f(10), 30) + @pytest.mark.group_one def test_in_to_out(self): @Compiled def identity(x: In) -> Out: @@ -170,6 +172,7 @@ def checkFunctionOfIntegers(self, f): for i in range(100): self.assertEqual(f_fast(i), f(i)) + @pytest.mark.group_one def test_assignment_of_pod(self): def f(x: int) -> int: y = x @@ -177,6 +180,7 @@ def f(x: int) -> int: self.checkFunctionOfIntegers(f) + @pytest.mark.group_one def test_simple_loop(self): def f(x: int) -> int: y = 0 @@ -187,6 +191,7 @@ def f(x: int) -> int: self.checkFunctionOfIntegers(f) + @pytest.mark.group_one def test_call_other_typed_function(self): def g(x: int) -> int: return x+1 @@ -196,6 +201,7 @@ def f(x: int) -> int: self.checkFunctionOfIntegers(f) + @pytest.mark.group_one def test_basic_type_conversion(self): def f(x: int) -> int: y = 1.5 @@ -203,6 +209,7 @@ def f(x: int) -> int: self.checkFunctionOfIntegers(f) + @pytest.mark.group_one def test_integers_in_closures(self): y = 2 @@ -211,6 +218,7 @@ def f(x: int) -> int: self.checkFunctionOfIntegers(f) + @pytest.mark.group_one def test_negation(self): @Compiled def negate_int(x: int): @@ -223,6 +231,7 @@ def negate_float(x: float): self.assertEqual(negate_int(10), -10) self.assertEqual(negate_float(20.5), -20.5) + @pytest.mark.group_one def test_can_stringify_unsigned(self): @Entrypoint def toString(x): @@ -233,6 +242,7 @@ def toString(x): self.assertEqual(toString(UInt16(10)), "10u16") self.assertEqual(toString(UInt8(10)), "10u8") + @pytest.mark.group_one def test_can_compile_register_builtins(self): registerTypes = [bool, Int8, Int16, Int32, int, UInt8, UInt16, UInt32, UInt64, Float32, float] @@ -295,6 +305,7 @@ def f_format(x: T): # e.g. round(float(1), 0) returns int when interpreted, # but float when compiled + @pytest.mark.group_one def test_can_call_types_with_no_args(self): @Entrypoint def makeEmpty(T): @@ -305,6 +316,7 @@ def makeEmpty(T): self.assertEqual(makeEmpty(bool), False) self.assertEqual(makeEmpty(str), "") + @pytest.mark.group_one def test_not_on_float(self): @Entrypoint def doit(f): @@ -315,6 +327,7 @@ def doit(f): self.assertEqual(doit(1.0), "its true") self.assertEqual(doit(0.0), "its false") + @pytest.mark.group_one def test_can_compile_register_operations(self): failed = False @@ -594,6 +607,7 @@ def pow(x: T1, y: T2): self.assertFalse(failed) + @pytest.mark.group_one def test_int_of_nan(self): @Entrypoint def f(x): @@ -605,6 +619,7 @@ def f(x): with self.assertRaisesRegex(Exception, "infinity"): f(inf) + @pytest.mark.group_one def test_mod_constant_in_tuple(self): @Entrypoint def rf(row): @@ -612,6 +627,7 @@ def rf(row): self.assertEqual(rf(makeNamedTuple(x=1.0)), 0.0) + @pytest.mark.group_one def test_pow_with_bad_inputs(self): @Entrypoint def callPow(x, y): @@ -623,6 +639,7 @@ def callPow(x, y): with self.assertRaises(ZeroDivisionError): callPow(0, -1) + @pytest.mark.group_one def test_floordiv_with_bad_inputs(self): @Entrypoint def callFloordiv(x, y): @@ -634,6 +651,7 @@ def callFloordiv(x, y): with self.assertRaises(ZeroDivisionError): callFloordiv(1, 0) + @pytest.mark.group_one def test_shift_with_bad_inputs(self): @Entrypoint def callShift(x, y): @@ -645,6 +663,7 @@ def callShift(x, y): with self.assertRaises(OverflowError): callShift(1, 2048) + @pytest.mark.group_one def test_formatting_with_format_strings_works(self): @Entrypoint def format(x): @@ -652,6 +671,7 @@ def format(x): assert format(1.0) == f"{1.0:.6g}" + @pytest.mark.group_one def test_formatting_strings_in_loop(self): @Entrypoint def format(a, b, c, d): @@ -662,6 +682,7 @@ def format(a, b, c, d): format(1, 2, 3, 4) + @pytest.mark.group_one def test_string_joining_in_loop(self): @Entrypoint def format(a, b, c, d): @@ -676,6 +697,7 @@ def format(a, b, c, d): format(1, 2, 3, 4) + @pytest.mark.group_one def test_unary_ops_on_constants(self): @Entrypoint def sliceAtPositiveZero(x): diff --git a/typed_python/compiler/tests/builtin_compilation_test.py b/typed_python/compiler/tests/builtin_compilation_test.py index bb4a04979..ec2b50d43 100644 --- a/typed_python/compiler/tests/builtin_compilation_test.py +++ b/typed_python/compiler/tests/builtin_compilation_test.py @@ -31,6 +31,7 @@ def result_or_exception(f, *p): class TestBuiltinCompilation(unittest.TestCase): + @pytest.mark.group_one def test_builtins_on_various_types(self): NT1 = NamedTuple(a=int, b=float, c=str, d=str) NT2 = NamedTuple(s=str, t=TupleOf(int)) @@ -167,6 +168,7 @@ def f_dir(x: T): c_f(T(v)) self.assertEqual(r1, r2, (T, v, f)) + @pytest.mark.group_one def test_min_max(self): def f_min(*v): return min(*v) @@ -210,6 +212,7 @@ def f_max(*v): self.assertEqual(r1, r2) self.assertEqual(type(r1), type(r2)) + @pytest.mark.group_one def test_min_max_with_key(self): T = OneOf(str, ListOf(int), TupleOf(int), Set(int)) @@ -283,6 +286,7 @@ def f_max4(*v): with self.assertRaises(TypeError): Entrypoint(f)(v) + @pytest.mark.group_one def test_min_max_iterable(self): def f_min(v): return min(v) @@ -342,6 +346,7 @@ def f_max(v): self.assertEqual(r1, r2, (f, v)) self.assertEqual(type(r1), type(r2)) + @pytest.mark.group_one def test_min_max_iterable_with_key(self): T = OneOf(str, ListOf(int), TupleOf(int), Set(int)) @@ -398,6 +403,7 @@ def f_max2(v): self.assertEqual(r1, r2) self.assertEqual(type(r1), type(r2)) + @pytest.mark.group_one def test_min_max_defaults(self): def f_min(v): return min(v) @@ -440,6 +446,7 @@ def f_max_key_default(v, default): self.assertEqual(f(v, d), d) self.assertEqual(Entrypoint(f)(v, d), d) + @pytest.mark.group_one def test_min_max_extra_kwargs(self): def f_min_kw(v, **kw): return min(v, **kw) @@ -454,6 +461,7 @@ def f_max_kw(v, **kw): with self.assertRaises(TypeError): Entrypoint(f)(v, x=99) + @pytest.mark.group_one def test_min_max_cover(self): # these functions are compiled indirectly and tested elsewhere # to avoid codecov failures, they appear here @@ -469,6 +477,7 @@ def test_min_max_cover(self): i_max_key(v, k) i_max_key_default(v, k, d) + @pytest.mark.group_one def test_min_max_with_object(self): @Entrypoint def minOI(x: object, y: int): @@ -503,6 +512,7 @@ def maxOO(x: object, y: object): assert maxIO(x, y) == max(x, y) assert maxOO(x, y) == max(x, y) + @pytest.mark.group_one def test_abs_of_object(self): @Entrypoint def callAbs(o: object): diff --git a/typed_python/compiler/tests/bytes_compilation_test.py b/typed_python/compiler/tests/bytes_compilation_test.py index 93b5dae3e..eceb949cb 100644 --- a/typed_python/compiler/tests/bytes_compilation_test.py +++ b/typed_python/compiler/tests/bytes_compilation_test.py @@ -45,6 +45,7 @@ def result_or_exception(f, *p): class TestBytesCompilation(unittest.TestCase): + @pytest.mark.group_one def test_bytes_passing_and_refcounting(self): @Compiled def takeFirst(x: bytes, y: bytes): @@ -59,6 +60,7 @@ def takeSecond(x: bytes, y: bytes): self.assertEqual(s, takeFirst(s, s2)) self.assertEqual(s2, takeSecond(s, s2)) + @pytest.mark.group_one def test_bytes_len(self): @Compiled def compiledLen(x: bytes): @@ -67,6 +69,7 @@ def compiledLen(x: bytes): for s in someBytes: self.assertEqual(len(s), compiledLen(s)) + @pytest.mark.group_one def test_bytes_concatenation(self): @Compiled def concat(x: bytes, y: bytes): @@ -81,6 +84,7 @@ def concatLen(x: bytes, y: bytes): self.assertEqual(s+s2, concat(s, s2)) self.assertEqual(len(s+s2), concatLen(s, s2)) + @pytest.mark.group_one def test_bytes_constants(self): def makeConstantConcatenator(s): def returner(): @@ -93,6 +97,7 @@ def returner(): self.assertEqual(s, s_from_code, (repr(s), repr(s_from_code))) + @pytest.mark.group_one def test_bytes_getitem(self): @Compiled def getitem(x: bytes, y: int): @@ -111,6 +116,7 @@ def callOrExcept(f, *args): ) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_bytes_perf(self): def bytesAdd(x: bytes): i = 0 @@ -137,6 +143,7 @@ def bytesAdd(x: bytes): # I get about 200 self.assertGreater(speedup, 50) + @pytest.mark.group_one def test_bytes_literals(self): def f(i: int): @@ -154,6 +161,7 @@ def g(i: int): self.assertEqual(f(i), cf(i)) self.assertEqual(g(i), cg(i)) + @pytest.mark.group_one def test_bytes_conversions(self): def f(x: bytes): @@ -173,6 +181,7 @@ def f(x: bytes): # for v in ['123', 'abcdefgh', 'a\u00CAb', 'XyZ\U0001D471']: # self.assertEqual(g(v), cg(v)) + @pytest.mark.group_one def test_bytes_slice(self): def f(x: bytes, l: int, r: int): return x[l:r] @@ -184,6 +193,7 @@ def f(x: bytes, l: int, r: int): for b in [b"", b"a", b"as", b"asdf"]: self.assertEqual(fComp(b, l, r), f(b, l, r)) + @pytest.mark.group_one def test_compare_bytes_to_constant(self): @Entrypoint def countEqualTo(z): @@ -206,6 +216,7 @@ def countEqualTo(z): self.assertLess(elapsed, .15) print("elapsed = ", elapsed) + @pytest.mark.group_one def test_add_constants(self): @Entrypoint def addConstants(count): @@ -222,6 +233,7 @@ def addConstants(count): # llvm should recognize that this is just 'N' and so it should take no time. self.assertLess(time.time() - t0, 1e-4) + @pytest.mark.group_one def test_bytes_split(self): def split(someBytes, *args, **kwargs): return someBytes.split(*args, **kwargs) @@ -285,6 +297,7 @@ def rsplit(someBytes, *args, **kwargs): compiledRsplit(b'abc', b'') @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_bytes_split_perf(self): def splitAndCount(s: bytes, sep: bytes, times: int): res = 0 @@ -308,6 +321,7 @@ def splitAndCount(s: bytes, sep: bytes, times: int): f"Compiler was {compiled / uncompiled} times slower." ) + @pytest.mark.group_one def test_bytes_iteration(self): def iter(x: bytes): r = ListOf(int)() @@ -346,6 +360,7 @@ def f_index(x: bytes, i: int): r2 = Compiled(contains_space)(v) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_bytes_bool_fns(self): def f_isalnum(x): return x.isalnum() @@ -382,6 +397,7 @@ def f_isupper(x): r2 = Entrypoint(f)(v) self.assertEqual(r1, r2, (f, v)) + @pytest.mark.group_one def test_bytes_startswith_endswith(self): def f_startswith(x, *args): return x.startswith(*args) @@ -404,6 +420,7 @@ def f_endswith(x, *args): r2 = c_f(x, y, start, end) self.assertEqual(r1, r2, (f, x, y, start, end)) + @pytest.mark.group_one def test_bytes_case(self): def f_lower(x): return x.lower() @@ -428,6 +445,7 @@ def f_title(x): r2 = Entrypoint(f)(v) self.assertEqual(r1, r2, (f, v)) + @pytest.mark.group_one def test_bytes_strip(self): def f_strip(x): return x.strip() @@ -463,6 +481,7 @@ def f_rstrip2(x, y): r2 = Entrypoint(f)(v, y) self.assertEqual(r1, r2, (f, v, y)) + @pytest.mark.group_one def test_bytes_strip_bad_arg(self): @Entrypoint def strip(x, y): @@ -471,6 +490,7 @@ def strip(x, y): with self.assertRaises(TypeError): strip(b"asdf", 10) + @pytest.mark.group_one def test_bytes_count(self): def f_count(x, sub): return x.count(sub) @@ -501,6 +521,7 @@ def f_count3(x, sub, start, end): r2 = Entrypoint(f)(v, sub, start, end) self.assertEqual(r1, r2, (v, sub, start, end)) + @pytest.mark.group_one def test_bytes_find(self): def f_find(x, sub): return x.find(sub) @@ -580,6 +601,7 @@ def f_rindex3(x, sub, start, end): with self.assertRaises(ValueError): Entrypoint(g)(v, sub, start, end) + @pytest.mark.group_one def test_bytes_mult(self): def f_mult(x, n): return x * n @@ -590,6 +612,7 @@ def f_mult(x, n): r2 = Entrypoint(f_mult)(v, n) self.assertEqual(r1, r2, n) + @pytest.mark.group_one def test_bytes_contains_bytes(self): @Entrypoint def f_contains(x, y): @@ -609,6 +632,7 @@ def f_not_contains(x, y): self.assertTrue(f_not_contains(b'b', ListOf(bytes)([b'asfd']))) self.assertFalse(f_not_contains(b'asdf', ListOf(bytes)([b'asdf']))) + @pytest.mark.group_one def test_bytes_replace(self): def replace(x: bytes, y: bytes, z: bytes): return x.replace(y, z) @@ -668,6 +692,7 @@ def validate_joining_bytes(self, function, make_obj): res = function(separator, make_obj(items)) self.assertEqual(expected, res, description) + @pytest.mark.group_one def test_bytes_join_for_tuple_of_bytes(self): # test passing tuple of bytes @Compiled @@ -676,6 +701,7 @@ def f(sep: bytes, items: TupleOf(bytes)) -> bytes: self.validate_joining_bytes(f, lambda items: TupleOf(bytes)(items)) + @pytest.mark.group_one def test_bytes_join_for_list_of_bytes(self): # test passing list of bytes @Compiled @@ -684,6 +710,7 @@ def f(sep: bytes, items: ListOf(bytes)) -> bytes: self.validate_joining_bytes(f, lambda items: ListOf(bytes)(items)) + @pytest.mark.group_one def test_bytes_join_for_dict_of_bytes(self): # test passing list of bytes @Compiled @@ -692,6 +719,7 @@ def f(sep: bytes, items: Dict(bytes, bytes)) -> bytes: self.validate_joining_bytes(f, lambda items: Dict(bytes, bytes)({i: b"a" for i in items})) + @pytest.mark.group_one def test_bytes_join_for_const_dict_of_bytes(self): # test passing list of bytes @Compiled @@ -700,6 +728,7 @@ def f(sep: bytes, items: ConstDict(bytes, bytes)) -> bytes: self.validate_joining_bytes(f, lambda items: ConstDict(bytes, bytes)({i: b"a" for i in items})) + @pytest.mark.group_one def test_bytes_join_for_bad_types(self): """bytes.join supports only joining iterables of bytes.""" @@ -719,6 +748,7 @@ def f_int(sep: bytes, items: ListOf(str)) -> bytes: with self.assertRaisesRegex(TypeError, ""): f_int(b",", ListOf(int)(["1", "2", "3"])) + @pytest.mark.group_one def test_bytes_decode(self): def f_decode1(x, _i1, _i2): return x.decode() @@ -737,6 +767,7 @@ def f_decode3(x, enc, err): r2 = result_or_exception(Entrypoint(f), v, enc, err) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_bytes_translate(self): def f_translate1(x, table): return x.translate(table) @@ -804,6 +835,7 @@ def f_maketrans3(t, x, y): r2 = result_or_exception(Entrypoint(f_maketrans3), bytes, x, y) self.assertEqual(r1, r2, (f_maketrans3, x, y)) + @pytest.mark.group_one def test_bytes_partition(self): def f_partition(x, sep): return x.partition(sep) @@ -824,6 +856,7 @@ def f_rpartition(x, sep): with self.assertRaises(TypeError): Entrypoint(f)(v, 'abc') + @pytest.mark.group_one def test_bytes_just(self): def f_center(x, w, fill): if fill == ' ': @@ -858,6 +891,7 @@ def f_rjust(x, w, fill): with self.assertRaises(TypeError): Entrypoint(f)(v, w, 'X') + @pytest.mark.group_one def test_bytes_to_int(self): @Entrypoint def bytesToInt(x: bytes): @@ -868,6 +902,7 @@ def bytesToInt(x: bytes): assert bytesToInt(b'') == 0 + @pytest.mark.group_one def test_bytes_tabs(self): def f_expandtabs(x, t): return x.expandtabs(t) @@ -894,6 +929,7 @@ def f_splitlines(x, *a): r2 = Entrypoint(f_splitlines)(v, k) self.assertEqual(r1, r2, (v, k)) + @pytest.mark.group_one def test_bytes_zfill(self): def f_zfill(x, w): return x.zfill(w) @@ -904,6 +940,7 @@ def f_zfill(x, w): r2 = Entrypoint(f_zfill)(v, w) self.assertEqual(r1, r2, (v, w)) + @pytest.mark.group_one def test_bytes_internal_fns(self): """ These are functions that are normally not called directly. diff --git a/typed_python/compiler/tests/class_compilation_test.py b/typed_python/compiler/tests/class_compilation_test.py index f9c1fcee8..260ac96ca 100644 --- a/typed_python/compiler/tests/class_compilation_test.py +++ b/typed_python/compiler/tests/class_compilation_test.py @@ -39,6 +39,7 @@ typeKnownToCompiler, SubclassOf, Held, + NamedTuple ) import typed_python._types as _types from typed_python.compiler.runtime import Entrypoint, Runtime, CountCompilationsVisitor @@ -135,6 +136,7 @@ def __init__(self, x, y): # noqa: F811 class TestClassCompilationCompilation(unittest.TestCase): + @pytest.mark.group_one def test_initializes_correctly(self): ShouldInitializeMembers().x @@ -144,6 +146,7 @@ def f(): f().x + @pytest.mark.group_one def test_class_attribute(self): a = AClass(x=10, y=20.5, z=(1, 2, 3)) @@ -163,6 +166,7 @@ def getZ(a: AClass) -> TupleOf(int): self.assertEqual(getY(a), a.y) self.assertEqual(getZ(a), a.z) + @pytest.mark.group_one def test_class_set_attribute(self): a = AClass() @@ -202,6 +206,7 @@ def setZ(a: AClass, z: TupleOf(int)) -> None: self.assertEqual(_types.refcount(aTupleOfInt), 1) + @pytest.mark.group_one def test_class_uninitialized_attribute(self): @Compiled def set(ac: AClassWithAnotherClass, a: AClass) -> None: @@ -247,6 +252,7 @@ def get(ac: AClassWithAnotherClass) -> AClass: self.assertEqual(_types.refcount(ac2), 2) self.assertEqual(get(anAWithAClass).x, 2) + @pytest.mark.group_one def test_call_method_basic(self): @Compiled def g(c: AClass): @@ -259,6 +265,7 @@ def g(c: AClass): self.assertEqual(g(c2), c2.g()) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_call_method_dispatch_perf(self): @Compiled def addCaller(c: AClass, count: int): @@ -286,6 +293,7 @@ def addCaller(c: AClass, count: int): # tun this test. Note that we generate two entrypoints (one for float, one for int) self.assertTrue(0.5 <= elapsed1 / elapsed2 <= 2.0, elapsed1 / elapsed2) + @pytest.mark.group_one def test_compile_class_method(self): c = AClass(x=20) @@ -306,6 +314,7 @@ def test_compile_class_method(self): print("speedup is ", speedup) # I get about 75 + @pytest.mark.group_one def test_dispatch_up_to_class_method(self): class TestClass(Class, Final): def f(self, x: OneOf(int, float)): @@ -318,6 +327,7 @@ def compiled(c: TestClass, x: float): self.assertEqual(compiled(TestClass(), 123), 124.0) self.assertEqual(compiled(TestClass(), 123.5), 124.5) + @pytest.mark.group_one def test_compile_class_init(self): @Compiled def f(x: int) -> AClassWithInit: @@ -326,6 +336,7 @@ def f(x: int) -> AClassWithInit: self.assertEqual(f(10).x, 10) self.assertEqual(f(10).y, 22.0) + @pytest.mark.group_one def test_compile_class_init_with_defaults(self): @Compiled def f() -> AClassWithDefaults: @@ -334,6 +345,7 @@ def f() -> AClassWithDefaults: self.assertEqual(f().x, 123) self.assertEqual(f().y, 0) + @pytest.mark.group_one def test_compile_class_repr_and_str(self): class RegularClassWithReprAndString: def __repr__(self): @@ -366,6 +378,7 @@ def callStr(x): self.assertEqual(callRepr(ClassWithReprAndStr()), "repr") self.assertEqual(callStr(ClassWithReprAndStr()), "str") + @pytest.mark.group_one def test_class_str_without_override(self): class NoStr(Class): x = Member(int) @@ -379,6 +392,7 @@ def callStr(x): assert str(n) == callStr(n) + @pytest.mark.group_one def test_compiled_class_subclass_layout(self): class BaseClass(Class): x = Member(int) @@ -396,6 +410,7 @@ def f(x: BaseClass): self.assertEqual(fCompiled(c), f(c)) + @pytest.mark.group_one def test_class_subclass_destructors(self): class BaseClass(Class): pass @@ -414,6 +429,7 @@ class ChildClass(BaseClass): self.assertEqual(_types.refcount(aListOfInt), 1) + @pytest.mark.group_one def test_class_subclass_destructors_compiled(self): class BaseClass(Class): pass @@ -437,6 +453,7 @@ def clearList(l): self.assertEqual(_types.refcount(aListOfInt), 1) + @pytest.mark.group_one def test_dispatch_with_multiple_overloads(self): # check that we can dispatch appropriately class TestClass(Class): @@ -473,6 +490,7 @@ def callWithInt(c: TestClass, x: int): self.assertEqual(callWithStr(TestClass(), ""), TestClass().f("")) self.assertEqual(callWithStr(TestClass(), "hi"), TestClass().f("hi")) + @pytest.mark.group_one def test_multiple_child_dispatches(self): # child specializations should get to look at an argument # of type 'OneOf(int, float)' and get to decide if they want to handle it. @@ -500,6 +518,7 @@ def call(c: BaseClass, x: OneOf(int, float)): self.assertEqual(call(ChildClass(), 1), "child: int") self.assertEqual(call(ChildClass(), 1.0), "child: float") + @pytest.mark.group_one def test_multiple_child_dispatches_with_arg_dispatch(self): # the child specializations should get to look at an argument # of type 'OneOf(int, float)' and get to decide if they want to handle it. @@ -530,6 +549,7 @@ def call2(c: BaseClass, x: int, y: int): self.assertEqual(call1(ChildClass(), 1), 11) self.assertEqual(call2(ChildClass(), 1, 2), 12) + @pytest.mark.group_one def test_dispatch_to_none_works(self): class BaseClass(Class): def f(self, x) -> int: @@ -546,6 +566,7 @@ def call(c: BaseClass, x: int): self.assertEqual(call(BaseClass(), 1), 1) self.assertEqual(call(ChildClass(), 1), 2) + @pytest.mark.group_one def test_dispatch_to_subclass_from_list(self): class BaseClass(Class): def f(self) -> int: @@ -604,6 +625,7 @@ def addFsUncompiled(c: ListOf(BaseClass), times: int): self.assertGreater(speedup, 20) + @pytest.mark.group_one def test_convert_up_in_compiled_code(self): class BaseClass(Class): def f(self) -> int: @@ -629,6 +651,7 @@ def dispatchUp(x: ChildClass): self.assertEqual(dispatchUp(ChildChildClass()), ChildChildClass().f()) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_perf_of_dispatch_with_final_is_fast(self): class BaseClass(Class): def f(self) -> float: @@ -662,6 +685,7 @@ def addFs(c, times: int): self.assertGreater(speedup, 1.2) + @pytest.mark.group_one def test_dispatch_with_different_types(self): class BaseClass(Class, Final): def f(self, x: int) -> str: @@ -677,6 +701,7 @@ def f(c: BaseClass, x: OneOf(int, float)): self.assertEqual(f(BaseClass(), 0), "int") self.assertEqual(f(BaseClass(), 1.0), "float") + @pytest.mark.group_one def test_dispatch_with_different_output_types(self): class BaseClass(Class, Final): def f(self, x: int) -> int: @@ -694,6 +719,7 @@ def f(x): self.assertEqual(f.resultTypeFor(OneOf(int, float)).typeRepresentation, OneOf(float, int)) self.assertEqual(f.resultTypeFor(object).typeRepresentation, OneOf(float, int)) + @pytest.mark.group_one def test_dispatch_with_no_specified_output_types(self): class BaseClass(Class): def f(self, x: int) -> object: @@ -722,6 +748,7 @@ def fFinal(x): self.assertEqual(fFinal.resultTypeFor(int).typeRepresentation, int) self.assertEqual(fFinal.resultTypeFor(float).typeRepresentation, float) + @pytest.mark.group_one def test_classes_with_lots_of_members(self): class BaseClass(Class): x00 = Member(int) @@ -756,6 +783,7 @@ def f(c: BaseClass): self.assertEqual(f(c), 10) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_class_member_perf_with_final(self): class BaseClass(Class): x0 = Member(float) @@ -790,6 +818,7 @@ def sumX0Child(x: ChildClass, t: int): self.assertTrue(0.7 < speedup < 1.3, speedup) + @pytest.mark.group_one def test_class_return_self(self): class C(Class): def e(self) -> object: @@ -802,6 +831,7 @@ def f(a: C) -> object: c_f = Compiled(f) self.assertIsInstance(c_f(C()), C) + @pytest.mark.group_one def test_compile_class_magic_methods(self): class C(Class, Final): s = Member(str) @@ -1037,6 +1067,7 @@ def f_ipow(x: C): r2 = compiled_f(C("")) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_class_reverse_methods(self): class C(Class, Final): s = Member(str) @@ -1126,6 +1157,7 @@ def f_ror(v: T, x: C): r2 = compiled_f(v, C()) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_class_format(self): class C1(Class, Final): pass @@ -1178,6 +1210,7 @@ def specialized_format(x): r2 = specialized_format(v) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_class_bytes(self): class C(Class, Final): __bytes__ = lambda self: b"my bytes" @@ -1191,6 +1224,7 @@ def f_bytes(x: C): r2 = c_f(v) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_class_delitem(self): class C(Class, Final): deleted = Member(int) @@ -1206,6 +1240,7 @@ def delIt(c, k): delIt(c, 10) assert c.deleted == 10 + @pytest.mark.group_one def test_compile_class_attr(self): class C(Class, Final): d = Member(Dict(str, str)) @@ -1306,6 +1341,7 @@ def f_delattr2(x: C): with self.assertRaises(KeyError): c_getattr2(v) + @pytest.mark.group_one def test_compile_class_float_methods(self): # if __float__ is defined, then floor() and ceil() are based off this conversion, # when __floor__ and __ceil__ are not defined @@ -1362,6 +1398,7 @@ def f_ceil(x: C2): r2 = compiled_f(C2()) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_class_dir(self): # The interpreted dir() calls __dir__() and sorts the result. # I expected the compiled dir() to do the same thing, but it doesn't sort. @@ -1416,6 +1453,7 @@ def f_dir(x: C): self.assertTrue(finalMem < initMem + 2) + @pytest.mark.group_one def test_compile_class_comparison_defaults(self): class C(Class, Final): i = Member(int) @@ -1458,6 +1496,7 @@ def f_hash(x: C): r2 = result_or_exception(compiled_f, v) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_class_comparison_to_other_types(self): class C(Class, Final): x = Member(int) @@ -1472,6 +1511,7 @@ def isEqObj(c: C, o: object): self.assertTrue(isEqObj(C(x=10), C(x=10))) self.assertTrue(isEqObj(C(x=10), makeNamedTuple(x=10))) + @pytest.mark.group_one def test_compile_class_comparison_methods(self): class C(Class, Final): i = Member(int) @@ -1534,6 +1574,7 @@ def f_hash(x: C): r2 = compiled_f(v) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_compile_class_hash_special_value(self): class C(Class, Final): i = Member(int) @@ -1550,6 +1591,7 @@ def f_hash(x: C): self.assertEqual(f_hash(C(i=-1)), -2) self.assertEqual(c_hash(C(i=-1)), -2) + @pytest.mark.group_one def test_compile_class_getsetitem(self): class C(Class, Final): d = Member(Dict(int, int)) @@ -1584,6 +1626,7 @@ def f_setitem(c: C, i: int, v: int): self.assertEqual(f_getitem(c, i), i + 200) self.assertEqual(c_getitem(c, i), i + 200) + @pytest.mark.group_one def test_compile_class_float_conv(self): class C0(Class, Final): __int__ = lambda self: 123 @@ -1610,6 +1653,7 @@ def g(x: int): with self.assertRaises(TypeError): c_g(C0()) + @pytest.mark.group_one def test_compile_class_missing_inplace_fallback(self): class ClassWithoutInplaceOp(Class, Final): s = Member(str) @@ -1692,6 +1736,7 @@ def inplace(x: ClassWithoutInplaceOp): r2 = Compiled(inplace)(v) self.assertEqual(r2.s, expected.s) + @pytest.mark.group_one def test_defining_float_doesnt_allow_implicit_conversion(self): aList = ListOf(float)() @@ -1727,6 +1772,7 @@ def tryToCallRequiresAFloat(): def compileCheck(self, f): self.assertEqual(f(), Compiled(f)()) + @pytest.mark.group_one def test_class_can_override_default_args(self): class B(Class): def f(self, x=10) -> int: @@ -1750,6 +1796,7 @@ def f(self, x=30) -> int: self.compileCheck(lambda: D().f(10)) self.compileCheck(lambda: D().f(20)) + @pytest.mark.group_one def test_class_methods_and_named_arguments(self): class B(Class): def f(self, **kwargs: int) -> int: @@ -1774,6 +1821,7 @@ def f(self) -> int: # noqa self.compileCheck(lambda: B().f(x=10, y=20)) self.compileCheck(lambda: C().f(x=10, y=20)) + @pytest.mark.group_one def test_class_method_star_arg_type_dispatch(self): class B(Class): def f(self, *args: int, **kwargs: int) -> int: @@ -1782,6 +1830,7 @@ def f(self, *args: int, **kwargs: int) -> int: self.assertEqual(B().f(1.5, x=2.5), 0) self.compileCheck(lambda: B().f(1.5, x=2.5)) + @pytest.mark.group_one def test_class_method_star_arg_type_dispatch_unknown(self): class B(Class): def f(self, *args: int, **kwargs: int) -> str: @@ -1797,6 +1846,7 @@ def callBWith(o: object): assert callBWith(1.0) == "float" assert callBWith(1) == "int" + @pytest.mark.group_one def test_class_methods_obey_star_arg_type_assignments(self): class B(Class): def f(self, *args, **kwargs) -> int: @@ -1843,6 +1893,7 @@ def f(self, *args: str, **kwargs: int) -> int: # noqa self.compileCheck(lambda: T().f(1, y="2")) self.compileCheck(lambda: T().f(1, y="2")) + @pytest.mark.group_one def test_class_with_global_closure_variables(self): def makeInt(): return 10 @@ -1894,6 +1945,7 @@ def takeLen(): self.assertEqual(takeLen(), 10) + @pytest.mark.group_one def test_pass_child_to_function_expecting_base_and_kwargs(self): class X(Class): def f(self, **kwargs) -> str: @@ -1918,6 +1970,7 @@ def done(): done() + @pytest.mark.group_one def test_compile_class_properties(self): class X(Class, Final): @property @@ -1932,6 +1985,7 @@ def callIt(): self.assertEqual(callIt(), 10) + @pytest.mark.group_one def test_compile_class_properties_with_subclasses(self): class X(Class): @property @@ -1953,6 +2007,7 @@ def callIt(x: X): self.assertEqual(callIt(X()), 10) self.assertEqual(callIt(Child()), 20) + @pytest.mark.group_one def test_overloading_operators(self): class X(Class, Final): def __add__(self, other: int): @@ -1971,6 +2026,7 @@ def add(x, y): self.assertEqual(add(X(), 1), 1) self.assertEqual(add(X(), 1.5), 2) + @pytest.mark.group_one def test_default_initialize_class_with_type_members(self): class C(Class, Final): t = Member(Value(float)) @@ -1983,6 +2039,7 @@ def callIt(): assert callIt().t is float + @pytest.mark.group_one def test_can_compile_against_base_class_and_pass_child(self): class C(Class): t = Member(float) @@ -2024,6 +2081,7 @@ def clearList(x: ListOf(C)): clearList(aList) assert _types.refcount(theB) == 1 + @pytest.mark.group_one def test_class_member_assign_is_implicit_containers(self): class C(Class, Final): x = Member(ListOf(ListOf(int))) @@ -2036,6 +2094,7 @@ def assignX(c, x): assignX(C(), [ListOf(int)([1, 2, 3])]) + @pytest.mark.group_one def test_kwarg_initialize_class(self): @Entrypoint def makeAClass(x, y, z): @@ -2043,6 +2102,7 @@ def makeAClass(x, y, z): assert makeAClass(1, 2, (3, 4)).z == TupleOf(int)((3, 4)) + @pytest.mark.group_one def test_class_assign_invalid_member(self): @Entrypoint def assignInvalid(c): @@ -2051,6 +2111,7 @@ def assignInvalid(c): with self.assertRaisesRegex(AttributeError, "no attribute 'invalidMember'"): assignInvalid(AClass()) + @pytest.mark.group_one def test_kwarg_initialize_class_invalid_arg(self): def makeAClass(x, y, z): return AClass(x=x, invalidMember=z, y=y) @@ -2061,6 +2122,7 @@ def makeAClass(x, y, z): with self.assertRaisesRegex(AttributeError, "has no attribute 'invalidMember'"): Entrypoint(makeAClass)(1, 2, (3, 4)) + @pytest.mark.group_one def test_kwarg_initialize_method(self): def initializeAClass(**kwargs): return AClassWithInit(**kwargs) @@ -2073,6 +2135,7 @@ def checkEqual(l, r): checkEqual(Entrypoint(initializeAClass)(x=1), initializeAClass(x=1)) checkEqual(Entrypoint(initializeAClass)(x=1, y=2), initializeAClass(x=1, y=2)) + @pytest.mark.group_one def test_pointer_to_member(self): class C(Class, Final): x = Member(int) @@ -2085,6 +2148,7 @@ def f(c): assert f(c) == pointerTo(c).x + @pytest.mark.group_one def test_type_of_subclass(self): class Base(Class): pass @@ -2104,6 +2168,7 @@ def fKnowsChild(c: Child): assert f(Child()) is Child assert fKnowsChild(Child()) is Child + @pytest.mark.group_one def test_isinstance_on_subclass(self): class Base(Class): pass @@ -2118,6 +2183,7 @@ def isinstanceCompiled(c: Base): assert not isinstanceCompiled(Base()) assert isinstanceCompiled(Child()) + @pytest.mark.group_one def test_isinstance_on_two_subclasses(self): class Base(Class): pass @@ -2134,6 +2200,7 @@ def isinstanceCompiled(l: Base, r: Base): assert isinstanceCompiled(Child(), Child()) assert not isinstanceCompiled(Base(), Child()) + @pytest.mark.group_one def test_downcast_in_compiled_code(self): class Base(Class): pass @@ -2154,6 +2221,7 @@ def g(x: Base): with self.assertRaises(TypeError): g(Base()) + @pytest.mark.group_one def test_downcast_in_compiled_code_adjacent(self): class Base(Class): def baseFun(self) -> int: @@ -2240,6 +2308,7 @@ def callFromBase1(f, x: Base1): # to cross call it assert callFromBase1(callAsBase2, Child()) == 3 + @pytest.mark.group_one def test_class_nonempty(self): class CNonempty(Class, Final): x = Member(str, nonempty=True) @@ -2288,6 +2357,7 @@ def setX(x, xVal): setX(cE, "hihi") assert getX(cE) == "hihi" + @pytest.mark.group_one def test_class_nonempty_forces_construction(self): class SomeOtherClass(Class): pass @@ -2313,6 +2383,7 @@ def callIt(X): with self.assertRaisesRegex(Exception, "Attribute 'x' is not initialized"): callIt(CEmpty).x + @pytest.mark.group_one def test_class_hierarchy(self): class Base(Class): def f(self) -> int: @@ -2333,6 +2404,7 @@ def callG(x: Base): assert callG(C1()) == Entrypoint(callG)(C1()) + @pytest.mark.group_one def test_convert_refTo(self): class C(Class, Final): x = Member(int) @@ -2350,6 +2422,7 @@ def doIt(): assert doIt() == 10 + @pytest.mark.group_one def test_call_overridden_fun(self): class C(Class): def getIt(self) -> int: @@ -2365,6 +2438,7 @@ def f(c: C): f(C()) + @pytest.mark.group_one def test_isinstance_perf(self): class C(Class): pass @@ -2410,6 +2484,7 @@ def countIt(times, c: C): # an exactly known type. assert elapsed < 0.01 + @pytest.mark.group_one def test_unresolved_forwards_in_class_type_signatures(self): UnresolvedForward = Forward("UnresolvedForward") @@ -2424,6 +2499,7 @@ def tryToCallF(): with self.assertRaisesRegex(TypeError, "unresolved forwards"): tryToCallF() + @pytest.mark.group_one def test_unresolved_forwards_in_function_type_signatures(self): UnresolvedForward = Forward("UnresolvedForward") @@ -2438,6 +2514,7 @@ def tryToCallF(): with self.assertRaisesRegex(TypeError, "has unresolved forwards"): tryToCallF() + @pytest.mark.group_one def test_could_be_instance_of(self): class A(Class): pass @@ -2522,6 +2599,7 @@ def g(self) -> X: class ActualSubclass(TF1(int), TF2(float)): pass + @pytest.mark.group_one def test_super(self): class B(Class): def f(self, x): @@ -2537,6 +2615,7 @@ def callIt(c, x): assert callIt(C(), 10) == 11 + @pytest.mark.group_one def test_super_with_diamond(self): class B(Class): def f(self, x: ListOf(str)): @@ -2571,6 +2650,7 @@ def callIt(c, x): assert lst == ['E', 'C', 'D', 'B'] + @pytest.mark.group_one def test_super_with_no_superclass(self): class B(Class): def f(self): @@ -2586,6 +2666,7 @@ def callIt(c): with self.assertRaisesRegex(AttributeError, r"'super' object has no attribute 'f'"): callIt(B()) + @pytest.mark.group_one def test_super_in_init(self): class B(Class): x = Member(int) @@ -2608,6 +2689,7 @@ def check(): check() Entrypoint(check)() + @pytest.mark.group_one def test_compile_classmethods(self): class Normal: @classmethod @@ -2629,6 +2711,7 @@ def checkIt(): checkIt() Entrypoint(checkIt)() + @pytest.mark.group_one def test_compile_classmethod_on_subclass_multi(self): class B(Class): @classmethod @@ -2653,6 +2736,7 @@ def callIt(b: B, x: OneOf(int, float)): assert callIt(C(), 1) == 2 assert callIt(C(), 1.0) == 1.5 + @pytest.mark.group_one def test_compile_staticmethod_on_subclass_multi(self): class B(Class): @staticmethod @@ -2677,6 +2761,7 @@ def callIt(b: B, x: OneOf(int, float)): assert callIt(C(), 1) == 2 assert callIt(C(), 1.0) == 1.5 + @pytest.mark.group_one def test_compile_classmethod_on_subclass(self): class BPy(object): @classmethod @@ -2760,6 +2845,7 @@ def callIt(b: SubclassOf(T), times: int): print("compiled virtual dispatch on instances ", speedup, "times faster") print("compiled virtual dispatch on type ", speedupType, "times faster") + @pytest.mark.group_one def test_compile_staticmethod_on_subclass(self): class B(Class): @staticmethod @@ -2791,6 +2877,7 @@ def callIt(b: T, times: int): assert callItAs(B)(B(), 1000000) == 1000000 assert callItAs(B)(C(), 1000000) == 2000000 + @pytest.mark.group_one def test_class_dispatch_on_type(self): class B(Class): @classmethod @@ -2804,6 +2891,7 @@ def call(T: SubclassOf(B)): assert call.resultTypeFor(SubclassOf(B)).typeRepresentation is int assert call(B) == 0 + @pytest.mark.group_one def test_interpreter_can_see_class_members(self): class B(Class): X = int @@ -2819,6 +2907,7 @@ def callInst(T: B): assert callType.resultTypeFor(SubclassOf(B)).typeRepresentation.Value is int assert callInst.resultTypeFor(B).typeRepresentation.Value is int + @pytest.mark.group_one def test_class_init_is_virtual(self): B = Forward("B") @@ -2857,6 +2946,7 @@ def constructOne(T: SubclassOf(B), x, times): assert constructOne(C, 0, 1000000) == C(0).f() * 1000000 print(time.time() - t0) + @pytest.mark.group_one def test_implicit_conversion_to_bool(self): class C(Class): def __len__(self) -> int: @@ -2870,6 +2960,7 @@ def check(c): check(C()) + @pytest.mark.group_one def test_del_during_unwind_works(self): class C(Class): def f(self): @@ -2900,6 +2991,7 @@ def outer(): except Exception: pass + @pytest.mark.group_one def test_del_works(self): delType = ListOf(type)() @@ -2922,6 +3014,7 @@ def doIt(): assert len(delType) == 2 assert delType[1] == Held(C) + @pytest.mark.group_one def test_del_swallows_exception(self): class C(Class): def __del__(self): @@ -2933,6 +3026,7 @@ def doIt(): doIt() Entrypoint(doIt)() + @pytest.mark.group_one def test_class_hasattr(self): class C(Class): x = Member(int) @@ -2970,6 +3064,7 @@ def compiledDel(): compiledDel() + @pytest.mark.group_one def test_class_hasattr_perf(self): class C(Class): x = Member(float) @@ -3002,6 +3097,7 @@ def loopWithHasattr(c): assert .6 < elapsedWithout / elapsedWith < 1.4 + @pytest.mark.group_one def test_virtual_dispatch_with_none(self): class C(Class): def f(self, x, y): @@ -3016,3 +3112,16 @@ def callf(c: C): return c.f(1, None) callf(B()) + + def test_call_method_with_oneof(self): + N = NamedTuple(x=int) + + class C(Class): + def f(self, x: N) -> int: + return x.x + + @Entrypoint + def call(c: C, x: OneOf(None, N)): + return c.f(x) + + call(C(), N(x=10)) diff --git a/typed_python/compiler/tests/closures_test.py b/typed_python/compiler/tests/closures_test.py index 2cbb55791..476bca5bb 100644 --- a/typed_python/compiler/tests/closures_test.py +++ b/typed_python/compiler/tests/closures_test.py @@ -59,6 +59,7 @@ def onNewFunction( class TestCompilingClosures(unittest.TestCase): + @pytest.mark.group_one def test_closure_of_untyped_function(self): x = 10 @@ -69,6 +70,7 @@ def f(): self.assertEqual(f.ClosureType.ElementTypes[0].ElementTypes[0], PyCell) self.assertTrue('x' in f.overloads[0].closureVarLookups) + @pytest.mark.group_one def test_lambda_with_same_code_doesnt_retrigger_compile(self): def makeAdder(): def add(x, y): @@ -95,6 +97,7 @@ def callFun(f, x, y): # we shouldn't have triggered compilation. self.assertFalse(vis.didCompile) + @pytest.mark.group_one def test_closure_grabbing_types(self): T = int @@ -107,6 +110,7 @@ def f(x): self.assertEqual(f(1.5), 1) self.assertEqual(bytecount(f.ClosureType), 8) + @pytest.mark.group_one def test_closure_grabbing_closures(self): x = 10 @@ -120,6 +124,7 @@ def g(): self.assertEqual(g(), x) + @pytest.mark.group_one def test_calling_closure_with_bound_args(self): x = 10 @@ -133,6 +138,7 @@ def callIt(arg): self.assertEqual(callIt(20), 30) + @pytest.mark.group_one def test_passing_closures_as_arguments(self): x = 10 @@ -147,6 +153,7 @@ def callIt(f, arg): self.assertEqual(callIt(f, 20), 30) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_calling_closures_perf(self): ct = 1000000 @@ -198,6 +205,7 @@ def append(y): self.assertLess(elapsedCompiled * 60, elapsedNontyped) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_assigning_closures_as_values(self): ct = 100000 @@ -274,6 +282,7 @@ def alternatingCall(c1, c2, ct): self.assertTrue(elapsedCompiled * 2 < elapsedNontyped) @pytest.mark.skip(reason="compiled code can't call closures holding untyped cells yet.") + @pytest.mark.group_one def test_closure_in_listof(self): def makeAdder(x): @Function @@ -302,6 +311,7 @@ def callEachItemManyTimes(l, times): self.assertEqual(resUncompiled, resCompiled) + @pytest.mark.group_one def test_mutually_recursive_closures(self): @Function def f(x): @@ -318,6 +328,7 @@ def g(x): self.assertEqual(f(10), 0) + @pytest.mark.group_one def test_typed_cell(self): T = TypedCell(int) @@ -344,12 +355,14 @@ def test_typed_cell(self): with self.assertRaises(Exception): t.get() + @pytest.mark.group_one def test_typed_cell_in_tuple(self): TC = TypedCell(int) aTup = NamedTuple(x=TC)(x=TC()) aTup.x.set(1) + @pytest.mark.group_one def test_typed_cell_with_forwards(self): Tup = Forward("Tup") Tup = Tup.define(NamedTuple(cell=TypedCell(Tup), x=int)) @@ -367,6 +380,7 @@ def test_typed_cell_with_forwards(self): self.assertEqual(t1.cell.get().cell.get().x, 1) self.assertEqual(t2.cell.get().cell.get().x, 2) + @pytest.mark.group_one def test_function_overload_with_closures(self): @Function def f(): @@ -402,6 +416,7 @@ def f2(anArg, anArg2, anArg3): self.assertEqual(combo(1, 2), 30) self.assertEqual(combo(1, 2, 3), 40) + @pytest.mark.group_one def test_pass_untyped_function_to_entrypoint_ignores_signature(self): @Entrypoint def callWithFloat(f): @@ -413,6 +428,7 @@ def f(x: int): self.assertEqual(callWithFloat(f), 1.5) self.assertEqual(callWithFloat(Function(f)), 1) + @pytest.mark.group_one def test_pass_untyped_function_to_entrypoint(self): @Entrypoint def returnIt(f): @@ -423,6 +439,7 @@ def f(x): returnIt(f) + @pytest.mark.group_one def test_pass_typed_function_to_entrypoint(self): @Entrypoint def returnIt(f): @@ -434,6 +451,7 @@ def f(x): self.assertEqual(returnIt(f)(10), 11) + @pytest.mark.group_one def test_access_untyped_function(self): @Entrypoint def callIt(x): @@ -445,6 +463,7 @@ def f(x): self.assertEqual(callIt(10), 11) + @pytest.mark.group_one def test_access_untyped_function_with_string_in_closure(self): y = "hi" @@ -458,6 +477,7 @@ def f(x): self.assertEqual(callIt("10"), "10hi") + @pytest.mark.group_one def test_pass_function_with_bound_variable(self): @Entrypoint def returnIt(f): @@ -485,6 +505,7 @@ def f(): # different from python but unavoidable self.assertNotEqual(fRes(), fRes2()) + @pytest.mark.group_one def test_pass_function_holding_function(self): @Entrypoint def returnIt(f): @@ -512,6 +533,7 @@ def h(): self.assertEqual(fRes.withEntrypoint(True)(), x) + @pytest.mark.group_one def test_pass_mutually_recursive_functions(self): @Entrypoint def returnIt(f): @@ -547,6 +569,7 @@ def g(x): # for each function call. print("took ", time.time() - t0, " to do 100k closure conversions") + @pytest.mark.group_one def test_no_recompile_for_same_function_body(self): def makeAdder(x): def adder(y): @@ -569,6 +592,7 @@ def callIt(f, x): self.assertFalse(vis.didCompile) + @pytest.mark.group_one def test_pass_closures_from_compiled_code_with_no_capture(self): def doIt(): def f(): @@ -581,6 +605,7 @@ def callIt(aFun): self.assertEqual(doIt(), Entrypoint(doIt)()) + @pytest.mark.group_one def test_call_mutually_recursive_closures_from_compiled_code(self): def doIt(count): def f(x): @@ -597,6 +622,7 @@ def g(x): self.assertEqual(doIt(100), compiledDoIt(100)) + @pytest.mark.group_one def test_closure_in_compiled_code_with_variable(self): def doIt(): x = 10 @@ -608,6 +634,7 @@ def f(): self.assertEqual(doIt(), Entrypoint(doIt)()) + @pytest.mark.group_one def test_closure_in_compiled_code_with_variable_that_changes(self): def doIt(): x = 10 @@ -625,12 +652,14 @@ def f(): self.assertEqual(doIt(), Entrypoint(doIt)()) + @pytest.mark.group_one def test_lambdas_in_compiled_code(self): def doIt(x): return (lambda y: x + y)(x) self.assertEqual(Entrypoint(doIt)(10), doIt(10)) + @pytest.mark.group_one def test_closure_in_compiled_code_bind_pod_arg(self): def doIt(x): def f(y): @@ -640,6 +669,7 @@ def f(y): self.assertEqual(Entrypoint(doIt)(10), doIt(10)) + @pytest.mark.group_one def test_closure_in_compiled_code_refcounts(self): def doIt(tup): def f(y): @@ -654,6 +684,7 @@ def f(y): self.assertEqual(refcount(aTup), 1) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_closure_var_lookup_speed(self): def sum(count, f): res = 0.0 @@ -693,6 +724,7 @@ def sumItDirect(count): self.assertTrue(.8 <= closureTime / directTime <= 1.2, closureTime / directTime) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_if_statement_def(self): def callIt(x): if x % 2: @@ -723,6 +755,7 @@ def f(y): print("speedup is ", speedup) # I get about 80 self.assertGreater(speedup, 60) + @pytest.mark.group_one def test_assign_functions_with_closure_works(self): def callIt(x): y = 10.0 @@ -746,6 +779,7 @@ def f(a): self.assertEqual(callItE(i), callIt(i)) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_assign_functions_with_closure_perf(self): def callIt(x): y = 10.0 @@ -778,6 +812,7 @@ def f(a): print("speedup is ", speedup) # I get about 8 self.assertGreater(speedup, 6) + @pytest.mark.group_one def test_two_closure_vars(self): @Entrypoint def callIt(x): @@ -796,6 +831,7 @@ def f(): self.assertEqual(callIt(1), 20) + @pytest.mark.group_one def test_mutually_recursive_assigned_variables(self): def callIt(x): if x % 2: @@ -827,6 +863,7 @@ def g(y): for i in range(10): self.assertEqual(callItE(i), callIt(i)) + @pytest.mark.group_one def test_closure_bound_in_class(self): def makeClass(i): def fExternal(): @@ -850,6 +887,7 @@ def callF(c): self.assertEqual(callF(C1()), 1) self.assertEqual(callF(C2()), 2) + @pytest.mark.group_one def test_calling_doesnt_leak(self): @Entrypoint def g(x): @@ -869,6 +907,7 @@ def f(x): assert currentMemUsageMb() - m0 < 2.0 + @pytest.mark.group_one def test_building_closures_doesnt_leak(self): m0 = currentMemUsageMb() t0 = time.time() @@ -882,6 +921,7 @@ def f(x): assert currentMemUsageMb() - m0 < 2.0 + @pytest.mark.group_one def test_building_closures_of_closures_doesnt_leak(self): m0 = currentMemUsageMb() t0 = time.time() @@ -897,6 +937,7 @@ def g(x): assert currentMemUsageMb() - m0 < 2.0 + @pytest.mark.group_one def test_building_notcompiled_with_closures_doesnt_leak(self): m0 = currentMemUsageMb() t0 = time.time() @@ -915,6 +956,7 @@ def g(x): assert currentMemUsageMb() - m0 < 2.0 + @pytest.mark.group_one def test_calling_notcompiled_doesnt_leak(self): @Entrypoint def callIt(x): @@ -930,6 +972,7 @@ def callIt(x): assert currentMemUsageMb() - m0 < 2.0 + @pytest.mark.group_one def test_calling_entrypoint_with_closures_doesnt_leak(self): @Entrypoint def callIt(f, x): @@ -945,6 +988,7 @@ def callIt(f, x): assert currentMemUsageMb() - m0 < 2.0 + @pytest.mark.group_one def test_type_inference_doesnt_leak(self): def g(x): return x + 2.0 @@ -963,6 +1007,7 @@ def callIt(x): assert currentMemUsageMb() - m0 < 1.0 + @pytest.mark.group_one def test_copy_closure_with_cells(self): # we need the closure to hold something with a refcount # or else we don't generate a closure @@ -991,6 +1036,7 @@ def makeClassHolding(x): # check that we are actually using a TypedCell assert issubclass(r.MemberTypes[0].ClosureType, TypedCell) + @pytest.mark.group_one def test_can_use_assigned_lambdas_in_compiled_code(self): @Entrypoint def callIt(x): @@ -1000,6 +1046,7 @@ def callIt(x): assert callIt(10) == 2 + @pytest.mark.group_one def test_can_use_reassigned_assigned_lambdas_in_compiled_code(self): @Entrypoint def callIt(x): @@ -1013,6 +1060,7 @@ def callIt(x): assert callIt(10) == 22 assert callIt(11) == 36 + @pytest.mark.group_one def test_captured_closure_values_have_good_types(self): aList = ListOf(int)([1, 2, 3]) @@ -1022,6 +1070,7 @@ def callIt(): assert callIt() == ListOf(int) + @pytest.mark.group_one def test_captured_closure_values_in_class_methods_have_good_types(self): aList = ListOf(int)([1, 2, 3]) @@ -1033,6 +1082,7 @@ def callIt(): assert Cls.callIt() == ListOf(int) + @pytest.mark.group_one def test_closure_lambdas_obey_not_compiled(self): @NotCompiled def g(): @@ -1044,6 +1094,7 @@ def f(): f() + @pytest.mark.group_one def test_passed_lambdas_obey_not_compiled(self): @NotCompiled def g(): @@ -1055,6 +1106,7 @@ def f(g): f(g) + @pytest.mark.group_one def test_interior_lambdas_obey_not_compiled(self): @Entrypoint def f(): @@ -1066,6 +1118,7 @@ def g(): f() + @pytest.mark.group_one def test_compiled_defs_obey_not_compiled(self): @Entrypoint def makeNocompile(): @@ -1077,6 +1130,7 @@ def g(): assert makeNocompile().isNocompile + @pytest.mark.group_one def test_compiled_defs_obey_entrypoint(self): @Entrypoint def makeEntrypoint(): @@ -1088,6 +1142,7 @@ def g(): assert makeEntrypoint().isEntrypoint + @pytest.mark.group_one def test_compile_closures_with_type_refs(self): class C(Class): pass diff --git a/typed_python/compiler/tests/compiler_typed_python_comparison_test.py b/typed_python/compiler/tests/compiler_typed_python_comparison_test.py index 1c195c911..a463e5be7 100644 --- a/typed_python/compiler/tests/compiler_typed_python_comparison_test.py +++ b/typed_python/compiler/tests/compiler_typed_python_comparison_test.py @@ -754,42 +754,54 @@ def scenariosWithArgsAndValuesAndUptypes(self, op, argTypes, values, actualTypes return [Scenario(op, argTypes, values, actualTypes)] + @pytest.mark.group_one def test_add(self): self.checkOperation(ArithmeticOperation("add")) + @pytest.mark.group_one def test_mul(self): self.checkOperation(ArithmeticOperation("mul")) + @pytest.mark.group_one def test_sub(self): self.checkOperation(ArithmeticOperation("sub")) + @pytest.mark.group_one def test_truediv(self): self.checkOperation(ArithmeticOperation("truediv")) + @pytest.mark.group_one def test_floordiv(self): self.checkOperation(ArithmeticOperation("floordiv")) + @pytest.mark.group_one def test_mod(self): self.checkOperation(ArithmeticOperation("mod")) # we are not currently getting the types of 'pow' right. int ** int should be int. @pytest.mark.skip + @pytest.mark.group_one def test_pow(self): self.checkOperation(ArithmeticOperation("pow")) + @pytest.mark.group_one def test_lshift(self): self.checkOperation(ArithmeticOperation("lshift")) # we have numerous failures here @pytest.mark.skip + @pytest.mark.group_one def test_rshift(self): self.checkOperation(ArithmeticOperation("rshift")) + @pytest.mark.group_one def test_and(self): self.checkOperation(ArithmeticOperation("and")) + @pytest.mark.group_one def test_or(self): self.checkOperation(ArithmeticOperation("or")) + @pytest.mark.group_one def test_xor(self): self.checkOperation(ArithmeticOperation("xor")) diff --git a/typed_python/compiler/tests/compiling_type_operations_test.py b/typed_python/compiler/tests/compiling_type_operations_test.py index 59927c42d..e3759fd77 100644 --- a/typed_python/compiler/tests/compiling_type_operations_test.py +++ b/typed_python/compiler/tests/compiling_type_operations_test.py @@ -18,6 +18,7 @@ class TestCompilingTypeOperations(unittest.TestCase): + @pytest.mark.group_one def test_can_make_new_types(self): @Entrypoint def f(x): @@ -30,6 +31,7 @@ def f(x): OneOf(None, int) ) + @pytest.mark.group_one def test_stringification_of_type(self): @Entrypoint def f(x): @@ -44,6 +46,7 @@ def check(T): ]: check(typ) + @pytest.mark.group_one def test_type_of(self): @Entrypoint def f(x): @@ -53,6 +56,7 @@ def f(x): self.assertEqual(f(10.5), float) self.assertEqual(f(Int32(10)), Int32) + @pytest.mark.group_one def test_type_of_list_of_int(self): def f(x): return type(x).ElementType is int @@ -60,6 +64,7 @@ def f(x): self.assertTrue(f(ListOf(int)())) self.assertTrue(Entrypoint(f)(ListOf(int)())) + @pytest.mark.group_one def test_type_invalid_member_accesses(self): @Entrypoint def f(): @@ -68,6 +73,7 @@ def f(): with self.assertRaisesRegex(AttributeError, "has no attribute 'notAMember'"): f() + @pytest.mark.group_one def test_type_invalid_unbound_member_call(self): @Entrypoint def f(): @@ -76,6 +82,7 @@ def f(): with self.assertRaisesRegex(TypeError, "requires a '.*' object but received"): f() + @pytest.mark.group_one def test_type_valid_unbound_member_call(self): @Entrypoint def f(x): diff --git a/typed_python/compiler/tests/const_dict_compilation_test.py b/typed_python/compiler/tests/const_dict_compilation_test.py index b3701f813..300e242e4 100644 --- a/typed_python/compiler/tests/const_dict_compilation_test.py +++ b/typed_python/compiler/tests/const_dict_compilation_test.py @@ -47,6 +47,7 @@ def makeSomeValues(dtype, count=10): class TestConstDictCompilation(unittest.TestCase): + @pytest.mark.group_one def test_const_dict_copying(self): for dtype in dictTypes: @Compiled @@ -58,6 +59,7 @@ def copyInOut(x: dtype): self.assertEqual(copyInOut(aDict), aDict) self.assertEqual(_types.refcount(aDict), 1) + @pytest.mark.group_one def test_const_dict_len(self): for dtype in dictTypes: @Compiled @@ -68,6 +70,7 @@ def compiledLen(x: dtype): d = makeSomeValues(dtype, ct) self.assertEqual(len(d), compiledLen(d)) + @pytest.mark.group_one def test_const_dict_getitem(self): for dtype in dictTypes: @Compiled @@ -86,6 +89,7 @@ def callOrExpr(f): for key in bigger_d: self.assertEqual(callOrExpr(lambda: d[key]), callOrExpr(lambda: compiledGetItem(d, key))) + @pytest.mark.group_one def test_const_dict_getitem_coercion(self): d = ConstDict(int, int)({1: 2}) @@ -134,6 +138,7 @@ def get_default(d, k, default): with self.assertRaises(TypeError): getitem(d, 1.5) + @pytest.mark.group_one def test_const_dict_contains(self): for dtype in dictTypes: @Compiled @@ -161,6 +166,7 @@ def compiledContains(x: ConstDict(int, int), y: int): self.assertFalse(compiledContains({k*2: k*2 for k in range(10)}, 5)) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_const_dict_loops_perf(self): def loop(x: ConstDict(int, int)): res = 0 @@ -194,6 +200,7 @@ def loop(x: ConstDict(int, int)): print("ConstDict lookup speedup is ", speedup) self.assertGreater(speedup, 1.75) + @pytest.mark.group_one def test_const_dict_key_error(self): @Compiled def lookup(x: ConstDict(int, int), y: int): @@ -203,6 +210,7 @@ def lookup(x: ConstDict(int, int), y: int): with self.assertRaises(Exception): lookup({1: 2}, 2) + @pytest.mark.group_one def test_const_dict_unsafe_operations(self): T = ConstDict(int, int) @@ -241,6 +249,7 @@ def getvalue(d, i): self.assertEqual(_types.refcount(toi), 1) + @pytest.mark.group_one def test_const_dict_comparison(self): @Entrypoint def eq(x, y): @@ -264,6 +273,7 @@ def lt(x, y): self.assertFalse(eq(t1, t2)) self.assertTrue(neq(t1, t2)) + @pytest.mark.group_one def test_const_dict_iteration(self): def iterateConstDict(cd): res = ListOf(type(cd).KeyType)() @@ -328,6 +338,7 @@ def iterateItemsObject(cd): self.assertEqual(_types.refcount(atup), 2) self.assertEqual(_types.refcount(atup2), 2) + @pytest.mark.group_one def test_const_dict_iteration_perf(self): def loop(x: ConstDict(int, int)): res = 0 @@ -355,6 +366,7 @@ def loop(x: ConstDict(int, int)): print("ConstDict iteration speedup is ", speedup) self.assertGreater(speedup, 2) + @pytest.mark.group_one def test_yield_from_const_dict(self): def iterateTwice(d): for k in d: @@ -372,6 +384,7 @@ def toList(d): assert toList(ConstDict(int, float)({1: 2.2})) == [1, 1] + @pytest.mark.group_one def test_yield_from_const_dict_values(self): def iterateTwice(d): for k in d.values(): @@ -389,6 +402,7 @@ def toList(d): assert toList(ConstDict(int, float)({1: 2.2})) == [2.2, 2.2] + @pytest.mark.group_one def test_yield_from_const_dict_items(self): def iterateTwice(d): for k in d.items(): @@ -406,6 +420,7 @@ def toList(d): assert toList(ConstDict(int, float)({1: 2.2})) == [(1, 2.2), (1, 2.2)] + @pytest.mark.group_one def test_convert_dict_to_const_dict(self): def f(): res = Dict(object, object)({1: '2', 3: '4', -3: '6'}) @@ -414,6 +429,7 @@ def f(): assert f() == Entrypoint(f)() + @pytest.mark.group_one def test_const_dict_add(self): @Entrypoint def addDicts(d1, d2): @@ -438,6 +454,7 @@ def addDicts(d1, d2): for d2 in someDicts: assert d1 + d2 == addDicts(d1, d2) + @pytest.mark.group_one def test_const_dict_sub(self): @Entrypoint def subKey(dct, key): diff --git a/typed_python/compiler/tests/conversion_test.py b/typed_python/compiler/tests/conversion_test.py index 08276ad9e..54be80870 100644 --- a/typed_python/compiler/tests/conversion_test.py +++ b/typed_python/compiler/tests/conversion_test.py @@ -110,6 +110,7 @@ def onNewFunction( class TestCompilationStructures(unittest.TestCase): + @pytest.mark.group_one def test_dispatch_order_independent(self): class AClass(Class): pass @@ -137,6 +138,7 @@ def checkFunctionOfIntegers(self, f): for i in range(100): self.assertEqual(f_fast(i), f(i)) + @pytest.mark.group_one def test_simple_loop(self): def f(x: int) -> int: y = 0 @@ -147,12 +149,14 @@ def f(x: int) -> int: self.checkFunctionOfIntegers(f) + @pytest.mark.group_one def test_returning(self): def f(x: int) -> int: return x self.checkFunctionOfIntegers(f) + @pytest.mark.group_one def test_basic_arithmetic(self): def f(x: int) -> int: y = x+1 @@ -160,6 +164,7 @@ def f(x: int) -> int: self.checkFunctionOfIntegers(f) + @pytest.mark.group_one def test_boolean_and(self): @Compiled def f(x: int, y: int, z: int) -> bool: @@ -174,6 +179,7 @@ def f(x: int, y: int, z: int) -> bool: self.assertEqual(f(1, 1, 0), False) self.assertEqual(f(1, 1, 1), True) + @pytest.mark.group_one def test_boolean_or(self): @Compiled def f(x: int, y: int, z: int) -> bool: @@ -188,6 +194,7 @@ def f(x: int, y: int, z: int) -> bool: self.assertEqual(f(1, 1, 0), True) self.assertEqual(f(1, 1, 1), True) + @pytest.mark.group_one def test_boolean_operators(self): @Compiled def f(x: int, y: int, z: float) -> bool: @@ -196,6 +203,7 @@ def f(x: int, y: int, z: float) -> bool: self.assertEqual(f(0, 1, 1.5), False) self.assertEqual(f(1, 1, 1.5), True) + @pytest.mark.group_one def test_boolean_operators_with_side_effects(self): # a function that appends 'effect' onto a list of effects # and then returns result, so that we can track when we @@ -232,6 +240,7 @@ def f_or(x: int, y: int, z: str) -> ListOf(str): self.assertEqual(f_or(1, 0, ""), ["x", "y"]) self.assertEqual(f_or(1, 1, ""), ["x", "y", "z"]) + @pytest.mark.group_one def test_object_to_int_conversion(self): @Function def toObject(o: object): @@ -243,6 +252,7 @@ def f(x: int) -> int: self.assertEqual(f(10), 10) + @pytest.mark.group_one def test_variable_type_changes_make_sense(self): @Compiled def f(x: int) -> float: @@ -252,6 +262,7 @@ def f(x: int) -> float: self.assertEqual(f(10), 1.2) + @pytest.mark.group_one def test_call_other_typed_function(self): def g(x: int) -> int: return x+1 @@ -261,6 +272,7 @@ def f(x: int) -> int: self.checkFunctionOfIntegers(f) + @pytest.mark.group_one def test_call_untyped_function(self): @Compiled def f(x: object): @@ -270,6 +282,7 @@ def f(x: object): self.assertIs(f(x), x) + @pytest.mark.group_one def test_call_other_untyped_function(self): def g(x): return x @@ -282,6 +295,7 @@ def f(x: object): self.assertIs(f(x), x) + @pytest.mark.group_one def test_integers_in_closures(self): y = 2 @@ -290,6 +304,7 @@ def f(x: int) -> int: self.checkFunctionOfIntegers(f) + @pytest.mark.group_one def test_loop_variable_changing_type(self): @Compiled def f(top: float) -> OneOf(int, float): @@ -303,6 +318,7 @@ def f(top: float) -> OneOf(int, float): self.assertEqual(f(3.5), 10.0) + @pytest.mark.group_one def test_unassigned_variables(self): @Compiled def f(switch: int, t: TupleOf(int)) -> TupleOf(int): @@ -315,6 +331,7 @@ def f(switch: int, t: TupleOf(int)) -> TupleOf(int): with self.assertRaisesRegex(Exception, "local variable 'x' referenced before assignment"): self.assertEqual(f(0, (1, 2, 3)), (1, 2, 3)) + @pytest.mark.group_one def test_return_from_function_without_return_value_specified(self): @Compiled def f(t: TupleOf(int)): @@ -322,6 +339,7 @@ def f(t: TupleOf(int)): self.assertEqual(f((1, 2, 3)), (1, 2, 3)) + @pytest.mark.group_one def test_return_from_function_with_bad_convert_throws(self): @Compiled def f(t: TupleOf(int)) -> None: @@ -331,6 +349,7 @@ def f(t: TupleOf(int)) -> None: f((1, 2, 3)) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_perf_of_mutually_recursive_untyped_functions(self): def q(x): return x-1 @@ -366,6 +385,7 @@ def g(x): print("for ", input, " speedup is ", speedup) + @pytest.mark.group_one def test_call_typed_function(self): @Function def f(x): @@ -377,6 +397,7 @@ def g(x: int): self.assertEqual(g(10), 11) + @pytest.mark.group_one def test_adding_with_nones_throws(self): @Compiled def g(): @@ -385,6 +406,7 @@ def g(): with self.assertRaisesRegex(Exception, "Can't apply op Add.. to expressions of type None"): g() + @pytest.mark.group_one def test_exception_before_return_propagated(self): @Compiled def g(): @@ -394,6 +416,7 @@ def g(): with self.assertRaisesRegex(Exception, "Can't apply op Add.. to expressions of type None"): g() + @pytest.mark.group_one def test_call_function_with_none(self): @Compiled def g(x: None): @@ -401,6 +424,7 @@ def g(x: None): self.assertEqual(g(None), None) + @pytest.mark.group_one def test_call_other_function_with_none(self): def f(x): return x @@ -411,6 +435,7 @@ def g(x: int): self.assertEqual(g(1), None) + @pytest.mark.group_one def test_interleaving_nones(self): def f(x, y, z): x+z @@ -428,6 +453,7 @@ def throws(x: int): with self.assertRaisesRegex(Exception, "Can't apply op Add.. to expressions of type None"): throws(1) + @pytest.mark.group_one def test_return_none(self): def f(x): return x @@ -439,6 +465,7 @@ def g(): self.assertEqual(g.resultTypeFor().typeRepresentation, type(None)) self.assertEqual(g(), None) + @pytest.mark.group_one def test_assign_with_none(self): def f(x): return x @@ -451,6 +478,7 @@ def g(x: int): self.assertEqual(g(1), None) + @pytest.mark.group_one def test_nonexistent_variable(self): @Compiled def f(): @@ -460,6 +488,7 @@ def f(): f() @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_iterating(self): @Compiled def sumDirectly(x: int): @@ -489,6 +518,7 @@ def sumUsingRange(x: int): print("Range is %.2f slower than nonrange." % ((t2-t1)/(t1-t0))) # I get 1.00 self.assertLess((t1-t0), (t2 - t1) * 1.2) + @pytest.mark.group_one def test_read_invalid_variables(self): @Compiled def readNonexistentVariable(readIt: bool): @@ -502,6 +532,7 @@ def readNonexistentVariable(readIt: bool): self.assertEqual(readNonexistentVariable(False), 0) + @pytest.mark.group_one def test_append_float_to_int_rules_same(self): def f(): x = ListOf(int)() @@ -510,6 +541,7 @@ def f(): self.assertEqual(f(), Compiled(f)()) + @pytest.mark.group_one def test_multiple_assignments(self): @Entrypoint def f(iterable): @@ -533,6 +565,7 @@ def f(iterable): with self.assertRaisesRegex(Exception, "too many"): f(Tuple(int, int, int, int)((1, 2, 3, 4))) + @pytest.mark.group_one def test_print_oneof(self): @Compiled def f(x: OneOf(float, str), y: OneOf(float, str)): @@ -541,6 +574,7 @@ def f(x: OneOf(float, str), y: OneOf(float, str)): f("hi", "hi") f(1.0, "hi") + @pytest.mark.group_one def test_type_oneof(self): @Compiled def f(x: OneOf(float, int)): @@ -549,6 +583,7 @@ def f(x: OneOf(float, int)): self.assertEqual(f(1), str(int)) self.assertEqual(f(1.0), str(float)) + @pytest.mark.group_one def test_can_raise_exceptions(self): @Compiled def aFunctionThatRaises(x: object): @@ -565,6 +600,7 @@ def aFunctionThatRaises(x: object): self.assertIn('conversion_test', trace) self.assertIn('aFunctionThatRaises', trace) + @pytest.mark.group_one def test_stacktraces_show_up(self): def f2(x): return f3(x) @@ -589,6 +625,7 @@ def f1(x): self.assertIn("f4", trace) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_perf_of_inlined_functions_doesnt_degrade(self): def f1(x): return f2(x) @@ -639,6 +676,7 @@ def getit(f): self.assertLessEqual(ratio, 1.2) print(f"Deeper call tree code was {ratio} times slow.") + @pytest.mark.group_one def test_exception_handling_preserves_refcount(self): @Entrypoint def f(x, shouldThrow): @@ -660,6 +698,7 @@ def f(x, shouldThrow): self.assertEqual(_types.refcount(aList), 1) + @pytest.mark.group_one def test_assert(self): @Entrypoint def assertNoMessage(x): @@ -678,6 +717,7 @@ def assertWithMessage(x, y): assertNoMessage(1) assertWithMessage(1, "message") + @pytest.mark.group_one def test_assert_false(self): @Entrypoint def check(x): @@ -689,6 +729,7 @@ def check(x): with self.assertRaises(AssertionError): check(10) + @pytest.mark.group_one def test_conditional_eval_or(self): @Compiled def f1(x: float, y: int): @@ -723,6 +764,7 @@ def f3(x: int, y: float, z: str): self.assertEqual(f3(3, 1.5, ""), 3) self.assertEqual(f3(3, 1.5, "one"), 3) + @pytest.mark.group_one def test_conditional_eval_and(self): @Compiled def f1(x: float, y: int): @@ -757,6 +799,7 @@ def f(x: int, y: str, z: float): self.assertEqual(f(3, "one", 0.0), 0.0) self.assertEqual(f(3, "one", 1.5), 1.5) + @pytest.mark.group_one def test_conversion_of_deeply_nested_functions(self): def g_0(): return 0 @@ -812,6 +855,7 @@ def compute(): if identity not in oldTimesCalculated: self.assertLessEqual(timesCalculated, 6, identity) + @pytest.mark.group_one def test_converting_break_in_while(self): def testBreak(x): res = 0 @@ -827,6 +871,7 @@ def testBreak(x): self.assertEqual(testBreak(10), Entrypoint(testBreak)(10)) + @pytest.mark.group_one def test_converting_break_in_while_with_try_outside_of_loop(self): def testBreak(): res = 0 @@ -843,6 +888,7 @@ def testBreak(): self.assertEqual(testBreak(), Entrypoint(testBreak)()) + @pytest.mark.group_one def test_converting_break_in_while_with_try_inside_of_loop(self): def testBreak(): res = 0 @@ -860,6 +906,7 @@ def testBreak(): self.assertEqual(testBreak(), Entrypoint(testBreak)()) + @pytest.mark.group_one def test_converting_break_through_nested_try_finally(self): def testBreak(): res = 0 @@ -883,6 +930,7 @@ def testBreak(): self.assertEqual(testBreak(), Entrypoint(testBreak)()) + @pytest.mark.group_one def test_converting_continue_through_multiple_nested_try_finally(self): def testBreak(): res = 0 @@ -912,6 +960,7 @@ def testBreak(): self.assertEqual(testBreak(), Entrypoint(testBreak)()) + @pytest.mark.group_one def test_converting_continue_in_while(self): def testContinue(x): res = 0 @@ -929,6 +978,7 @@ def testContinue(x): self.assertEqual(testContinue(10), Entrypoint(testContinue)(10)) + @pytest.mark.group_one def test_converting_break_in_foreach(self): def testBreak(x): res = 0 @@ -942,6 +992,7 @@ def testBreak(x): for thing in [ListOf(int)(range(10)), Tuple(int, int, int, int)((1, 2, 3, 4))]: self.assertEqual(testBreak(thing), Entrypoint(testBreak)(thing)) + @pytest.mark.group_one def test_converting_continue_in_foreach(self): def testContinue(x): res = 0 @@ -955,6 +1006,7 @@ def testContinue(x): for thing in [ListOf(int)(range(10)), Tuple(int, int, int, int)((1, 2, 3, 4))]: self.assertEqual(testContinue(thing), Entrypoint(testContinue)(thing)) + @pytest.mark.group_one def test_call_function_with_wrong_number_of_arguments(self): def f(x, y): return x + y @@ -966,6 +1018,7 @@ def callIt(x: int): with self.assertRaisesRegex(TypeError, "annot find a valid overload"): callIt(1) + @pytest.mark.group_one def test_call_function_with_default_arguments(self): def f(x, y=1): return x + y @@ -976,6 +1029,7 @@ def callIt(x): self.assertEqual(callIt(10), f(10)) + @pytest.mark.group_one def test_call_function_with_named_args_ordering(self): def f(x, y): return x @@ -986,6 +1040,7 @@ def callWithArgsReversed(x, y): self.assertEqual(callWithArgsReversed(2, 3), 2) + @pytest.mark.group_one def test_call_function_with_named_args(self): def f(x=1, y=10): return x + y @@ -1007,6 +1062,7 @@ def callWithXY(x: int, y: int): self.assertEqual(callWithY(2), callWithYCompiled(2)) self.assertEqual(callWithXY(2, 3), callWithXYCompiled(2, 3)) + @pytest.mark.group_one def test_call_function_with_star_args(self): def f(*args): return args @@ -1017,6 +1073,7 @@ def callIt(x, y, z): self.assertEqual(callIt(1, 2.5, "hi"), Tuple(int, float, str)((1, 2.5, "hi"))) + @pytest.mark.group_one def test_call_function_with_kwargs(self): def f(**kwargs): return kwargs @@ -1027,6 +1084,7 @@ def callIt(x, y, z): self.assertEqual(callIt(1, 2.5, "hi"), dict(x=1, y=2.5, z="hi")) + @pytest.mark.group_one def test_call_function_with_excess_named_arg(self): def f(x=1, y=2): return x + y @@ -1038,6 +1096,7 @@ def callIt(x, y, z): with self.assertRaisesRegex(TypeError, "annot find a valid over"): callIt(1, 2, 3) + @pytest.mark.group_one def test_star_arg_call_function(self): def f(x, y): return x + y @@ -1048,6 +1107,7 @@ def callIt(a): self.assertEqual(callIt(Tuple(int, int)((1, 2))), 3) + @pytest.mark.group_one def test_star_kwarg_type(self): def f(**kwargs): return type(kwargs) @@ -1058,6 +1118,7 @@ def callIt(): self.assertEqual(callIt(), dict) + @pytest.mark.group_one def test_star_kwarg_as_dict(self): def f(**kwargs): return kwargs @@ -1068,6 +1129,7 @@ def callIt(): self.assertEqual(callIt(), dict(x=10, y=20)) + @pytest.mark.group_one def test_star_kwarg_call_function(self): def f(x, y): return x + y @@ -1082,6 +1144,7 @@ def callIt(x, y): self.assertEqual(callIt(1, 2), 3) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_perf_of_star_kwarg_intermediate_is_fast(self): def f(x, y): return x + y @@ -1124,6 +1187,7 @@ def sumUsingF(a: int): self.assertTrue(.7 <= elapsedF / elapsedG <= 1.3, elapsedF / elapsedG) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_perf_of_star_arg_intermediate_is_fast(self): def f(x, y): return x + y @@ -1165,6 +1229,7 @@ def sumUsingF(a: int): # check that the extra call to 'g' doesn't introduce any overhead self.assertTrue(.65 <= elapsedF / elapsedG <= 1.35, elapsedF / elapsedG) + @pytest.mark.group_one def test_star_args_type(self): def f(*args): return type(args) @@ -1175,6 +1240,7 @@ def callF(): self.assertEqual(callF(), tuple) + @pytest.mark.group_one def test_typed_functions_with_star_args(self): @Function def f(x: int): @@ -1195,6 +1261,7 @@ def callF2(x, y): self.assertEqual(callF1(0), 1) self.assertEqual(callF2(0, 1), 2) + @pytest.mark.group_one def test_typed_functions_with_kwargs(self): @Function def f(x, **kwargs): @@ -1226,6 +1293,7 @@ def callF4(x, y): with self.assertRaisesRegex(TypeError, "annot find a valid overload"): callF4(0, 1) + @pytest.mark.group_one def test_typed_functions_with_typed_kwargs(self): @Function def f(**kwargs: int): @@ -1249,6 +1317,7 @@ def callF(**kwargs): self.assertEqual(callF(x=1.5), "int") self.assertEqual(callF(x="1"), "str") + @pytest.mark.group_one def test_typed_functions_dispatch_based_on_names(self): @Function def f(x): @@ -1274,6 +1343,7 @@ def callFWithX(x): self.assertEqual(callFWithX(10), "x") self.assertEqual(callFWithY(10), "y") + @pytest.mark.group_one def test_typed_functions_with_oneof(self): @Function def f(x: OneOf(int, float)): @@ -1296,6 +1366,7 @@ def callF2(x: OneOf(int, float, str)): with self.assertRaisesRegex(TypeError, r"annot find a valid overload"): callF2("h") + @pytest.mark.group_one def test_can_call_function_with_typed_function_as_argument(self): @Function def add(x: int, y: int): @@ -1313,6 +1384,7 @@ def callIt(x: int, f: add): with self.assertRaisesRegex(TypeError, "annot find a valid overload"): callIt(1, g) + @pytest.mark.group_one def test_check_type_of_method_conversion(self): @Entrypoint def g(x: OneOf(None, TupleOf(int))): @@ -1321,6 +1393,7 @@ def g(x: OneOf(None, TupleOf(int))): self.assertEqual(g((1, 2, 3)), TupleOf(int)) self.assertEqual(g(None), type(None)) + @pytest.mark.group_one def test_check_is_on_unlike_things(self): @Entrypoint def g(x, y): @@ -1330,6 +1403,7 @@ def g(x, y): self.assertTrue(g(None, None)) self.assertFalse(g(ListOf(int)(), TupleOf(int)())) + @pytest.mark.group_one def test_if_condition_throws(self): def throws(): raise Exception("Boo") @@ -1347,6 +1421,7 @@ def shouldThrow(): with self.assertRaisesRegex(Exception, "Couldn't initialize type int"): shouldThrow() + @pytest.mark.group_one def test_if_with_return_types(self): @Entrypoint def popCheck(d, x): @@ -1355,6 +1430,7 @@ def popCheck(d, x): popCheck(Dict(int, int)(), 1) + @pytest.mark.group_one def test_assign_to_arguments_with_typechange(self): @Entrypoint def f(x, y: object): @@ -1362,6 +1438,7 @@ def f(x, y: object): f(1, 1) + @pytest.mark.group_one def test_unassigned_variable_access(self): @Compiled def reduce2(aList: ListOf(int)): @@ -1372,6 +1449,7 @@ def reduce2(aList: ListOf(int)): with self.assertRaisesRegex(Exception, "ame 'r' is not defined"): reduce2([1, 2, 3]) + @pytest.mark.group_one def test_iterate_closures(self): x = ListOf(int)((1, 2, 3)) @@ -1384,6 +1462,7 @@ def f(): self.assertEqual(f(), [1, 2, 3]) + @pytest.mark.group_one def test_function_not_returning_returns_none(self): @Entrypoint def f(l, i, y): @@ -1391,6 +1470,7 @@ def f(l, i, y): self.assertEqual(f.resultTypeFor(ListOf(int), int, int).typeRepresentation, type(None)) + @pytest.mark.group_one def test_method_not_returning_returns_none(self): class NoPythonObjectTypes(RuntimeEventVisitor): def onNewFunction( @@ -1425,6 +1505,7 @@ def f(l: ListOf(int), i, y: OneOf(int, float)): with NoPythonObjectTypes(): f(ListOf(int)([1, 2, 3]), 0, 2) + @pytest.mark.group_one def test_try_simple(self): def f0(x: int) -> str: @@ -1778,6 +1859,7 @@ def t3(a: int) -> int: self.assertEqual(r1, r2, (str(f), v)) @flaky(max_runs=5, min_passes=1) + @pytest.mark.group_one def test_try_general(self): def g1(a: int, b: int, c: int, d: int) -> str: ret = "start " @@ -2011,6 +2093,7 @@ def g11(x: int) -> int: r2 = result_or_exception_tb(c_f, a, b, c, d) self.assertEqual(r1, r2, (str(f), a, b, c, d)) + @pytest.mark.group_one def test_try_nested(self): def n1(x: int, y: int) -> str: @@ -2109,6 +2192,7 @@ def n2(x: int, y: int) -> str: r2 = result_or_exception_tb(c_f, a, b) self.assertEqual(r1, r2, (str(f), a, b)) + @pytest.mark.group_one def test_compile_chained_context_managers(self): class CM(Class, Final): lst = Member(ListOf(int)) @@ -2133,6 +2217,7 @@ def chainTwoOfThem(): chainTwoOfThem() Entrypoint(chainTwoOfThem)() + @pytest.mark.group_one def test_try_reraise(self): # Test reraise directly in exception handler @@ -2213,6 +2298,7 @@ def reraise(b: int) -> str: self.assertEqual(r1, r2, (a, b)) self.assertEqual(r3, r4, (a, b)) + @pytest.mark.group_one def test_context_manager_refcounts(self): class ContextManaer(Class, Final): def __enter__(self): @@ -2231,6 +2317,7 @@ def f(x): f(a) assert _types.refcount(a) == 1 + @pytest.mark.group_one def test_try_finally_refcounts(self): @Entrypoint def f(x): @@ -2244,6 +2331,7 @@ def f(x): f(a) assert _types.refcount(a) == 1 + @pytest.mark.group_one def test_context_manager_functionality(self): class ConMan1(): @@ -2559,6 +2647,7 @@ def with_cm_loop2(a: int, b: int, c: int, d: int, t: ListOf(str)) -> int: self.assertEqual(t1, t2, (a, b, c, d, e, f, g, h)) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_context_manager_perf(self): class ConMan1(): @@ -2658,6 +2747,7 @@ def with_cm_simple2(a: int, b: int, c: int, d: int, t: ListOf(str)) -> int: self.assertLessEqual(m3 - m2, m1 - m0 + 1024, (f1.__name__, a)) + @pytest.mark.group_one def test_context_manager_assignment(self): class ConMan(Class, Final): a = Member(int) @@ -2721,6 +2811,7 @@ def with_cm_assign(a: int, b: int, c: int, d: int, t: ListOf(str)) -> int: self.assertEqual(r1, r2, (a, b, c, d)) self.assertEqual(t1, t2, (a, b, c, d)) + @pytest.mark.group_one def test_catch_definite_exception(self): @Entrypoint def g(): @@ -2735,6 +2826,7 @@ def f(x): self.assertEqual(f(1), None) + @pytest.mark.group_one def test_catch_definite_exception_propagate_but_catch(self): @Entrypoint def g(): @@ -2752,6 +2844,7 @@ def f(x): self.assertEqual(f(1), None) + @pytest.mark.group_one def test_catch_definite_exception_propagate(self): @Entrypoint def g(): @@ -2767,6 +2860,7 @@ def f(x): with self.assertRaisesRegex(Exception, "Boo again"): f(1) + @pytest.mark.group_one def test_catch_possible_exception(self): @Entrypoint def g(): @@ -2784,6 +2878,7 @@ def f(x): self.assertEqual(f(1), None) self.assertEqual(f(-1), 0) + @pytest.mark.group_one def test_many_mutually_interesting_functions(self): def f0(x): pass @@ -2819,6 +2914,7 @@ def f6(x): Entrypoint(f6)(10) + @pytest.mark.group_one def test_not_compiled_called_from_compiled(self): @NotCompiled def f(): @@ -2832,6 +2928,7 @@ def g(): self.assertEqual(g(), "OK") + @pytest.mark.group_one def test_not_compiled_lambdas(self): @Entrypoint def callIt(f): @@ -2839,6 +2936,7 @@ def callIt(f): self.assertEqual(callIt(NotCompiled(lambda x: x + 1, int)), 2) + @pytest.mark.group_one def test_same_code_with_different_globals(self): def call(x): return f(x) # noqa @@ -2855,6 +2953,7 @@ def callFunc(f, x): self.assertEqual(callFunc(f1, 10.5), "10.5") self.assertEqual(callFunc(f2, 10.5), 10) + @pytest.mark.group_one def test_reconstructed_code_has_same_identity_hash(self): def call(x): return x @@ -2869,6 +2968,7 @@ def call(x): assert identityHash(call.__code__) == identityHash(newCall.__code__) + @pytest.mark.group_one def test_code_with_nested_listcomp(self): def call(x): return [[(i, 0, 0) for i in y] for y in x] @@ -2877,6 +2977,7 @@ def call(x): evaluateFunctionDefWithLocalsInCells(ast, {'f': str}, {}) + @pytest.mark.group_one def test_code_with_nested_setcomp(self): def call(x): return {[(i, 0, 0) for i in y] for y in x} @@ -2885,6 +2986,7 @@ def call(x): evaluateFunctionDefWithLocalsInCells(ast, {'f': str}, {}) + @pytest.mark.group_one def test_code_with_nested_dictcomp(self): def call(x): return {0: [(i, 0, 0) for i in y] for y in x} @@ -2893,6 +2995,7 @@ def call(x): evaluateFunctionDefWithLocalsInCells(ast, {'f': str}, {}) + @pytest.mark.group_one def test_closure_grabs_global_typed_object(self): def countIt(x): res = 0 @@ -2922,6 +3025,7 @@ def callIt(f, x): print("took ", time.time() - t0) self.assertLess(time.time() - t0, .1) + @pytest.mark.group_one def test_closure_can_grab_and_modify_global_typed_object(self): aModuleLevelDict['modify_count'] = 0 @@ -2955,6 +3059,7 @@ def callIt(f, x): print("took ", time.time() - t0) self.assertLess(time.time() - t0, .1) + @pytest.mark.group_one def test_can_compile_after_compilation_failure(self): class ThrowsCompilerExceptions(CompilableBuiltin): def __eq__(self, other): @@ -2982,6 +3087,7 @@ def g(): self.assertEqual(g(), 3) + @pytest.mark.group_one def test_converting_where_type_alternates(self): def add(x, y): return x if y is None else y if x is None else x + y @@ -3019,6 +3125,7 @@ def addUp(p1, p2, v1, v2): assert v == [0.0, 2.0, 2.0, 3.0] assert p == [False, True, True, True] + @pytest.mark.group_one def test_convert_not_on_ints_and_floats(self): def check(): y = ListOf(int)() @@ -3035,6 +3142,7 @@ def check(): check(), Entrypoint(check)() ) + @pytest.mark.group_one def test_compiler_can_see_type_members_of_instances(self): @Entrypoint def eltTypeOf(x): @@ -3043,6 +3151,7 @@ def eltTypeOf(x): assert eltTypeOf(ListOf(int)) == int assert eltTypeOf(ListOf(int)()) == int + @pytest.mark.group_one def test_function_entrypoint_multithreaded(self): def makeAFunction(x): T = OneOf(None, x) @@ -3073,6 +3182,7 @@ def wrapFunction(f): assert len(overloads) == 2 + @pytest.mark.group_one def test_double_assignment(self): def doubleAssign(): x = y = ListOf(int)() # noqa @@ -3081,6 +3191,7 @@ def doubleAssign(): assert len(doubleAssign()) == 0 assert len(Entrypoint(doubleAssign)()) == 0 + @pytest.mark.group_one def test_double_nested_assignment(self): def doubleAssign(): x = (y, z) = (1, 2) @@ -3092,6 +3203,7 @@ def doubleAssign(): doubleAssign() Entrypoint(doubleAssign)() + @pytest.mark.group_one def test_double_nested_assignment_with_failure(self): def doubleAssign(): try: @@ -3105,6 +3217,7 @@ def doubleAssign(): doubleAssign() Entrypoint(doubleAssign)() + @pytest.mark.group_one def test_slice_objects(self): @Entrypoint def createSlice(start, stop, step): @@ -3112,6 +3225,7 @@ def createSlice(start, stop, step): assert isinstance(createSlice(1, 2, 3), slice) + @pytest.mark.group_one def test_slice_objects_are_fast(self): def count(start, stop, step): res = 0.0 @@ -3136,6 +3250,7 @@ def count(start, stop, step): print("speedup is ", speedup) + @pytest.mark.group_one def test_type_and_repr_of_slice_objects(self): @Entrypoint def typeOf(): @@ -3155,6 +3270,7 @@ def reprOf(): assert reprOf() == repr(slice(1, 2, 3)) + @pytest.mark.group_one def test_class_interaction_with_slice_is_fast(self): class C(Class, Final): def __getitem__(self, x) -> int: @@ -3183,6 +3299,7 @@ def count(c, start, stop, step): print("speedup is ", speedup) + @pytest.mark.group_one def test_class_interaction_with_slice_pairs(self): class C(Class, Final): def __getitem__(self, x) -> int: @@ -3211,6 +3328,7 @@ def count(c, start, stop, step): print("speedup is ", speedup) + @pytest.mark.group_one def test_chained_comparisons(self): def f1(x, y, z): return x < y < z @@ -3261,6 +3379,7 @@ def side_effect(x, accumulator): self.assertEqual(r1, r2) + @pytest.mark.group_one def test_variable_restriction_is_correct(self): @Entrypoint def toTypedDict(x: dict): @@ -3269,6 +3388,7 @@ def toTypedDict(x: dict): assert toTypedDict({1: 2}) == {1: 2} + @pytest.mark.group_one def test_function_return_conversion_level_is_ImplicitContainers(self): @Function def toList(x) -> ListOf(int): @@ -3280,6 +3400,7 @@ def toListC(x) -> ListOf(int): assert toList([1, 2]) == toListC([1, 2]) == ListOf(int)([1, 2]) + @pytest.mark.group_one def test_iterate_with_multiple_variable_targets(self): @Entrypoint def iterate(iterable): @@ -3293,6 +3414,7 @@ def iterate(iterable): with self.assertRaisesRegex(Exception, "not enough values to unpack"): iterate(ListOf(ListOf(int))([[1, 2], [3]])) + @pytest.mark.group_one def test_iterate_constant_expression_multiple(self): @Entrypoint def iterate(): @@ -3303,6 +3425,7 @@ def iterate(): assert iterate() == 6 + @pytest.mark.group_one def test_iterate_oneof(self): @Entrypoint def iterate(x: OneOf(ListOf(int), ListOf(float))): @@ -3315,6 +3438,7 @@ def iterate(x: OneOf(ListOf(int), ListOf(float))): assert iterate.resultTypeFor(ListOf(int)).typeRepresentation == OneOf(float, int) + @pytest.mark.group_one def test_iterate_oneof_segregates_variables(self): @Entrypoint def iterate(x: OneOf(ListOf(int), ListOf(str))): @@ -3328,6 +3452,7 @@ def iterate(x: OneOf(ListOf(int), ListOf(str))): assert iterate(ListOf(int)([1, 2])) is int assert iterate(ListOf(str)(["2"])) is str + @pytest.mark.group_one def test_iterate_oneof_variable_types_join(self): @Entrypoint def iterate(x: OneOf(ListOf(int), ListOf(str))): @@ -3342,6 +3467,7 @@ def iterate(x: OneOf(ListOf(int), ListOf(str))): assert iterate(ListOf(int)([1, 2])) is OneOf(None, int, str) assert iterate(ListOf(str)(["2"])) is OneOf(None, int, str) + @pytest.mark.group_one def test_check_isinstance_on_oneof(self): @Entrypoint def doIt(var: OneOf(int, float)): @@ -3353,6 +3479,7 @@ def doIt(var: OneOf(int, float)): assert doIt(1.0) is float assert doIt(1) is int + @pytest.mark.group_one def test_check_one_of_type(self): @Entrypoint def doIt(var: OneOf(int, float)): @@ -3363,6 +3490,7 @@ def doIt(var: OneOf(int, float)): assert doIt(1.0) is float assert doIt(1) is int + @pytest.mark.group_one def test_check_subtype(self): class Base(Class): pass @@ -3387,6 +3515,7 @@ def doIt(var: Base): assert doIt(Child3()) is Base @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_check_one_of_type_perf_difference(self): @Entrypoint def accumulate(var: OneOf(int, float), times: int): @@ -3442,6 +3571,7 @@ def accumulateWithCheck(var: OneOf(int, float), times: int): print("float speedup is", speedup) assert speedup > 2.0 + @pytest.mark.group_one def test_compile_annotated_assignment(self): def f(): x: int = 20 @@ -3450,6 +3580,7 @@ def f(): assert f() == Entrypoint(f)() + @pytest.mark.group_one def test_with_exception(self): class SimpleCM1(): def __enter__(self): @@ -3487,6 +3618,7 @@ def testCM(cm): self.assertEqual(r2, 0) self.assertEqual(r3, 1) + @pytest.mark.group_one def test_context_manager_corruption(self): class CM(): def __enter__(self): @@ -3521,6 +3653,7 @@ def repeat_b(n): with self.assertRaises(ZeroDivisionError): repeat_b(1000) + @pytest.mark.group_one def test_context_manager_multiple_on_one_line1(self): class ConMan1(): def __enter__(self): @@ -3548,6 +3681,7 @@ def f(): # Former problem: c_f raises RuntimeError 'No active exception to reraise' self.assertEqual(r1, r2) + @pytest.mark.group_one def test_context_manager_multiple_on_one_line2(self): class ConMan(): def __init__(self, a, b, c, t): @@ -3603,6 +3737,7 @@ def with_cm_multiple(a, b, c, d, e, f, g, t) -> int: self.assertEqual(r1, r2, (a, b, c, d, e, f, g)) self.assertEqual(t1, t2, (a, b, c, d, e, f, g)) + @pytest.mark.group_one def test_import_module(self): @Entrypoint def importSomething(): @@ -3612,6 +3747,7 @@ def importSomething(): assert importSomething() is sys + @pytest.mark.group_one def test_import_nonexistent_module(self): def importSomething(doIt): if doIt: @@ -3636,6 +3772,7 @@ def importSomething(doIt): assert type(nativeException) == type(compiledException) assert nativeException.args == compiledException.args + @pytest.mark.group_one def test_import_from(self): @Entrypoint def importSomething(): @@ -3651,6 +3788,7 @@ def importSomething(): assert importedPath is os.path assert importedExit is os._exit + @pytest.mark.group_one def test_import_from_invalid_name(self): def importSomething(doIt): if doIt: @@ -3675,6 +3813,7 @@ def importSomething(doIt): assert type(nativeException) == type(compiledException) assert nativeException.args == compiledException.args + @pytest.mark.group_one def test_class_as_context_manager(self): class SimpleCM1(): def __enter__(self): @@ -3709,6 +3848,7 @@ def testCM(cm): assert testCM(SimpleCM2()) == 0 assert testCM(SimpleCM3()) == 1 + @pytest.mark.group_one def test_access_oneof_variable(self): @Entrypoint def f(x) -> object: @@ -3735,6 +3875,7 @@ def loop2(): loop1() loop2() + @pytest.mark.group_one def test_notcompiled_lambda_closure_refcounts(self): x = ListOf(int)() @@ -3765,6 +3906,7 @@ def returnIt(x): closure = None assert refcount(x) == 1 + @pytest.mark.group_one def test_map_large_named_tuples(self): def getNamedTupleOfLists(n): nameToList = {"a" + str(i): ListOf(str)([str(i)]) for i in range(n)} diff --git a/typed_python/compiler/tests/dict_compilation_test.py b/typed_python/compiler/tests/dict_compilation_test.py index 03eccc704..2b45b6f9c 100644 --- a/typed_python/compiler/tests/dict_compilation_test.py +++ b/typed_python/compiler/tests/dict_compilation_test.py @@ -29,6 +29,7 @@ def compiledHash(T, obj): class TestDictCompilation(unittest.TestCase): + @pytest.mark.group_one def test_can_copy_dict(self): @Entrypoint def f(x): @@ -62,6 +63,7 @@ def reversed(x: ListOf(Dict(int, int))): self.assertEqual(refcounts, refcounts2) + @pytest.mark.group_one def test_dict_contains(self): @Entrypoint def isIn(x, d): @@ -84,6 +86,7 @@ def isNotIn(x, d): self.assertFalse(isIn("boo", d)) self.assertTrue(isNotIn("boo", d)) + @pytest.mark.group_one def test_dict_length(self): @Entrypoint def dict_len(x): @@ -100,6 +103,7 @@ def dict_len(x): self.assertEqual(dict_len(x), 1) + @pytest.mark.group_one def test_dict_getitem(self): @Entrypoint def dict_getitem(x, y): @@ -114,6 +118,7 @@ def dict_getitem(x, y): with self.assertRaisesRegex(KeyError, "2"): dict_getitem(x, 2) + @pytest.mark.group_one def test_dict_get_default(self): @Entrypoint def dict_get(x, y): @@ -132,6 +137,7 @@ def dict_get(x, y): with self.assertRaises(TypeError): self.assertEqual(x[1.5], 2) + @pytest.mark.group_one def test_dict_get_nodefault(self): @Entrypoint def dict_get(x, y): @@ -153,6 +159,7 @@ def dict_get(x, y): self.assertEqual(dict_get(x, 2), None) self.assertEqual(x.get(2), None) + @pytest.mark.group_one def test_dict_setitem(self): @Entrypoint def dict_setitem(d, k, v): @@ -185,6 +192,7 @@ def dict_setmany(d, count): self.assertEqual(x, {i: str(i*i) for i in range(1000)}) + @pytest.mark.group_one def test_dict_with_oneof_keys(self): d = Dict(OneOf(None, int), int)() @@ -203,6 +211,7 @@ def lookup(d, v): self.assertEqual(d.get(30), None) self.assertEqual(d.get(20), 20) + @pytest.mark.group_one def test_dict_position_same(self): def check(someInts): dInterp = Dict(int, int)() @@ -236,6 +245,7 @@ def checkThem(d, ints): check(range(i)) check(numpy.random.choice(1000000, size=i).tolist()) + @pytest.mark.group_one def test_adding_to_dicts(self): @Entrypoint def f(count): @@ -256,6 +266,7 @@ def f(count): self.assertTrue(f(20000)) + @pytest.mark.group_one def test_dicts_in_dicts(self): @Entrypoint def f(): @@ -271,6 +282,7 @@ def f(): self.assertEqual(d['hi']['good'], 100.0) + @pytest.mark.group_one def test_dict_destructors(self): @Entrypoint def f(): @@ -280,6 +292,7 @@ def f(): f() + @pytest.mark.group_one def test_dict_setdefault(self): @Entrypoint def dict_setdefault(d, k, v): @@ -298,6 +311,7 @@ def dict_setdefault(d, k, v): self.assertEqual(v2, "b") self.assertEqual(x, {1: "a", 2: "b"}) + @pytest.mark.group_one def test_dict_setdefault_noarg(self): @Entrypoint def dict_setdefault(d, k): @@ -316,6 +330,7 @@ def dict_setdefault(d, k): self.assertEqual(v2, "") self.assertEqual(x, {1: "a", 2: ""}) + @pytest.mark.group_one def test_dict_pop(self): @Entrypoint def dict_pop(d, k): @@ -336,6 +351,7 @@ def dict_pop_2(d, k, v): with self.assertRaisesRegex(KeyError, "10"): dict_pop(d, 10) + @pytest.mark.group_one def test_dict_with_different_types(self): """Check if the dictionary with different types supports proper key and type conversion. @@ -352,6 +368,7 @@ def dict_setvalue(d, k, v): x["a"] = 1 self.assertEqual(x, {"a": 1}) + @pytest.mark.group_one def test_dict_del(self): @Entrypoint def dict_delitem(d, k): @@ -366,6 +383,7 @@ def dict_delitem(d, k): self.assertEqual(x, {2: 3}) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_dict_read_write_perf(self): def dict_setmany(d, count, passes): for _ in range(passes): @@ -400,6 +418,7 @@ def dict_setmany(d, count, passes): print("Speedup was ", ratio, ". compiled time was ", t3 - t2) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_dict_read_write_perf_releases_gil(self): def dict_setmany(d, count, passes): for _ in range(passes): @@ -437,6 +456,7 @@ def dict_setmany(d, count, passes): print("Multicore slowdown factor was ", slowdownRatio) + @pytest.mark.group_one def test_iteration(self): def iterateDirect(d): res = ListOf(type(d).KeyType)() @@ -485,6 +505,7 @@ def iterateItems(d): self.assertEqual(iterateCompiled(d), iterate(d)) + @pytest.mark.group_one def test_refcounting(self): TOI = TupleOf(int) x = Dict(TOI, TOI)() @@ -512,6 +533,7 @@ def getItem(d, k): self.assertEqual(_types.refcount(aTup3), 2) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_dict_hash_perf_compiled(self): @Entrypoint def f(dictToLookupIn, items, passes): @@ -540,6 +562,7 @@ def f(dictToLookupIn, items, passes): f(aDict, someStrings, 1000000) print(time.time() - t0, "to lookup 100mm strings") + @pytest.mark.group_one def test_dict_clear_compiles(self): T = Dict(str, str) @@ -569,6 +592,7 @@ def clearIt(d): d["1"] = "1" self.assertTrue("1" in d) + @pytest.mark.group_one def test_dict_update_compiles(self): T = Dict(str, str) @@ -591,6 +615,7 @@ def updateCompiled(d, d2): self.assertEqual(aDict, aDict2) + @pytest.mark.group_one def test_dict_pop_many(self): @Entrypoint def f(x: Dict(int, int)): @@ -612,6 +637,7 @@ def f(x: Dict(int, int)): self.assertEqual(len(x), 0) + @pytest.mark.group_one def test_dict_up_and_down(self): @Entrypoint def f(targets): @@ -639,6 +665,7 @@ def f(targets): for i5 in range(C): f(ListOf(int)([i1, i2, i3, i4, i5])) + @pytest.mark.group_one def test_dict_fuzz(self): # try adding and removing items repeatedly, in an effort to fill the table up @Entrypoint @@ -670,6 +697,7 @@ def f(actions: TupleOf(Tuple(bool, int))): print(actions) raise + @pytest.mark.group_one def test_dict_of_int_with_neg_one(self): # negative one is special because it hashes to -1. Python # treats a -1 as an error code (indicating there was @@ -691,6 +719,7 @@ def get(d, x): self.assertEqual(get(d, -1), 2) + @pytest.mark.group_one def test_dict_of_float_with_neg_one(self): # negative one is special because it hashes to -1. Python # treats a -1 as an error code (indicating there was @@ -712,6 +741,7 @@ def get(d, x): self.assertEqual(get(d, -1.0), 2) + @pytest.mark.group_one def test_dict_assign_and_copy(self): @Entrypoint @@ -733,6 +763,7 @@ def dict_copy_and_modify_original(d, x, y): d = Dict(str, int)({'a': 1, 'b': 3, 'c': 5}) self.assertEqual(dict_copy_and_modify_original(d, 'q', 'b'), {'a': 1, 'b': 3, 'c': 5}) + @pytest.mark.group_one def test_dict_del_refcounts(self): T = Dict(int, ListOf(int)) @@ -760,6 +791,7 @@ def delOne(d): assert _types.refcount(aListOf) == 1 + @pytest.mark.group_one def test_dict_aliasing(self): T = Dict(int, int) @@ -770,6 +802,7 @@ def test_dict_aliasing(self): assert len(t2) == 0 + @pytest.mark.group_one def test_dict_aliasing_compiled(self): T = Dict(int, int) @@ -786,6 +819,7 @@ def dup(x): assert len(t2) == 0 + @pytest.mark.group_one def test_dict_assign_untyped_containers(self): T = Dict(int, ListOf(int)) @@ -801,6 +835,7 @@ def setIt(d, x): assert len(aDict[10]) == 1 + @pytest.mark.group_one def test_dict_assign_untyped_sets(self): T = Dict(int, Set(int)) @@ -816,6 +851,7 @@ def setIt(d, x): assert len(aDict[10]) == 1 + @pytest.mark.group_one def test_dict_compiled_equality_with_python_and_object(self): def f_compare(x, y): return x == y @@ -834,6 +870,7 @@ def f_compare(x, y): self.assertEqual(r2, True) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_dict_size_change_during_iteration_raises(self): @Entrypoint def checkIt(): @@ -846,6 +883,7 @@ def checkIt(): with self.assertRaisesRegex(RuntimeError, "dictionary size changed"): checkIt() + @pytest.mark.group_one def test_dict_collisions(self): aDict = Dict(int, int)() @@ -862,6 +900,7 @@ def test_dict_collisions(self): if time.time() - t0 > 1e-5: print(i, time.time() - t0) + @pytest.mark.group_one def test_dict_of_object_compiles(self): aDict = Dict(object, object)() @@ -892,6 +931,7 @@ def put(d: Dict(object, object), k: object, v: object): print("object hash of UInt32(70) is ", compiledHash(object, UInt32(70))) assert aDict[UInt32(70)] == 60 + @pytest.mark.group_one def test_dict_of_oneof(self): A = Alternative("A", A=dict()) B = Alternative("B", B=dict()) @@ -905,6 +945,7 @@ def put(d, k, v): put(aDict, B.B(), 10) assert B.B() in aDict + @pytest.mark.group_one def test_dict_of_alternatives(self): A = Alternative("A", A=dict(x=int), B=dict(x=float)) @@ -926,6 +967,7 @@ def get(d, k): assert get(aDict, A.A(x=i)) == i assert get(aDict, A.B(x=i)) == i * 1000 + @pytest.mark.group_one def test_dict_of_concrete_alternatives(self): A = Alternative("A", A=dict(), B=dict(), C=dict(), D=dict()) @@ -949,6 +991,7 @@ def get(d, k): assert get(aDict, A.C()) == 3 assert get(aDict, A.D()) == 4 + @pytest.mark.group_one def test_yield_from_dict(self): def iterateTwice(d): for k in d: @@ -966,6 +1009,7 @@ def toList(d): assert toList(Dict(int, float)({1: 2.2})) == [1, 1] + @pytest.mark.group_one def test_yield_from_dict_values(self): def iterateTwice(d): for k in d.values(): @@ -983,6 +1027,7 @@ def toList(d): assert toList(Dict(int, float)({1: 2.2})) == [2.2, 2.2] + @pytest.mark.group_one def test_yield_from_dict_items(self): def iterateTwice(d): for k in d.items(): @@ -1000,6 +1045,7 @@ def toList(d): assert toList(Dict(int, float)({1: 2.2})) == [(1, 2.2), (1, 2.2)] + @pytest.mark.group_one def test_dict_with_const_dict_keys(self): d = Dict(ConstDict(int, int), int)() diff --git a/typed_python/compiler/tests/entrypoint_test.py b/typed_python/compiler/tests/entrypoint_test.py index 86eb711bb..8f8a5d48c 100644 --- a/typed_python/compiler/tests/entrypoint_test.py +++ b/typed_python/compiler/tests/entrypoint_test.py @@ -48,6 +48,7 @@ def aMethod(x): class TestCompileSpecializedEntrypoints(unittest.TestCase): + @pytest.mark.group_one def test_entrypoint_functions_work(self): @Entrypoint def f(x: TupleOf(int)): @@ -55,6 +56,7 @@ def f(x: TupleOf(int)): self.assertEqual(f.resultTypeFor(object).typeRepresentation, TupleOf(int)) + @pytest.mark.group_one def test_specialized_entrypoint(self): compiledAdd = Entrypoint(add) @@ -64,10 +66,12 @@ def test_specialized_entrypoint(self): self.assertEqual(compiledAdd(IntList([1, 2, 3]), 1), add(IntList([1, 2, 3]), 1)) self.assertEqual(compiledAdd(FloatList([1, 2, 3]), 1), add(FloatList([1, 2, 3]), 1)) + @pytest.mark.group_one def test_specialized_entrypoint_on_staticmethod(self): compiled = Entrypoint(AClass.aMethod) self.assertEqual(compiled(10), 11) + @pytest.mark.group_one def test_specialized_entrypoint_doesnt_recompile(self): def add(x, y): return x + y @@ -85,6 +89,7 @@ def add(x, y): self.assertEqual(Runtime.singleton().timesCompiled - compileCount, 2) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_specialized_entrypoint_dispatch_perf(self): def add(x, y): return x + y @@ -100,6 +105,7 @@ def add(x, y): self.assertTrue(time.time() - t0 < 5.0, time.time() - t0) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_specialized_entrypoint_perf_difference(self): compiledAdd = Entrypoint(add) @@ -118,6 +124,7 @@ def test_specialized_entrypoint_perf_difference(self): print("speedup for ", T, " is ", speedup) # I get about 70x + @pytest.mark.group_one def test_many_threads_compiling_same_specialization(self): @Entrypoint def sumFun(a, b): @@ -156,6 +163,7 @@ def threadloop(): assert not failed + @pytest.mark.group_one def test_specialization_noniterable_after_iterable(self): class AClass(): @@ -174,6 +182,7 @@ def specialized_f(x): r = specialized_f(x) self.assertTrue(r) + @pytest.mark.group_one def test_can_pass_types_as_values(self): @Entrypoint def append(T, x): @@ -183,6 +192,7 @@ def append(T, x): self.assertEqual(append(int, 1.5), [1]) + @pytest.mark.group_one def test_can_use_entrypoints_from_functions(self): @Entrypoint def f(x): @@ -198,6 +208,7 @@ def g(x): self.assertEqual(f(100), 100) + @pytest.mark.group_one def test_can_use_entrypoints_on_class_methods(self): class ARandomPythonClass: def __init__(self, x=10): @@ -219,6 +230,7 @@ def g2(x: int, y: int): self.assertEqual(ARandomPythonClass(23).f(10), 33) + @pytest.mark.group_one def test_can_use_entrypoints_on_typed_class_methods(self): class AClass(Class, Final): x = Member(int) @@ -251,6 +263,7 @@ def g2(x: int, y: float): self.assertEqual(AClass(x=23).g2(10, 20.5), 30.5) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_can_pass_functions_as_objects(self): def addsOne(x): return x + 1 @@ -295,6 +308,7 @@ def sumDoubles(count): @flaky(max_runs=3, min_passes=1) @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_sequential_append_performance(self): @Entrypoint def cumSum1(x): @@ -327,6 +341,7 @@ def cumSum2(x): @flaky(max_runs=3, min_passes=1) @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_nocompile_works(self): thisWouldNotBeVisible = set() @@ -356,6 +371,7 @@ def sumOver(count, x): self.assertLess(time.time() - t0, .4) + @pytest.mark.group_one def test_disable_compiled_code(self): @Entrypoint def sum(x: int): @@ -397,6 +413,7 @@ def sum(x: int): # this should be fast again self.assertLess(t5 - t4, (t1 - t0) * 2) + @pytest.mark.group_one def test_call_entrypoint_with_default_argument(self): @Entrypoint def f(x, y=1, z=2): @@ -405,6 +422,7 @@ def f(x, y=1, z=2): self.assertEqual(f(1), 4) self.assertEqual(f(1, 4), 7) + @pytest.mark.group_one def test_event_visitors(self): out = {} @@ -444,6 +462,7 @@ def f(x): self.assertTrue(out['f'][3]) assert type(out['f'][3][0]).__name__ == 'TypedCallTarget' + @pytest.mark.group_one def test_star_args_on_entrypoint(self): @Entrypoint def argCount(*args): @@ -452,6 +471,7 @@ def argCount(*args): self.assertEqual(argCount(1, 2, 3), 3) self.assertEqual(argCount(1, 2, 3, 4), 4) + @pytest.mark.group_one def test_star_args_on_entrypoint_typed(self): @Entrypoint def argCount(): @@ -474,6 +494,7 @@ def argCount(x, *args: int): self.assertEqual(argCount.resultTypeFor(int, int, str), None) + @pytest.mark.group_one def test_entrypoint_no_coercion(self): @Entrypoint def f(x): @@ -482,6 +503,7 @@ def f(x): self.assertEqual(f(1.5), float) self.assertEqual(f(1), int) + @pytest.mark.group_one def test_entrypoint_and_static_recursion_untyped_classes(self): class X: @staticmethod @@ -493,6 +515,7 @@ def sum(x): self.assertEqual(X.sum(10), sum(range(11))) + @pytest.mark.group_one def test_entrypoint_and_static_recursion_typed_classes(self): class X(Class): @staticmethod @@ -504,6 +527,7 @@ def sum(x): self.assertEqual(X.sum(10), sum(range(11))) + @pytest.mark.group_one def test_is_compiled(self): @Entrypoint def callIsCompiled(): @@ -514,6 +538,7 @@ def callIsCompiled(): with DisableCompiledCode(): self.assertFalse(callIsCompiled()) + @pytest.mark.group_one def test_entrypoint_always_compiles_when_called_with_numpy_array(self): @Entrypoint def f(x: ListOf(int)): @@ -528,6 +553,7 @@ def f(x: ListOf(int)): self.assertEqual(f(a), a.sum()) + @pytest.mark.group_one def test_can_compile_deserialized_functions(self): @Entrypoint def callIt(f, x): @@ -542,6 +568,7 @@ def aFun(x): self.assertEqual(callIt(aFun2, 10), aFun2(10)) + @pytest.mark.group_one def test_can_serialize_entrypoints(self): @Entrypoint def f(x): @@ -555,6 +582,7 @@ def f(x): self.assertEqual(f(10), f2(10)) + @pytest.mark.group_one def test_can_serialize_nocompile(self): @NotCompiled def f(x): @@ -568,6 +596,7 @@ def f(x): self.assertEqual(f(10), f2(10)) + @pytest.mark.group_one def test_can_serialize_functions_with_multiple_overloads(self): @Entrypoint def f(x): @@ -584,6 +613,7 @@ def f(x, y): self.assertEqual(f(10), f2(10)) self.assertEqual(f(10, 11), f2(10, 11)) + @pytest.mark.group_one def test_can_serialize_closures(self): x = 10 @@ -598,6 +628,7 @@ def adder(y): self.assertEqual(adder(10), adder2(10)) + @pytest.mark.group_one def test_not_compiled_references_work(self): @NotCompiled def simple(): diff --git a/typed_python/compiler/tests/exception_handling_test.py b/typed_python/compiler/tests/exception_handling_test.py index 3d0f01834..fd0890146 100644 --- a/typed_python/compiler/tests/exception_handling_test.py +++ b/typed_python/compiler/tests/exception_handling_test.py @@ -18,6 +18,7 @@ from typed_python import Entrypoint, ListOf, NotCompiled, _types +@pytest.mark.group_one def test_string_to_int_error_catchable(): @Entrypoint def f(x): @@ -31,6 +32,7 @@ def f(x): assert f("3.0") == "CAUGHT" +@pytest.mark.group_one def test_string_to_float_error_catchable(): @Entrypoint def f(x): @@ -44,6 +46,7 @@ def f(x): assert f("asdf") == "CAUGHT" +@pytest.mark.group_one def test_mod_zero_catchable(): @Entrypoint def f(x): @@ -56,6 +59,7 @@ def f(x): assert f(0.0) == "CAUGHT" +@pytest.mark.group_one def test_throwing_exceptions_from_C_code_triggers_destructors(): @NotCompiled def throws(): @@ -80,6 +84,7 @@ def f(x): assert _types.refcount(aList) == 2 +@pytest.mark.group_one def test_throwing_exceptions_from_uncompiled_code_triggers_destructors(): @NotCompiled def throws(): @@ -104,6 +109,7 @@ def f(x): assert _types.refcount(aList) == 2 +@pytest.mark.group_one def test_exceptions_from_not_compiled(): @NotCompiled def g0(x): @@ -120,6 +126,7 @@ def f0(x): assert f0(0.0) == "caught" +@pytest.mark.group_one def test_can_rethrow_in_compiled_code(): def throws(): raise Exception("something to throw") @@ -140,6 +147,7 @@ def f(): assert aList == ["something to throw"] +@pytest.mark.group_one def test_raise_non_exception_in_compiled_code(): @Entrypoint def throw(x): @@ -152,6 +160,7 @@ def throw(x): throw(None) +@pytest.mark.group_one def test_can_capture_exception_and_rethrow(): def throws(): raise Exception("From 'throws'") @@ -186,9 +195,23 @@ def getStringTraceback(toCall): assert 'in g' in stringTb # verify the compiler is the same - assert getStringTraceback(f) == getStringTraceback(Entrypoint(f)) + s1 = getStringTraceback(f) + s2 = getStringTraceback(Entrypoint(f)) + if s1 != s2: + print() + print("interpreter") + print(s1) + print() + print() + print() + print("compiler") + print(s2) + assert s1 == s2 + + +@pytest.mark.group_one def test_catch_and_return_none(): def blah(x): if x: @@ -207,6 +230,7 @@ def trySplit(x): assert trySplit("a_b_c") is None +@pytest.mark.group_one def test_catch_multiple_types(): @Entrypoint def catcher(toRaise): @@ -222,6 +246,7 @@ def catcher(toRaise): catcher(RuntimeError) +@pytest.mark.group_one def test_convert_assert(): @Entrypoint def assertIt(x): @@ -233,6 +258,7 @@ def assertIt(x): assertIt(False) +@pytest.mark.group_one def test_convert_assert_str(): @Entrypoint def assertIt(x): @@ -242,3 +268,12 @@ def assertIt(x): with pytest.raises(AssertionError): assertIt(False) + + +def test_raise_simple_str(): + @Entrypoint + def raiseStringException(x): + raise UserWarning(str(x)) + + with pytest.raises(UserWarning): + raiseStringException(100) diff --git a/typed_python/compiler/tests/exceptions_from_c_code_test.py b/typed_python/compiler/tests/exceptions_from_c_code_test.py index 735ce5bb1..767daec33 100644 --- a/typed_python/compiler/tests/exceptions_from_c_code_test.py +++ b/typed_python/compiler/tests/exceptions_from_c_code_test.py @@ -15,6 +15,7 @@ from typed_python import Entrypoint, ListOf, NotCompiled, _types +@pytest.mark.group_one def test_string_to_int_error_catchable(): @Entrypoint def f(x): @@ -28,6 +29,7 @@ def f(x): assert f("3.0") == "CAUGHT" +@pytest.mark.group_one def test_string_to_float_error_catchable(): @Entrypoint def f(x): @@ -41,6 +43,7 @@ def f(x): assert f("asdf") == "CAUGHT" +@pytest.mark.group_one def test_mod_zero_catchable(): @Entrypoint def f(x): @@ -53,6 +56,7 @@ def f(x): assert f(0.0) == "CAUGHT" +@pytest.mark.group_one def test_throwing_exceptions_from_C_code_triggers_destructors(): @NotCompiled def throws(): @@ -77,6 +81,7 @@ def f(x): assert _types.refcount(aList) == 2 +@pytest.mark.group_one def test_throwing_exceptions_from_uncompiled_code_triggers_destructors(): @NotCompiled def throws(): @@ -101,6 +106,7 @@ def f(x): assert _types.refcount(aList) == 2 +@pytest.mark.group_one def test_exceptions_from_not_compiled(): @NotCompiled def g0(x): diff --git a/typed_python/compiler/tests/function_signature_calculator_test.py b/typed_python/compiler/tests/function_signature_calculator_test.py index 76441e5ea..60e89cc66 100644 --- a/typed_python/compiler/tests/function_signature_calculator_test.py +++ b/typed_python/compiler/tests/function_signature_calculator_test.py @@ -32,6 +32,7 @@ def anyIsBad(types): return False +@pytest.mark.group_one def test_basic(): class A(Class): pass @@ -102,6 +103,7 @@ def f(self, x) -> bytes: assert calc.returnTypeFor([ChildClassWithBadOverride, Both], {}) is SomeInvalidClassReturnType +@pytest.mark.group_one def test_override_diamond(): class BaseClass(Class): def f(self, x) -> int: @@ -126,6 +128,7 @@ def f(self, x: int) -> int: assert not calc.overloadInvalidSignatures(0, [ChildChildClass, int], {}) +@pytest.mark.group_one def test_understands_more_specific_types(): @Function def f(x: int) -> lambda X: X: @@ -136,6 +139,7 @@ def f(x: int) -> lambda X: X: assert calc.returnTypeFor([OneOf(int, float)], {}) is int +@pytest.mark.group_one def test_convert_subclass_of_trivially(): class C(Class): pass diff --git a/typed_python/compiler/tests/generators_test.py b/typed_python/compiler/tests/generators_test.py index 5a429eabd..7d434d130 100644 --- a/typed_python/compiler/tests/generators_test.py +++ b/typed_python/compiler/tests/generators_test.py @@ -34,6 +34,7 @@ def timeIt(f): class TestGeneratorsAndComprehensions(unittest.TestCase): + @pytest.mark.group_one def test_list_comp(self): @Entrypoint def listComp(x): @@ -44,6 +45,7 @@ def listComp(x): assert isinstance(lst, list) assert lst == [a + 1 for a in range(10)] + @pytest.mark.group_one def test_set_comprehension(self): @Entrypoint def setComp(x): @@ -54,6 +56,7 @@ def setComp(x): assert isinstance(st, set) assert st == {a + 1 for a in range(10)} + @pytest.mark.group_one def test_tuple_comprehension(self): @Entrypoint def tupComp(x): @@ -64,6 +67,7 @@ def tupComp(x): assert isinstance(tup, tuple) assert tup == tuple(a + 1 for a in range(10)) + @pytest.mark.group_one def test_dict_comprehension(self): @Entrypoint def dictComp(x): @@ -74,6 +78,7 @@ def dictComp(x): assert isinstance(d, dict) assert d == {a: a + 1 for a in range(10)} + @pytest.mark.group_one def test_dict_comprehension_multiple_types(self): def dictComp(x): return {k if (k%3) else "Boo": k + 1 if (k % 2) else "hi" for k in range(10)} @@ -85,6 +90,7 @@ def dictComp(x): assert d == dictComp(10) + @pytest.mark.group_one def test_list_from_listcomp(self): @Entrypoint def listComp(x): @@ -95,6 +101,7 @@ def listComp(x): assert isinstance(lst, ListOf(int)) assert lst == [a + 1 for a in range(10)] + @pytest.mark.group_one def test_generator_exp_is_generator(self): @Entrypoint def generatorComp(x): @@ -107,6 +114,7 @@ def generatorComp(x): assert list(g) == [x + 1 for x in range(10)] @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_list_from_listcomp_perf(self): def sum(iterable): res = 0 @@ -164,6 +172,7 @@ def listCompSumUntyped(x): assert untypedTime / avgCompiledTime > 10 @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_untyped_tuple_from_listcomp_perf(self): import time @@ -227,6 +236,7 @@ def executeInLoop(self, f, duration=.25, threshold=1.0): self.assertLess(currentMemUsageMb() - memUsage, threshold) @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_listcomp_doesnt_leak(self): @Entrypoint def listComp(x): @@ -245,6 +255,7 @@ def sumListComp(x): self.executeInLoop(lambda: sumListComp(1000000), duration=.1, threshold=20.0) self.executeInLoop(lambda: sumListComp(1000000), duration=.25, threshold=1.0) + @pytest.mark.group_one def test_call_generator(self): @Entrypoint def generateInts(ct): @@ -253,6 +264,7 @@ def generateInts(ct): assert list(generateInts(100)) == [1, 2] + @pytest.mark.group_one def test_call_generator_with_branch(self): @Entrypoint def generateInts(ct): @@ -268,6 +280,7 @@ def generateInts(ct): assert list(generateInts(1)) == [1, 2, 4] assert list(generateInts(-1)) == [1, 3, 4] + @pytest.mark.group_one def test_call_generator_with_loop(self): @Entrypoint def generateInts(ct): @@ -282,6 +295,7 @@ def generateInts(ct): assert list(generateInts(10)) == list(range(10)) + [-1, -2] assert list(generateInts(0)) == list(range(0)) + [-1, -2] + @pytest.mark.group_one def test_call_generator_with_closure_var(self): xInClosure = 100 @@ -294,6 +308,7 @@ def generateInts(ct): assert list(generateInts(10)) == [1, 100, 10, 2] + @pytest.mark.group_one def test_call_generator_with_arg_assign(self): @Entrypoint def generateInts(ct): @@ -303,6 +318,7 @@ def generateInts(ct): assert list(generateInts(10)) == [10, 2] + @pytest.mark.group_one def test_call_generator_with_aug_assign(self): @Entrypoint def generateInts(ct): @@ -316,6 +332,7 @@ def generateInts(ct): assert list(generateInts(0)) == [0, 1, 3, 6] + @pytest.mark.group_one def test_call_generator_with_ann_assign(self): @Entrypoint def generateInts(ct): @@ -325,6 +342,7 @@ def generateInts(ct): assert list(generateInts(0)) == [0, 1] + @pytest.mark.group_one def test_call_generator_with_pass(self): @Entrypoint def generateInts(ct): @@ -335,6 +353,7 @@ def generateInts(ct): assert list(generateInts(100)) == [100] + @pytest.mark.group_one def test_call_generator_with_continue(self): @Entrypoint def generateInts(ct): @@ -351,6 +370,7 @@ def generateInts(ct): assert list(generateInts(5)) == [0, 1, 1, 2, 3, 3, 4, 5] + @pytest.mark.group_one def test_call_generator_with_break(self): @Entrypoint def generateInts(ct): @@ -367,6 +387,7 @@ def generateInts(ct): assert list(generateInts(5)) == [0, 1, 1] + @pytest.mark.group_one def test_call_generator_with_closure_var_cant_assign(self): xInClosure = 100 @@ -381,6 +402,7 @@ def generateInts(ct): with self.assertRaises(NameError): assert list(generateInts(10)) == [1, 100, 10, 2] + @pytest.mark.group_one def test_call_generator_with_assert(self): @Entrypoint def generateInts(ct): @@ -393,6 +415,7 @@ def generateInts(ct): assert list(generateInts(15)) == [15, 5] + @pytest.mark.group_one def test_call_generator_with_try_finally(self): @Entrypoint def generateInts(): @@ -409,6 +432,7 @@ def generateInts(): assert list(generateInts()) == [1, 2, 3, 4, 5] + @pytest.mark.group_one def test_call_generator_with_try(self): @Entrypoint def generateInts(): @@ -435,6 +459,7 @@ def generateInts(): assert list(generateInts()) == [1, 2, 3, 4, 5, 6] + @pytest.mark.group_one def test_generator_produces_stop_iteration_when_done(self): @Entrypoint def generateInts(): @@ -456,6 +481,7 @@ def generateInts(): with pytest.raises(StopIteration): g.__next__() + @pytest.mark.group_one def test_raise_in_generator_stops_iteration(self): @Entrypoint def generateInts(): @@ -480,6 +506,7 @@ def generateInts(): g.__next__() @pytest.mark.skip(reason='not implemented yet') + @pytest.mark.group_one def test_reraise_in_generator_after_yield(self): @Entrypoint def generateInts(): @@ -503,6 +530,7 @@ def generateInts(): with pytest.raises(Exception, match="catch me"): g.__next__() + @pytest.mark.group_one def test_return_in_generator(self): @Entrypoint def generateInts(): @@ -524,6 +552,7 @@ def generateInts(): except StopIteration as i: assert i.args == () + @pytest.mark.group_one def test_argless_return_in_generator(self): @Entrypoint def generateInts(): @@ -545,6 +574,7 @@ def generateInts(): except StopIteration as i: assert i.args == () + @pytest.mark.group_one def test_with_in_generator(self): class ContextManager(Class, Final): entered = Member(int) @@ -598,6 +628,7 @@ def generateInts(x): assert g.__next__() == 6 assert cm.entered == 0 + @pytest.mark.group_one def test_for_in_generator(self): @Entrypoint def generateInts(x): @@ -624,6 +655,7 @@ def generateInts(x): with self.assertRaises(StopIteration): assert g.__next__() == -3 + @pytest.mark.group_one def test_for_in_generator_over_various_builtin_types(self): @Entrypoint def generate(l): @@ -638,6 +670,7 @@ def generate(l): ]: assert list(generate(toIterate)) == list(toIterate) + @pytest.mark.group_one def test_can_iterate_class(self): class C(Class, Final): x = Member(int) @@ -660,6 +693,7 @@ def iterate(l): print(list(c)) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_can_iterate_class_perf(self): class C(Class, Final): x = Member(int) @@ -710,6 +744,7 @@ def addUntyped(iterable): # I get about 12. assert elapsedUntyped / elapsedTyped > 4 + @pytest.mark.group_one def test_can_use_lambdas_in_generators(self): @Entrypoint def iterate(x): @@ -720,6 +755,7 @@ def iterate(x): assert list(iterate(10)) == [2, 20] + @pytest.mark.group_one def test_can_use_lambdas_in_generators_with_renamed_variables(self): @Entrypoint def iterate(x): @@ -730,6 +766,7 @@ def iterate(x): assert list(iterate(10)) == [2, 20] + @pytest.mark.group_one def test_can_make_closures_in_generator(self): @Entrypoint def iterate(x): @@ -741,6 +778,7 @@ def f(y): assert list(iterate(10)) == [2, 20] + @pytest.mark.group_one def test_generator_interior_closures_masked_correctly(self): @Entrypoint def iterate(x): @@ -753,6 +791,7 @@ def f(y): assert list(iterate(10)) == [2, 20] + @pytest.mark.group_one def test_generator_interior_closures_capture(self): @Entrypoint def iterate(x): @@ -763,6 +802,7 @@ def f(y): assert list(iterate(10)) == [11] + @pytest.mark.group_one def test_generator_doubly_interior_closures_masked_correctly(self): @Entrypoint def iterate(x): @@ -777,6 +817,7 @@ def g(): assert list(iterate(10)) == [2, 20] + @pytest.mark.group_one def test_generator_in_generator(self): @Entrypoint def iterate(x): @@ -792,6 +833,7 @@ def f(y): assert list(iterate(10)) == [3, 5, 12, 14] + @pytest.mark.group_one def test_generator_in_generator_reading_parent(self): @Entrypoint def iterate(x): @@ -802,6 +844,7 @@ def f(y): assert list(iterate(10)) == [11] + @pytest.mark.group_one def test_list_comp_in_generator(self): @Entrypoint def iterate(x): @@ -809,6 +852,7 @@ def iterate(x): assert list(iterate(10)) == [list(range(10))] + @pytest.mark.group_one def test_set_comp_in_generator(self): @Entrypoint def iterate(x): @@ -816,6 +860,7 @@ def iterate(x): assert list(iterate(10)) == [set(range(10))] + @pytest.mark.group_one def test_tuple_comp_in_generator(self): @Entrypoint def iterate(x): @@ -823,6 +868,7 @@ def iterate(x): assert list(iterate(10)) == [tuple(range(10))] + @pytest.mark.group_one def test_dict_comp_in_generator(self): @Entrypoint def iterate(x): @@ -831,6 +877,7 @@ def iterate(x): assert list(iterate(10)) == [{z: z + 1 for z in range(10)}] @pytest.mark.skip("not implemented yet") + @pytest.mark.group_one def test_list_comp_masking(self): # check that the masking behavior of nested variables in list comps is right # technically, each successive listcomp is its own scope @@ -843,6 +890,7 @@ def iterate(x): x = 10 assert iterate(10) == [x+1 for x in range(x) for x in range(x - 3)] + @pytest.mark.group_one def test_type_annotations_on_generator(self): @Entrypoint def iterate(x) -> Generator(OneOf(None, int)): @@ -850,6 +898,7 @@ def iterate(x) -> Generator(OneOf(None, int)): assert isinstance(iterate(10), Generator(OneOf(None, int))) + @pytest.mark.group_one def test_generators_come_precompiled(self): # verify that once we trigger a generator # we don't force it to compile when we actually use it - @@ -887,6 +936,7 @@ def callIt(actually: int): assert secondTime < 0.0001 assert thirdTime < 0.0001 + @pytest.mark.group_one def test_generators_on_object_instances(self): @Entrypoint def callAll(x: object): @@ -894,6 +944,7 @@ def callAll(x: object): assert callAll(['1', '2']) == ['1', '2'] + @pytest.mark.group_one def test_generator_on_object_instance_type(self): def startIterating(x): for y in x: diff --git a/typed_python/compiler/tests/hash_compilation_test.py b/typed_python/compiler/tests/hash_compilation_test.py index 6b30f839b..16389f04a 100644 --- a/typed_python/compiler/tests/hash_compilation_test.py +++ b/typed_python/compiler/tests/hash_compilation_test.py @@ -28,6 +28,7 @@ def compiledHash(x): class TestHashCompilation(unittest.TestCase): + @pytest.mark.group_one def test_hashes_equivalent_integers(self): someIntegers = [] @@ -39,6 +40,7 @@ def test_hashes_equivalent_integers(self): for intVal in someIntegers: self.assertEqual(hash(intType(intVal)), int(compiledHash(intType(intVal))), (intType, intVal, intType(intVal))) + @pytest.mark.group_one def test_hashes_equivalent_floats(self): # we have to do this through tuples because if we 'hash' a normal python str, # we use python's hash function which is not the same as the typed_python one. @@ -51,6 +53,7 @@ def test_hashes_equivalent_floats(self): self.assertEqual(hash(tup), compiledHash(tup)) + @pytest.mark.group_one def test_hash_tuples(self): for valueMaker in [ lambda: Tuple()(()), @@ -59,6 +62,7 @@ def test_hash_tuples(self): ]: self.assertEqual(hash(valueMaker()), compiledHash(valueMaker())) + @pytest.mark.group_one def test_hash_strings_and_bytes(self): # we have to do this through tuples because if we 'hash' a normal python str, # we use python's hash function which is not the same as the typed_python one. diff --git a/typed_python/compiler/tests/held_class_compilation_test.py b/typed_python/compiler/tests/held_class_compilation_test.py index c0dbd2283..21d533e96 100644 --- a/typed_python/compiler/tests/held_class_compilation_test.py +++ b/typed_python/compiler/tests/held_class_compilation_test.py @@ -73,6 +73,7 @@ def checkCompiler(self, f, *args, **kwargs): self.assertEqual(compiledOutput, interpretedOutput) + @pytest.mark.group_one def test_held_class_pointer_to_self(self): @Entrypoint def callPointerTo(h): @@ -83,6 +84,7 @@ def callPointerTo(h): assert callPointerTo(h) == pointerTo(h) assert h.pointerToSelf() == pointerTo(h) + @pytest.mark.group_one def test_comparison_calls_magic_method(self): @Held class H(Class, Final): @@ -111,6 +113,7 @@ def checkIt(): checkIt() Entrypoint(checkIt)() + @pytest.mark.group_one def test_comparison_magic_reverse_magic_method(self): @Held class H(Class, Final): @@ -145,6 +148,7 @@ def checkIt(): checkIt() Entrypoint(checkIt)() + @pytest.mark.group_one def test_comparison_default(self): @Held class H(Class, Final): @@ -182,6 +186,7 @@ def checkIt(): checkIt() Entrypoint(checkIt)() + @pytest.mark.group_one def test_comparison_against_object(self): @Held class H(Class, Final): @@ -195,14 +200,17 @@ def checkEqual(h: H, o: object): assert checkEqual(H(x=2), H(x=2)) assert not checkEqual(H(x=2), H(x=3)) + @pytest.mark.group_one def test_held_class_repr(self): assert repr(H()) == "ReprForH" self.checkCompiler(lambda x: repr(x), H()) + @pytest.mark.group_one def test_held_class_str(self): assert str(H()) == "StrForH" self.checkCompiler(lambda x: str(x), H()) + @pytest.mark.group_one def test_held_class_entrypointed_methods(self): h1 = H(x=2, y=3) h2 = H(x=2, y=3) @@ -213,6 +221,7 @@ def test_held_class_entrypointed_methods(self): assert h1.x == h2.x assert h1.getX() == h1.x + @pytest.mark.group_one def test_stringify_held_class(self): h = H(x=2, y=3) @@ -222,6 +231,7 @@ def callStr(h): assert str(h) == callStr(h) + @pytest.mark.group_one def test_pointer_to_held_class_compiles(self): h = H(x=2, y=3) @@ -231,6 +241,7 @@ def getPtr(h): assert pointerTo(h) == getPtr(h) + @pytest.mark.group_one def test_pass_held_to_function_with_signature(self): @Entrypoint def f(h: H): @@ -244,6 +255,7 @@ def g(): assert g().x == 100 + @pytest.mark.group_one def test_pass_held_by_ref_across_entrypoint(self): @Entrypoint def g(h): @@ -253,6 +265,7 @@ def g(h): g(h) assert h.x == 100 + @pytest.mark.group_one def test_compile_held_class(self): @Held class H(Class, Final): @@ -290,6 +303,7 @@ def move(c): self.checkCompiler(lambda c: c.h1.f(), c) self.checkCompiler(lambda c: c.h1.typeOfSelf(), c) + @pytest.mark.group_one def test_compile_list_of_held_class(self): assert not _types._temporaryReferenceTracerActive() @@ -361,6 +375,7 @@ def incrementViaIterator(l): self.assertEqual(getitem(aList, 0).x, 2) self.assertEqual(getitem(aList, 5).x, 2) + @pytest.mark.group_one def test_compile_construct_with_init(self): @Held class H(Class, Final): @@ -377,6 +392,7 @@ def __init__(self, x): # noqa self.checkCompiler(lambda: H(x=10).x) + @pytest.mark.group_one def test_compile_access_child_held_class(self): @Held class H2(Class, Final): @@ -389,10 +405,12 @@ def f(): self.checkCompiler(f) + @pytest.mark.group_one def test_compile_add_operator(self): self.checkCompiler(lambda: (Complex(real=10) + 20).real) self.checkCompiler(lambda: (Complex(real=10) + Complex(imag=20)).imag) + @pytest.mark.group_one def test_compile_add_operator_perf(self): @Entrypoint def f(ct): @@ -408,6 +426,7 @@ def f(ct): f(100000000) print(time.time() - t0) + @pytest.mark.group_one def test_del_works(self): delType = ListOf(type)() @@ -433,6 +452,7 @@ def doIt(): assert len(delType) >= 1 assert delType[0] == C + @pytest.mark.group_one def test_class_hasattr(self): @Held class C(Class): @@ -465,6 +485,7 @@ def compiledDel(): compiledDel() + @pytest.mark.group_one def test_class_hasattr_perf(self): @Held class C(Class): diff --git a/typed_python/compiler/tests/held_class_interpreter_semantics_test.py b/typed_python/compiler/tests/held_class_interpreter_semantics_test.py index b90b520d5..80b8bc994 100644 --- a/typed_python/compiler/tests/held_class_interpreter_semantics_test.py +++ b/typed_python/compiler/tests/held_class_interpreter_semantics_test.py @@ -25,6 +25,7 @@ def increment(self): class TestHeldClassInterpreterSemantics(unittest.TestCase): + @pytest.mark.group_one def test_held_class_str(self): @Held class H(Class): @@ -33,6 +34,7 @@ def __str__(self): assert str(H()) == "HI" + @pytest.mark.group_one def test_can_return_held_class_from_typed_function(self): @Function def f(x, y) -> H: @@ -47,6 +49,7 @@ def f(x, y) -> H: assert res2.x == 12 assert res2.y == 22 + @pytest.mark.group_one def test_construct_and_call_method(self): # note that we can't just call this at the root of the function # because pytest keeps all the temporary variables alive, which obviates @@ -56,6 +59,7 @@ def runTest(): assert runTest() == 30 + @pytest.mark.group_one def test_construct_and_call_method_multiline(self): def runTest(): res = H(x=10, y=20).addToX( @@ -73,6 +77,7 @@ def runTest2(): assert runTest() == 20 assert runTest2() == 20 + @pytest.mark.group_one def test_can_assign_to_held_class_in_list(self): def runTest(): aList = ListOf(H)() @@ -84,6 +89,7 @@ def runTest(): runTest() + @pytest.mark.group_one def test_list_of_held_class_item_type(self): assert sys.gettrace() is None @@ -106,12 +112,14 @@ def test_list_of_held_class_item_type(self): assert sys.gettrace() is None + @pytest.mark.group_one def test_construct_held_class_on_heap_doesnt_leak(self): mb = currentMemUsageMb() for _ in range(100000): H() assert currentMemUsageMb() - mb < .1 + @pytest.mark.group_one def test_can_call_held_class_in_interpreter(self): @Held class H(Class, Final): @@ -120,6 +128,7 @@ def __call__(self, a): assert H()(10) == (H, 10) + @pytest.mark.group_one def test_can_construct_held_class_on_heap(self): h = H(x=10, y=20) assert type(h) is H @@ -129,6 +138,7 @@ def test_can_construct_held_class_on_heap(self): assert h.x == 20 + @pytest.mark.group_one def test_can_construct_held_class_on_heap_with_init(self): @Held class H(Class, Final): @@ -140,6 +150,7 @@ def __init__(self): h = H() assert h.x == 100 + @pytest.mark.group_one def test_held_class_methods_get_passed_refs(self): @Held class H(Class, Final): @@ -148,6 +159,7 @@ def f(self): assert H().f() is H + @pytest.mark.group_one def test_multiple_refs_simultaneously(self): aList = ListOf(H)() aList.resize(2) @@ -192,6 +204,7 @@ def runTest(): runTest() + @pytest.mark.group_one def test_refs_passed_to_functions(self): aList = ListOf(H)() aList.resize(1) @@ -228,6 +241,7 @@ def outer(h, val): assert aList[0].x == 30 @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_nested_ref_call_cost(self): # verify that the python interpreter is not # slowed down too much while HeldClass references are in play. @@ -254,6 +268,7 @@ def f(l, h, depth): f(aList, aList[0], 0) + @pytest.mark.group_one def test_access_held_class_functions(self): aList = ListOf(H)() aList.resize(1) @@ -265,6 +280,7 @@ def test_access_held_class_functions(self): assert aList[0].x == 11 + @pytest.mark.group_one def test_held_class_held_classes(self): @Held class H2(Class, Final): @@ -283,6 +299,7 @@ class H2(Class, Final): aList[0].h = h assert aList[0].h.x == 5 + @pytest.mark.group_one def test_held_class_ref_conversion_with_existing_trace_function(self): # HeldClass uses 'sys.settrace' internally to know when the temporary ref # needs to get converted to a proper instance. We need to check that this doesn't @@ -321,6 +338,7 @@ def tryIt(l): assert traced1 == traced2 assert type(objects1[0]) is H + @pytest.mark.group_one def test_held_class_instance_conversion_doesnt_leak(self): aList = ListOf(H)() aList.resize(1) @@ -337,6 +355,7 @@ def test_held_class_instance_conversion_doesnt_leak(self): assert leakSize < .1 + @pytest.mark.group_one def test_pointer_to_held_class(self): h = H() @@ -345,6 +364,7 @@ def test_pointer_to_held_class(self): h.x = 10 assert p.x.get() == 10 + @pytest.mark.group_one def test_contains_operator(self): @Held class H(Class, Final): @@ -356,6 +376,7 @@ def __contains__(self, other): assert 10 in H(x=10) assert 11 not in H(x=10) + @pytest.mark.group_one def test_len_operator(self): @Held class H(Class, Final): @@ -366,6 +387,7 @@ def __len__(self): assert len(H(x=10)) == 10 + @pytest.mark.group_one def test_getitem(self): @Held class H(Class, Final): @@ -376,6 +398,7 @@ def __getitem__(self, y): assert H(x=10)[20] == 30 + @pytest.mark.group_one def test_setitem(self): @Held class H(Class, Final): @@ -391,6 +414,7 @@ def __setitem__(self, x, y): h[1] = 30 assert h.x == 20 + @pytest.mark.group_one def test_inquiry(self): @Held class H(Class, Final): @@ -408,6 +432,7 @@ def __bool__(self): assert H2(x=1) assert not H2(x=0) + @pytest.mark.group_one def test_ceil(self): @Held class H(Class, Final): @@ -416,6 +441,7 @@ def __ceil__(self): assert math.ceil(H()) == 123 + @pytest.mark.group_one def test_add_operator(self): @Held class H(Class, Final): @@ -426,6 +452,7 @@ def __add__(self, other): assert H(x=12) + 1 == 13 + @pytest.mark.group_one def test_nested_held_classes(self): @Held class H1(Class, Final): @@ -443,6 +470,7 @@ def checkX(h): checkX(H2(10).h) + @pytest.mark.group_one def test_temporary_held_classes_in_lists(self): @Held class H1(Class, Final): diff --git a/typed_python/compiler/tests/isinstance_compilation_test.py b/typed_python/compiler/tests/isinstance_compilation_test.py index eda298c30..adfebb829 100644 --- a/typed_python/compiler/tests/isinstance_compilation_test.py +++ b/typed_python/compiler/tests/isinstance_compilation_test.py @@ -19,6 +19,7 @@ class TestIsinstanceCompilation(unittest.TestCase): + @pytest.mark.group_one def test_basic_isinstance(self): @Entrypoint def isInt(x): @@ -28,6 +29,7 @@ def isInt(x): self.assertFalse(isInt(1.0)) self.assertFalse(isInt("hi")) + @pytest.mark.group_one def test_isinstance_with_oneof(self): @Entrypoint def isIntOneOf(x: OneOf(int, float)): @@ -36,6 +38,7 @@ def isIntOneOf(x: OneOf(int, float)): self.assertTrue(isIntOneOf(0)) self.assertFalse(isIntOneOf(1.0)) + @pytest.mark.group_one def test_isinstance_with_oneof_and_str(self): @Entrypoint def isStrOneOf(x: OneOf(int, str)): @@ -44,6 +47,7 @@ def isStrOneOf(x: OneOf(int, str)): self.assertFalse(isStrOneOf(0)) self.assertTrue(isStrOneOf("1.0")) + @pytest.mark.group_one def test_isinstance_with_value(self): @Entrypoint def isIntValue(x: OneOf(0, 1.0)): @@ -52,6 +56,7 @@ def isIntValue(x: OneOf(0, 1.0)): self.assertTrue(isIntValue(0)) self.assertFalse(isIntValue(1.0)) + @pytest.mark.group_one def test_isinstance_complex(self): @Entrypoint def isTupleOfInt(x): @@ -61,6 +66,7 @@ def isTupleOfInt(x): self.assertFalse(isTupleOfInt((1, 2))) self.assertTrue(isTupleOfInt(TupleOf(int)((1, 2)))) + @pytest.mark.group_one def test_isinstance_typeof_none(self): @Entrypoint def isNone(x): diff --git a/typed_python/compiler/tests/list_of_compilation_test.py b/typed_python/compiler/tests/list_of_compilation_test.py index 920013bc1..53af8465e 100644 --- a/typed_python/compiler/tests/list_of_compilation_test.py +++ b/typed_python/compiler/tests/list_of_compilation_test.py @@ -42,777 +42,3 @@ def checkFunction(self, f, argsToCheck): self.assertEqual(fastval, slowval) return t_py, t_fast - def test_list_of_list_refcounts(self): - @Compiled - def f(x: ListOf(ListOf(int)), z: bool): - if z: - y = x[0] # noqa - - return x - - return 10 - - aList = ListOf(ListOf(int))() - aList.resize(1) - - interiorList = aList[0] - - rc = _types.refcount(interiorList) - - f(aList, True) - - self.assertEqual(rc, _types.refcount(interiorList)) - - def test_list_of_float(self): - def f(x: ListOf(float), y: ListOf(float)) -> float: - j = 0 - res = 0.0 - i = 0 - - while j < len(y): - i = 0 - while i < len(x): - res = res + x[i] * y[j] - i = i + 1 - j = j + 1 - - return res - - aListOfFloat = ListOf(float)(list(range(1000))) - aListOfFloat2 = ListOf(float)(list(range(1000))) - - self.assertEqual(_types.refcount(aListOfFloat), 1) - - t_py, t_fast = self.checkFunction(f, [(aListOfFloat, aListOfFloat2)]) - - self.assertEqual(_types.refcount(aListOfFloat), 1) - - # I get around 150x - self.assertTrue(t_py / t_fast > 50.0) - - print(t_py / t_fast, " speedup") - - def test_list_negative_indexing(self): - @Compiled - def getitem(x: ListOf(int), y: int): - return x[y] - - for listToCheck in [[], [1], [1, 2], [1, 2, 3]]: - for ix in [-2, -1, 0, 1, 2]: - try: - val = listToCheck[ix] - except IndexError: - val = None - - if val is not None: - self.assertEqual(val, getitem(listToCheck, ix)) - else: - with self.assertRaises(Exception): - getitem(listToCheck, ix) - - def test_list_passing(self): - @Compiled - def f(x: ListOf(int)) -> int: - return 0 - - self.assertEqual(f((1, 2, 3)), 0) - - def test_list_len(self): - @Compiled - def f(x: ListOf(int)) -> int: - return len(x) - - self.assertEqual(f((1, 2, 3)), 3) - - def test_list_assign(self): - @Compiled - def f(x: ListOf(int)) -> ListOf(int): - y = x - return y - - t = ListOf(int)((1, 2, 3)) - - self.assertEqual(f(t), t) - - self.assertEqual(_types.refcount(t), 1) - - def test_list_indexing(self): - @Compiled - def f(x: ListOf(int), y: int) -> int: - return x[y] - - self.assertEqual(f((1, 2, 3), 1), 2) - - with self.assertRaises(Exception): - f((1, 2, 3), 1000000000) - - def test_list_refcounting(self): - @Function - def f(x: ListOf(int), y: ListOf(int)) -> ListOf(int): - return x - - for compileIt in [False, True]: - if compileIt: - f = Compiled(f) - - intTup = ListOf(int)(list(range(1000))) - - self.assertEqual(_types.refcount(intTup), 1) - - res = f(intTup, intTup) - - self.assertEqual(_types.refcount(intTup), 2) - - res = None # noqa: F841 - - self.assertEqual(_types.refcount(intTup), 1) - - def test_list_of_adding(self): - T = ListOf(int) - - @Compiled - def f(x: T, y: T) -> T: - return x + y - - t1 = T((1, 2, 3)) - t2 = T((3, 4)) - - res = f(t1, t2) - - self.assertEqual(_types.refcount(res), 1) - self.assertEqual(_types.refcount(t1), 1) - self.assertEqual(_types.refcount(t2), 1) - - self.assertEqual(res, t1+t2) - - def test_list_of_list_refcounting(self): - T = ListOf(int) - TT = ListOf(T) - - @Compiled - def f(x: TT) -> TT: - return x + x + x - - t1 = T((1, 2, 3)) - t2 = T((4, 5, 5)) - - aTT = TT((t1, t2)) - - fRes = f(aTT) - - self.assertEqual(fRes, aTT+aTT+aTT) - self.assertEqual(_types.refcount(aTT), 1) - self.assertEqual(_types.refcount(fRes), 1) - - fRes = None - aTT = None - self.assertEqual(_types.refcount(t1), 1) - - def test_list_creation_doesnt_leak(self): - T = ListOf(int) - - @Compiled - def f(x: T, y: T) -> T: - return x + y - - t1 = T(tuple(range(10000))) - - initMem = psutil.Process().memory_info().rss / 1024 ** 2 - - for i in range(10000): - f(t1, t1) - - finalMem = psutil.Process().memory_info().rss / 1024 ** 2 - - self.assertTrue(finalMem < initMem + 5) - - def test_list_reserve(self): - T = ListOf(TupleOf(int)) - - @Compiled - def f(x: T): - x.reserve(x.reserved() + 10) - - aList = T() - aList.resize(10) - - oldReserved = aList.reserved() - f(aList) - self.assertEqual(oldReserved+10, aList.reserved()) - - def test_list_resize(self): - T = ListOf(TupleOf(int)) - - aTup = TupleOf(int)((1, 2, 3)) - - @Compiled - def f(x: T, y: TupleOf(int)): - x.resize(len(x) + 10, y) - - aList = T() - aList.resize(10) - - f(aList, aTup) - - self.assertEqual(_types.refcount(aTup), 11) - - def test_list_extend(self): - T = ListOf(int) - - @Compiled - def f(x: T, y: T): - x.extend(y) - - t = T([1, 2, 3]) - t2 = T([1, 2, 3]) - - f(t, t2) - - self.assertEqual(t, [1, 2, 3, 1, 2, 3]) - - t = T([1, 2, 3]) - t2 = T([1, 2, 3]) - - for _ in range(5): - print(len(t)) - - f(t, t) - t2.extend(t2) - - self.assertEqual(t, t2) - - def test_list_append(self): - T = ListOf(int) - - @Compiled - def f(x: T): - i = 0 - ct = len(x) - while i < ct: - x.append(x[i]) - i = i + 1 - - aList = T([1, 2, 3, 4]) - - f(aList) - - self.assertEqual(aList, [1, 2, 3, 4, 1, 2, 3, 4]) - - def test_list_pop(self): - T = ListOf(int) - - @Compiled - def f(x: T): - i = 0 - while i < len(x): - x.pop(i) - i = i + 1 - - aList = T([1, 2, 3, 4]) - - f(aList) - - self.assertEqual(aList, [2, 4]) - - def test_list_of_oneOf(self): - T = ListOf(OneOf(None, float)) - - @Compiled - def f(): - x = T() - x.resize(2) - x[0] = 10.0 - x[1] = None - x.append(10.0) - x.append(None) - return x - - self.assertEqual(f(), [10.0, None, 10.0, None]) - - @flaky(max_runs=3, min_passes=1) - def test_lists_add_perf(self): - T = ListOf(int) - - @Compiled - def range(x: int): - out = T() - out.resize(x) - - i = 0 - while i < x: - out[i] = i - i = i + 1 - - return out - - @Compiled - def addSafe(x: T, y: T): - out = T() - - i = 0 - while i < len(x): - out.append(x[i] + y[i]) - i = i + 1 - - return out - - @Compiled - def addUnsafe(x: T, y: T): - out = T() - out.reserve(len(x)) - - dest_ptr = out.pointerUnsafe(0) - max_ptr = out.pointerUnsafe(len(x)) - x_ptr = x.pointerUnsafe(0) - y_ptr = y.pointerUnsafe(0) - - while dest_ptr < max_ptr: - dest_ptr.initialize(x_ptr.get() + y_ptr.get()) - dest_ptr += 1 - x_ptr += 1 - y_ptr += 1 - - out.setSizeUnsafe(len(x)) - - return out - - def timingComparison(addFun): - ct = 10000000 - x = range(ct) - y = range(ct) - - xnumpy = numpy.arange(ct) - ynumpy = numpy.arange(ct) - - t0 = time.time() - for _ in range(10): - y = addFun(x, y) - t1 = time.time() - for _ in range(10): - ynumpy = xnumpy+ynumpy - t2 = time.time() - - slowerThanNumpyRatio = (t1 - t0) / (t2 - t1) - - self.assertEqual(y[10], x[10] * 11) - - print("Performance of ", addFun, "vs numpy is", slowerThanNumpyRatio, "times slower") - - return slowerThanNumpyRatio - - # numpy sped up between 1.16 and 1.17 somehow. I suspect it's using a more native set of - # SIMD instructions that we're not persuading LLVM to emit. - self.assertLess(timingComparison(addSafe), 10) # 2.0 for me with numpy 1.16, but 4.0 with numpy 1.17? - self.assertLess(timingComparison(addUnsafe), 4.0) # 1.07 for me against numpy 1.16 but 4.0 against numpy 1.17 - - def test_list_duplicate_operation(self): - @Compiled - def dupList(x: ListOf(int)): - return ListOf(int)(x) - - x = ListOf(int)([1, 2, 3]) - y = dupList(x) - x[0] = 100 - self.assertEqual(y[0], 1) - - def test_list_short_circuit_if(self): - @Compiled - def chkList(x: ListOf(int)): - return len(x) > 0 and x[0] - - x = ListOf(int)([]) - self.assertFalse(chkList(x)) - - def test_not_list(self): - @Compiled - def chkListInt(x: ListOf(int)): - return not x - - x = ListOf(int)([]) - self.assertTrue(chkListInt(x)) - x.append(0) - self.assertFalse(chkListInt(x)) - - @Compiled - def chkListListInt(x: ListOf(ListOf(int))): - return not x - - x = ListOf(ListOf(int))() - self.assertTrue(chkListListInt(x)) - x.append(ListOf(int)()) - self.assertFalse(chkListListInt(x)) - - def test_convert_tuple_of_to_list(self): - @Entrypoint - def convertTo(x, T): - return T(x) - - self.assertEqual( - convertTo(TupleOf(int)([1, 2, 3]), ListOf(int)), - [1, 2, 3] - ) - - self.assertEqual( - convertTo(TupleOf(float)([1.5, 2.5, 3.5]), ListOf(int)), - [1, 2, 3] - ) - - self.assertEqual( - ListOf(int)(TupleOf(float)([1.5, 2.5, 3.5])), - [1, 2, 3] - ) - - self.assertEqual( - ListOf(OneOf(int, str))(TupleOf(float)([1.5, 2.5, 3.5])), - [1, 2, 3] - ) - - self.assertEqual( - convertTo(TupleOf(float)([1.5, 2.5, 3.5]), ListOf(OneOf(int, str))), - [1, 2, 3] - ) - - # in a loop, so we can see we're not violating any refcounts - for _ in range(100): - with self.assertRaisesRegex( - TypeError, - "Cannot construct a new float from an instance of str" - ): - convertTo(TupleOf(float)([1.5, 2.5, "3.5"]), ListOf(OneOf(int, str))) - - def test_pop_behind_if(self): - @Entrypoint - def f(aList): - if aList[-1] < 0: - aList.pop() - - return aList - - self.assertEqual(f(ListOf(int)((0,))), [0]) - self.assertEqual(f(ListOf(int)((-1,))), []) - - def test_list_slice(self): - def slice(aList: ListOf(int), a, b, c): - return aList[a:b:c] - - sliceCompiled = Entrypoint(slice) - - self.assertEqual(sliceCompiled([], None, None, 1), []) - - for l in [ - ListOf(int)([]), - ListOf(int)([1]), - ListOf(int)([1, 2]), - ListOf(int)([1, 2, 3]), - ListOf(int)([1, 2, 3, 4]) - ]: - for a in [None] + list(range(-5, 5)): - for b in [None] + list(range(-5, 5)): - for c in [None] + list(range(-5, 5)): - if c != 0: - l0 = list(list(l)[a:b:c]) - l1 = slice(l, a, b, c) - l2 = sliceCompiled(l, a, b, c) - - self.assertTrue(len(l1) >= 0, len(l1)) - self.assertTrue(len(l2) >= 0, len(l2)) - - self.assertEqual(l0, l1, (l, a, b, c)) - self.assertEqual(l0, l2, (l, a, b, c)) - - def test_list_pop_refcounts(self): - lst = ListOf(ListOf(int))() - aTup = ListOf(int)() - - for i in range(100): - lst.append(aTup) - - @Entrypoint - def popTen(lst): - for _ in range(10): - lst.pop() - - rc1 = _types.refcount(aTup) - popTen(lst) - rc2 = _types.refcount(aTup) - - self.assertEqual(rc2, rc1 - 10) - - def test_list_resize_recompile(self): - lst = ListOf(int)() - - @Entrypoint - def r1(lst): - lst.resize(10) - - @Entrypoint - def r2(lst): - lst.resize(10, 10) - - r1(lst) - r2(lst) - - def test_listof_aliasing(self): - T = ListOf(int) - - t1 = T() - t2 = T(t1) - - t1.append(1) - - assert len(t2) == 0 - - def test_listof_aliasing_compiled(self): - T = ListOf(int) - - @Entrypoint - def dup(x): - return T(x) - - t1 = T() - t2 = dup(t1) - - t1.append(1) - - assert len(t2) == 0 - - def test_list_add_coersion(self): - aLst = ListOf(UInt16)() - aLst.resize(20) - - @Entrypoint - def addTwo(l): - l[10] += 2 - - addTwo(aLst) - assert aLst[10] == 2 - - aLst[10] = UInt8(2) - assert aLst[10] == 2 - - aLst[10] = UInt16(2) - assert aLst[10] == 2 - - aLst[10] += 2 - assert aLst[10] == 4 - - def test_list_index_with_uints(self): - aLst = ListOf(UInt16)() - aLst.resize(20) - - @Entrypoint - def addTwo(l): - l[UInt8(10)] += 2 - - addTwo(aLst) - assert aLst[UInt8(10)] == 2 - - aLst[UInt8(10)] = UInt8(2) - assert aLst[UInt8(10)] == 2 - - aLst[UInt8(10)] = UInt16(2) - assert aLst[UInt8(10)] == 2 - - aLst[UInt8(10)] += 2 - assert aLst[UInt8(10)] == 4 - - def test_list_index_with_floats_fails(self): - aLst = ListOf(UInt16)() - aLst.resize(20) - - @Entrypoint - def addTwo(l): - l[10.5] += 2 - - @Entrypoint - def lookup(l): - return l[10.5] - - @Entrypoint - def assign(l): - l[10.5] = 0 - - with self.assertRaisesRegex(TypeError, "Can't take.*integer index"): - addTwo(aLst) - - with self.assertRaisesRegex(TypeError, "Can't take.*integer index"): - lookup(aLst) - - with self.assertRaisesRegex(TypeError, "Can't take.*integer index"): - assign(aLst) - - with self.assertRaises(TypeError): - aLst[1.2] - - with self.assertRaises(TypeError): - aLst[1.2] = 1 - - with self.assertRaises(TypeError): - aLst[1.2] += 1 - - def test_list_index_with_class_with_index(self): - aLst = ListOf(UInt16)() - aLst.resize(20) - - class AnIndex(Class, Final): - ix = Member(int) - - def __index__(self): - return self.ix - - anIndex = AnIndex(ix=10) - - @Entrypoint - def addTwo(l): - l[anIndex] += 2 - - addTwo(aLst) - assert aLst[anIndex] == 2 - - @Entrypoint - def addTwoObjectstyle(l, index: object): - l[index] += 2 - - addTwoObjectstyle(aLst, anIndex) - assert aLst[anIndex] == 4 - - aLst[anIndex] = UInt8(2) - assert aLst[anIndex] == 2 - - aLst[anIndex] = UInt16(2) - assert aLst[anIndex] == 2 - - aLst[anIndex] += 2 - assert aLst[anIndex] == 4 - - def test_list_index_with_class_with_bad_index(self): - aLst = ListOf(UInt32)() - aLst.resize(20) - - class AnIndex(Class, Final): - ix = Member(int) - - def __index__(self): - return "invalid index" - - anIndex = AnIndex(ix=10) - - @Entrypoint - def getIndex(l, index): - return l[index] - - with self.assertRaisesRegex(TypeError, "returned non-int"): - getIndex(aLst, anIndex) - - with self.assertRaisesRegex(TypeError, "returned non-int"): - aLst[anIndex] - - @Entrypoint - def getIndexAsObject(l, index: object): - return l[index] - - with self.assertRaisesRegex(TypeError, "returned non-int"): - getIndexAsObject(aLst, anIndex) - - class AUintIndex(Class, Final): - ix = Member(int) - - def __index__(self): - return UInt8(10) - - with self.assertRaisesRegex(TypeError, "returned non-int"): - assert getIndexAsObject(aLst, AUintIndex()) == aLst[10] - - with self.assertRaisesRegex(TypeError, "returned non-int"): - assert getIndex(aLst, AUintIndex()) == aLst[10] - - with self.assertRaisesRegex(TypeError, "returned non-int"): - assert aLst[AUintIndex()] == aLst[10] - - def test_list_to_and_from_bytes(self): - aList = ListOf(int)([1, 2, 3]) - - assert len(aList.toBytes()) == 24 - assert ListOf(int).fromBytes(aList.toBytes()) == aList - - with self.assertRaisesRegex(TypeError, "POD"): - ListOf(str)(["hi"]).toBytes() - - with self.assertRaisesRegex(TypeError, "POD"): - ListOf(str).fromBytes(b"") - - @Entrypoint - def toBytes(l): - return l.toBytes() - - @Entrypoint - def fromBytes(T, b): - return T.fromBytes(b) - - assert aList.toBytes() == toBytes(aList) - assert fromBytes(ListOf(int), aList.toBytes()) == aList - - assert fromBytes(ListOf(UInt8), aList.toBytes()) == ListOf(UInt8).fromBytes(aList.toBytes()) - - def test_assign_list_conversion(self): - L = ListOf(ListOf(int)) - - aList = L() - - # this casts the list - aList.append([1, 2]) - - # this also casts the list - aList[0] = [1, 2, 3] - - @Entrypoint - def appendIt(l, x): - l.append(x) - - @Entrypoint - def assignIt(l, x): - l[0] = x - - appendIt(aList, [1, 2]) - assignIt(aList, [1, 2, 3]) - - with self.assertRaises(TypeError): - appendIt(aList, ["hi"]) - - with self.assertRaises(TypeError): - assignIt(aList, ["hi"]) - - with self.assertRaises(TypeError): - aList.append("hi") - - with self.assertRaises(TypeError): - aList[0] = "hi" - - def test_add_untyped_tuple(self): - @Entrypoint - def addIt(aTup: ListOf(int), x: int): - return aTup + (x,) - - @Entrypoint - def addItLst(aTup: ListOf(int), x: int): - return aTup + [x] - - assert addIt((1, 2), 3) == [1, 2, 3] - assert addItLst((1, 2), 3) == [1, 2, 3] - - def test_implicitly_convert_list_of_int_to_tuple(self): - @Entrypoint - def sumIt(aTup: TupleOf(int)): - res = 0 - for a in aTup: - res += a - return res - - @Entrypoint - def sumThem(aLst: ListOf(ListOf(int))): - res = 0 - for l in aLst: - res += sumIt(l) - return res - - assert sumThem([[1], [2], [3, 4, 5]]) == 15 diff --git a/typed_python/compiler/tests/masquerade_test.py b/typed_python/compiler/tests/masquerade_test.py index 6e9a56e94..febc953fd 100644 --- a/typed_python/compiler/tests/masquerade_test.py +++ b/typed_python/compiler/tests/masquerade_test.py @@ -33,6 +33,7 @@ class TestMasqueradeTypes(unittest.TestCase): not directly modifying the kwargs you're passed in compiled code, and we don't allow list and dict masquerades to escape a given statement. """ + @pytest.mark.group_one def test_compile_star_arg_of_masquerade(self): @Entrypoint def f(**x): @@ -44,6 +45,7 @@ def g(x: int): assert g(3) == (3, 3) + @pytest.mark.group_one def test_star_args_of_masquerade(self): def f(*args): return args[1] @@ -54,6 +56,7 @@ def callF(): self.assertEqual(callF.resultTypeFor().interpreterTypeRepresentation, list) + @pytest.mark.group_one def test_iterate_kwargs(self): def f(**kwargs): res = 0 @@ -69,6 +72,7 @@ def sumSomeThings(): assert sumSomeThings() == 6 + @pytest.mark.group_one def test_promote_masquerade_tuple_to_typed_tuple(self): @Entrypoint def f(x: TupleOf(int)): @@ -80,6 +84,7 @@ def callF(): assert callF() == 3 + @pytest.mark.group_one def test_promote_masquerade_list_to_typed_list(self): @Entrypoint def f(x: ListOf(int)): diff --git a/typed_python/compiler/tests/math_functions_compilation_test.py b/typed_python/compiler/tests/math_functions_compilation_test.py index d41e53a67..a86c660c9 100644 --- a/typed_python/compiler/tests/math_functions_compilation_test.py +++ b/typed_python/compiler/tests/math_functions_compilation_test.py @@ -50,6 +50,7 @@ def compiledHash(x): class TestMathFunctionsCompilation(unittest.TestCase): + @pytest.mark.group_one def test_entrypoint_overrides(self): @Entrypoint def f(x): @@ -62,6 +63,7 @@ def f(x): print(r2) print(r3) + @pytest.mark.group_one def test_math_functions(self): for funToTest in [ lambda x: math.isinf(x), @@ -83,6 +85,7 @@ def test_math_functions(self): self.assertEqual(compiled(val), funToTest(val), val) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_math_functions_perf(self): def checkMany(x: float, i: int): count = 0 @@ -117,6 +120,7 @@ def checkMany(x: float, i: int): # I get about .9x, so we're a little slower than numpy but not much print("speedup vs numpy is", speedupVsNumpy) + @pytest.mark.group_one def test_math_transcendental_fns(self): def f_acos(x): return math.acos(x) @@ -262,6 +266,7 @@ def f_atan2(x, y): else: self.assertEqual(r1, r2, (mathFun, v1, v2)) + @pytest.mark.group_one def test_math_other_one(self): def f_fabs(x): return math.fabs(x) @@ -341,6 +346,7 @@ def f_factorial(x): self.assertIsInstance(r2, float) self.assertTrue(abs(r1 - r2) / r1 < 1e-15, (mathFun, v)) + @pytest.mark.group_one def test_math_frexp_modf(self): def f_frexp(x): return math.frexp(x) @@ -367,6 +373,7 @@ def f_modf(x): for i in range(2): self.assertLess(abs((r1[i] - r3[i])/r1[i]) if r1[i] else abs(r1[i] - r3[i]), 1e-6) + @pytest.mark.group_one def test_math_other_two(self): def f_hypot(x, y): return math.hypot(x, y) @@ -487,6 +494,7 @@ def f_ldexp(x, y): r4 = compiled(Float32(v1), v2) self.assertEqual(r3, r4, (mathFun, v1, v2)) + @pytest.mark.group_one def test_math_fsum(self): def f_fsum(iterable): return math.fsum(iterable) @@ -512,6 +520,7 @@ def f_fsum(iterable): with self.assertRaises(TypeError): compiled(1234) # not iterable + @pytest.mark.group_one def test_math_constants(self): def all_constants(x): return (type(x), math.pi, math.e, math.tau, math.inf, math.nan) @@ -544,6 +553,7 @@ def f_runtime_error(): c_runtime_error() @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_math_functions_perf_other(self): count = 1000000 element = lambda i: -5.0 + i / (count / 10.0) @@ -606,6 +616,7 @@ def many_hypot(n: int): print(f"{f.__name__} speedup vs numpy is", speedupVsNumpy) + @pytest.mark.group_one def test_math_float_overload_order(self): @Entrypoint def f(x): @@ -626,6 +637,7 @@ def g(x): self.assertEqual(r1, r4) self.assertEqual(r2, r3) + @pytest.mark.group_one def test_math_int_overload_order(self): for T1 in [UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, int]: for T2 in [UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, int]: @@ -654,6 +666,7 @@ def g(x): del f del g + @pytest.mark.group_one def test_math_functions_on_object(self): class ClassCeil: def __ceil__(self): @@ -853,6 +866,7 @@ def f_tanh(t: object): else: self.assertEqual(r1, r2, (f, v)) + @pytest.mark.group_one def test_math_functions_on_oneof(self): class ClassIndex: def __index__(self): @@ -904,6 +918,7 @@ def f_gcd(x: T3, y: T3) -> int: else: self.assertEqual(r1[1], r2[1], v) + @pytest.mark.group_one def test_math_internal_fns(self): self.assertEqual(sumIterable([1, 2, 3]), 6) self.assertEqual(sumIterable([1e100, 1e-100, -1e100]), 1e-100) diff --git a/typed_python/compiler/tests/multithreading_test.py b/typed_python/compiler/tests/multithreading_test.py index 47b8c26d8..8a08f09b5 100644 --- a/typed_python/compiler/tests/multithreading_test.py +++ b/typed_python/compiler/tests/multithreading_test.py @@ -49,6 +49,7 @@ class AClass(Class): class TestMultithreading(unittest.TestCase): @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_gil_is_released(self): @Compiled def f(x: int): @@ -81,6 +82,7 @@ def f(x: int): else: self.assertTrue(ratio >= .9 and ratio < 1.1, ratio) + @pytest.mark.group_one def test_refcounts_of_objects_across_boundary(self): class Object: pass @@ -113,6 +115,7 @@ def rapidlyIncAndDecref(x: typeOfInstance): self.assertEqual(_types.refcount(instance), 1) + @pytest.mark.group_one def test_serialize_is_parallel(self): if os.environ.get('TRAVIS_CI', None): return @@ -146,6 +149,7 @@ def f(): # expect the ratio to be close to 1, but have some error margin self.assertTrue(ratio >= .8 and ratio < 1.2, ratios) + @pytest.mark.group_one def test_can_access_locks_in_compiler_with_locks_as_obj(self): lock = threading.Lock() recursiveLock = threading.RLock() @@ -161,6 +165,7 @@ def lockFun(l: object): self.assertFalse(lock.locked()) + @pytest.mark.group_one def test_can_access_locks_in_compiler_with_typed_locks(self): lock = threading.Lock() recursiveLock = threading.RLock() @@ -183,6 +188,7 @@ def recursiveLockFun(l: threading.RLock): self.assertFalse(lock.locked()) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_lock_perf(self): lock = threading.Lock() recursiveLock = threading.RLock() @@ -213,6 +219,7 @@ def recursiveLockFun(l: threading.RLock, aList: ListOf(int), count: int): self.assertLess(t1 - t0, .1) self.assertLess(t2 - t1, .1) + @pytest.mark.group_one def test_lock_works(self): lock = threading.Lock() @@ -238,6 +245,7 @@ def loopWithLock(l, aList, count): self.assertEqual(ct * 4, aList[0]) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_lock_with_separate_locks_perf(self): @Entrypoint def loopWithLock(l, aList, count): diff --git a/typed_python/compiler/tests/named_tuple_subclass_compilation_test.py b/typed_python/compiler/tests/named_tuple_subclass_compilation_test.py index 03cc349d7..d843ea86a 100644 --- a/typed_python/compiler/tests/named_tuple_subclass_compilation_test.py +++ b/typed_python/compiler/tests/named_tuple_subclass_compilation_test.py @@ -9,6 +9,7 @@ def __add__(self, other): return T(x=self.x + other, y=self.y) +@pytest.mark.group_one def test_can_construct(): @Entrypoint def getOne(x): @@ -17,6 +18,7 @@ def getOne(x): assert getOne(10).x == 10 +@pytest.mark.group_one def test_can_hit_operators(): @Entrypoint def getOne(x): @@ -25,6 +27,7 @@ def getOne(x): assert getOne(10).x == 10 +@pytest.mark.group_one def test_subclass_of_named_tuple_compilation(): NT = NamedTuple(a=int, b=str) @@ -85,6 +88,7 @@ def getAProperty(x: X): @flaky(max_runs=3, min_passes=1) +@pytest.mark.group_one def test_subclass_of_named_tuple_compilation_perf(): NT = NamedTuple(a=float, b=str) @@ -111,6 +115,7 @@ def loop(self, x, times): assert time.time() - t0 < .01 +@pytest.mark.group_one def test_bound_method_on_named_tuple(): class NT(NamedTuple(x=str)): @Function diff --git a/typed_python/compiler/tests/numpy_interaction_test.py b/typed_python/compiler/tests/numpy_interaction_test.py index f15bfea9d..e59f8bf42 100644 --- a/typed_python/compiler/tests/numpy_interaction_test.py +++ b/typed_python/compiler/tests/numpy_interaction_test.py @@ -3,11 +3,13 @@ import numpy.linalg +@pytest.mark.group_one def test_convert_list_to_numpy_array(): aList = ListOf(int)(range(20)) assert isinstance(aList.toArray(), numpy.ndarray) +@pytest.mark.group_one def test_can_add_numpy_arrays_in_compiled_code(): @Entrypoint def add(x): @@ -16,6 +18,7 @@ def add(x): assert isinstance(add(numpy.ones(10)), numpy.ndarray) +@pytest.mark.group_one def test_can_call_numpy_builtins_from_compiled_code(): @Entrypoint def callSin(x): @@ -30,6 +33,7 @@ def callF(f, x): assert isinstance(callF(numpy.sin, numpy.ones(10).cumsum()), numpy.ndarray) +@pytest.mark.group_one def test_can_call_numpy_matrix_funs(): @Entrypoint def callDiagonal(x): @@ -39,6 +43,7 @@ def callDiagonal(x): assert callDiagonal(10).tolist() == [1 for _ in range(10)] +@pytest.mark.group_one def test_listof_from_sliced_numpy_array(): x = numpy.array((0, 1, 2)) y = x[::2] diff --git a/typed_python/compiler/tests/one_of_compilation_test.py b/typed_python/compiler/tests/one_of_compilation_test.py index f4985f2fc..13e2030dd 100644 --- a/typed_python/compiler/tests/one_of_compilation_test.py +++ b/typed_python/compiler/tests/one_of_compilation_test.py @@ -73,6 +73,7 @@ def f(self, y): class TestOneOfCompilation(unittest.TestCase): + @pytest.mark.group_one def test_oneof_wrapper_fast_is_check(self): assert typeWrapper(OneOf(int, float))._simpleNoneCheckIndex() == -1 assert typeWrapper(OneOf(int, None))._simpleNoneCheckIndex() == 1 @@ -80,6 +81,7 @@ def test_oneof_wrapper_fast_is_check(self): assert typeWrapper(OneOf(None, int))._simpleNoneCheckIndex() == 0 assert typeWrapper(OneOf(None, object))._simpleNoneCheckIndex() is None + @pytest.mark.group_one def test_one_of_basic(self): @Compiled def f(x: OneOf(int, float)) -> OneOf(int, float): @@ -88,6 +90,7 @@ def f(x: OneOf(int, float)) -> OneOf(int, float): self.assertEqual(f(10), 10) self.assertEqual(f(10.2), 10.2) + @pytest.mark.group_one def test_one_of_with_refcounts(self): @Compiled def f(x: OneOf(None, TupleOf(int))) -> OneOf(None, TupleOf(int)): @@ -101,6 +104,7 @@ def f(x: OneOf(None, TupleOf(int))) -> OneOf(None, TupleOf(int)): self.assertEqual(_types.refcount(aTup), 1) + @pytest.mark.group_one def test_one_of_binop_stays_dual(self): @Compiled def f(x: OneOf(int, float), y: int) -> OneOf(int, float): @@ -115,6 +119,7 @@ def check(x, y): for b in [0, 1, 2]: check(a, b) + @pytest.mark.group_one def test_one_of_binop_converges(self): @Compiled def f(x: OneOf(int, float), y: float) -> float: @@ -129,6 +134,7 @@ def check(x, y): for b in [0.0, 1.0, 2.0]: check(a, b) + @pytest.mark.group_one def test_one_of_binop_rhs(self): @Compiled def f(x: int, y: OneOf(int, float)) -> OneOf(int, float): @@ -144,6 +150,7 @@ def check(x, y): for b in things: check(a, b) + @pytest.mark.group_one def test_one_of_dual_binop(self): @Compiled def f(x: OneOf(int, float), y: OneOf(int, float)) -> OneOf(int, float): @@ -172,6 +179,7 @@ def check(x, y): for b in things: check(a, b) + @pytest.mark.group_one def test_one_of_downcast_to_primitive(self): @Compiled def f(x: OneOf(int, float)) -> int: @@ -180,6 +188,7 @@ def f(x: OneOf(int, float)) -> int: self.assertEqual(f(10), 10) self.assertEqual(f(10.5), 10) + @pytest.mark.group_one def test_one_of_downcast_to_oneof(self): @Compiled def f(x: OneOf(int, float, None)) -> OneOf(int, None): @@ -189,6 +198,7 @@ def f(x: OneOf(int, float, None)) -> OneOf(int, None): self.assertIs(f(None), None) self.assertEqual(f(10.5), 10) + @pytest.mark.group_one def test_one_of_upcast(self): @Compiled def f(x: OneOf(int, None)) -> OneOf(int, float, None): @@ -197,6 +207,7 @@ def f(x: OneOf(int, None)) -> OneOf(int, float, None): self.assertEqual(f(10), 10) self.assertIs(f(None), None) + @pytest.mark.group_one def test_one_of_returning(self): @Compiled def f(x: OneOf(None, int, float)) -> OneOf(None, int, float): @@ -207,6 +218,7 @@ def f(x: OneOf(None, int, float)) -> OneOf(None, int, float): self.assertEqual(f(10.5), 10.5) self.assertIs(f(None), None) + @pytest.mark.group_one def test_value_equal(self): @Compiled def f(x: Value, y: Value) -> bool: @@ -216,6 +228,7 @@ def f(x: Value, y: Value) -> bool: for val2 in someValues: self.assertEqual(val1 == val2, f(val1, val2), (val1, val2)) + @pytest.mark.group_one def test_value_types(self): @Compiled def f(x: ValueType(1), y: ValueType(2)): @@ -223,6 +236,7 @@ def f(x: ValueType(1), y: ValueType(2)): self.assertEqual(f(1, 2), 3) + @pytest.mark.group_one def test_convert_bool_to_value(self): @Compiled def f(x: bool) -> Value: @@ -231,6 +245,7 @@ def f(x: bool) -> Value: self.assertEqual(f(False), False) self.assertEqual(f(True), True) + @pytest.mark.group_one def test_value_get_method(self): @Compiled def getHi(x: Value) -> Value: @@ -239,6 +254,7 @@ def getHi(x: Value) -> Value: self.assertEqual(getHi({}), None) self.assertEqual(getHi({'hi': 20}), 20) + @pytest.mark.group_one def test_convert_ordering(self): # we should always pick the int if we can @Compiled @@ -272,6 +288,7 @@ def f4(x: float) -> OneOf(str, int): # require an explicit cast. self.assertEqual(f4(1.5), 1) + @pytest.mark.group_one def test_oneof_method_dispatch(self): @Compiled def f(c: OneOf(ClassA, ClassB), y: OneOf(int, float)): @@ -285,6 +302,7 @@ def f(c: OneOf(ClassA, ClassB), y: OneOf(int, float)): self.assertEqual(f(aB, 0.5), aB.f(0.5)) self.assertEqual(f(aB, 1), aB.f(1)) + @pytest.mark.group_one def test_oneof_attribute_dispatch(self): @Compiled def f(c: OneOf(ClassA, ClassB)): @@ -296,6 +314,7 @@ def f(c: OneOf(ClassA, ClassB)): self.assertEqual(f(anA), anA.x) self.assertEqual(f(aB), aB.x) + @pytest.mark.group_one def test_oneof_getitem(self): @Compiled def f(c: OneOf(TupleOf(int), ListOf(float))): @@ -304,6 +323,7 @@ def f(c: OneOf(TupleOf(int), ListOf(float))): self.assertEqual(f(TupleOf(int)((1,))), 1) self.assertEqual(f(ListOf(float)((1.5,))), 1.5) + @pytest.mark.group_one def test_oneof_to_bool(self): @Compiled def f(c: OneOf(int, float)): @@ -316,6 +336,7 @@ def f(c: OneOf(int, float)): self.assertEqual(f(0), "no") self.assertEqual(f(0.0), "no") + @pytest.mark.group_one def test_oneof_round(self): def f(c: OneOf(int, float)): return round(c) @@ -325,6 +346,7 @@ def f(c: OneOf(int, float)): for thing in [0, 0.0, 1, 1.5]: self.assertEqual(f(thing), fComp(thing)) + @pytest.mark.group_one def test_len_of_none_or_listof(self): @Entrypoint def iterate(x: OneOf(None, ListOf(int))): @@ -335,6 +357,7 @@ def iterate(x: OneOf(None, ListOf(int))): self.assertEqual(iterate(ListOf(int)([1, 2, 3])), [1, 2, 3]) + @pytest.mark.group_one def test_oneof_call(self): @Compiled def f(i: int): @@ -348,6 +371,7 @@ def f(i: int): self.assertEqual(f(1), "1") self.assertEqual(f(2), 2.0) + @pytest.mark.group_one def test_named_tuple_with_oneof(self): @Entrypoint def makeNT(x: NamedTuple(x=OneOf("A", "B"))): # noqa @@ -355,6 +379,7 @@ def makeNT(x: NamedTuple(x=OneOf("A", "B"))): # noqa self.assertEqual(makeNT(NamedTuple(x=OneOf("A", "B"))(x="A")).x, "A") + @pytest.mark.group_one def test_oneof_in_return_types(self): class A(Class, Final): @staticmethod @@ -369,6 +394,7 @@ def do(): do() + @pytest.mark.group_one def test_make_oneof(self): @Entrypoint def f(x): @@ -382,6 +408,7 @@ def f(x): with self.assertRaises(TypeError): f(10) + @pytest.mark.group_one def test_oneof_promotion(self): @Entrypoint def f(x: OneOf("A", "B")) -> str: # noqa @@ -390,6 +417,7 @@ def f(x: OneOf("A", "B")) -> str: # noqa assert f("A") == "A" assert f("B") == "B" + @pytest.mark.group_one def test_oneof_promotion_heterogeneous(self): @Entrypoint def f(x: OneOf("A", 10)) -> OneOf(str, int): # noqa @@ -398,6 +426,7 @@ def f(x: OneOf("A", 10)) -> OneOf(str, int): # noqa assert f("A") == "A" assert f(10) == 10 + @pytest.mark.group_one def test_operations_on_oneof_values(self): @Entrypoint def oneof_concat(x: OneOf('A', 'B')): # noqa @@ -438,6 +467,7 @@ def oneof_not(x: OneOf(0, 1)): self.assertEqual(oneof_not(0), True) self.assertEqual(oneof_not(1), False) + @pytest.mark.group_one def test_oneof_setitem(self): @Entrypoint def setItem(x: OneOf(None, ListOf(int)), i, y): @@ -460,6 +490,7 @@ def getSlice(x: OneOf(None, ListOf(int)), i, j): assert getSlice(aList, 0, 0) == ListOf(int)() assert getSlice(aList, 0, 1) == aList + @pytest.mark.group_one def test_oneof_resize_works_with_fcall(self): from typed_python import UInt16 @@ -484,6 +515,7 @@ def resizeOneof(sz): assert len(resizeOneof(10)) == 10 + @pytest.mark.group_one def test_oneof_resize_works_with_inline_call(self): @Entrypoint def resizeOneof(sz): @@ -503,6 +535,7 @@ def resizeOneof(sz): assert len(resizeOneof(10)) == 10 + @pytest.mark.group_one def test_assign_to_oneof_preserves_ref(self): @Entrypoint def preservesReference(): @@ -517,6 +550,7 @@ def preservesReference(): assert len(x[5]) == 10 + @pytest.mark.group_one def test_returning_oneof_preserves_reference(self): @Entrypoint def returnAsNotNone(x: OneOf(None, ListOf(UInt16))) -> ListOf(UInt16): @@ -538,6 +572,7 @@ def preservesReference(): assert len(x[5]) == 10 assert len(y) == 10 + @pytest.mark.group_one def test_explicitly_converting_to_oneof_works(self): @Entrypoint def check(): @@ -559,6 +594,7 @@ def check(): check() + @pytest.mark.group_one def test_oneof_binary_ops_dont_duplicate(self): class AddMakesTuple: def __init__(self, x): @@ -586,6 +622,7 @@ def check(a1, a2): lst.append(10) assert aL[1] == lst + @pytest.mark.group_one def test_compile_str_on_oneof(self): @Entrypoint def callStr(x: OneOf(ZeroDivisionError, str)): @@ -593,6 +630,7 @@ def callStr(x: OneOf(ZeroDivisionError, str)): assert callStr(ZeroDivisionError()) == str(ZeroDivisionError()) + @pytest.mark.group_one def test_convert_oneof_or_none_to_index(self): @Entrypoint def index(l: ListOf(int), y: OneOf(None, int)): @@ -603,6 +641,7 @@ def index(l: ListOf(int), y: OneOf(None, int)): with self.assertRaisesRegex(TypeError, "Can't take instance of type 'NoneType'"): assert index([1, 2, 3], None) == 3 + @pytest.mark.group_one def test_check_if_oneof_is_none(self): @Entrypoint def strTranslate(x: str, table): @@ -622,6 +661,7 @@ def strTranslate(x: str, table): strTranslate("hi", {}) + @pytest.mark.group_one def test_oneof_method_call(self): @Entrypoint def append(x: OneOf(ListOf(int), ListOf(float))): @@ -631,6 +671,7 @@ def append(x: OneOf(ListOf(int), ListOf(float))): append(l) assert len(l) == 4 + @pytest.mark.group_one def test_split_on_oneof_type(self): @Entrypoint def split(x: Value): @@ -638,6 +679,7 @@ def split(x: Value): assert issubclass(split("HI"), OneOf) + @pytest.mark.group_one def test_string_split_on_oneof_with_constant(self): @Entrypoint def split(x: Value): @@ -648,6 +690,7 @@ def split(x: Value): with self.assertRaisesRegex(TypeError, "Can.t call bytes.split"): split(b"AHIB") + @pytest.mark.group_one def test_string_split_on_oneof_retains_type(self): @Entrypoint def split(x: Value): @@ -657,6 +700,7 @@ def split(x: Value): assert split("AHIB") == ListOf(str) + @pytest.mark.group_one def test_len_of_oneof(self): @Entrypoint def lenOf(x: Value): @@ -664,6 +708,7 @@ def lenOf(x: Value): assert lenOf("AHIB") == 4 + @pytest.mark.group_one def test_string_split_on_oneof_retains_type_2(self): @Entrypoint def split(x: Value, y: Value): @@ -674,6 +719,7 @@ def split(x: Value, y: Value): assert split("AHIB", "HI") == list assert split(b"AHIB", b"HI") == list + @pytest.mark.group_one def test_isinstance_convert_overlapping(self): @Entrypoint def checkIt(x: OneOf(1, 2, 3, int)): @@ -686,6 +732,7 @@ def checkIt(x: OneOf(1, 2, 3, int)): assert checkIt(2) == 2 + @pytest.mark.group_one def test_call_function_with_none_and_ifcheck(self): @Entrypoint def checkIt(x, y: object): @@ -694,6 +741,7 @@ def checkIt(x, y: object): checkIt(None, float) + @pytest.mark.group_one def test_call_type_on_oneof(self): @Entrypoint def checkIt(x: OneOf(int, float)): @@ -705,6 +753,7 @@ def checkIt(x: OneOf(int, float)): assert checkIt(1.0) == "float" @pytest.mark.skipif("sys.version_info.minor < 8") + @pytest.mark.group_one def test_direct_assign_works_with_oneof(self): @Entrypoint def checkIt(x: OneOf(None, Tuple(str, str))): @@ -717,3 +766,18 @@ def checkIt(x: OneOf(None, Tuple(str, str))): assert checkIt(('a', 'b')) == 'ab' assert checkIt(None) == 'empty' + + def test_convert_one_of_constants_to_string(self): + @Entrypoint + def toString(x: OneOf("hi", "bye")): # noqa + return f"its: {x}" + + toString('hi') + + def test_unpack_oneof_none_or_tuple(self): + @Entrypoint + def unpackIt(x: OneOf(None, Tuple(int, int))): + a, b = x + return a + b + + unpackIt((1, 2)) diff --git a/typed_python/compiler/tests/operator_is_compilation_test.py b/typed_python/compiler/tests/operator_is_compilation_test.py index 2ca50768e..35a2055c6 100644 --- a/typed_python/compiler/tests/operator_is_compilation_test.py +++ b/typed_python/compiler/tests/operator_is_compilation_test.py @@ -18,6 +18,7 @@ class TestOperatorIsCompilation(unittest.TestCase): + @pytest.mark.group_one def test_none_is_none(self): @Entrypoint def f(x): @@ -26,6 +27,7 @@ def f(x): self.assertTrue(f(None)) self.assertFalse(f(1)) + @pytest.mark.group_one def test_one_is_not_one(self): @Entrypoint def f(x): @@ -34,6 +36,7 @@ def f(x): self.assertFalse(f(None)) self.assertFalse(f(1)) + @pytest.mark.group_one def test_true_is_not_false(self): @Entrypoint def testIs(x, y): @@ -67,6 +70,7 @@ def testIsNot(x, y): self.assertFalse(testIs(False, True)) self.assertTrue(testIsNot(False, True)) + @pytest.mark.group_one def test_types_are_themselves(self): trueLambdas = [ lambda: type is type, @@ -88,6 +92,7 @@ def test_types_are_themselves(self): for fl in falseLambda: self.assertFalse(Entrypoint(fl)()) + @pytest.mark.group_one def test_oneof_and_is(self): @Entrypoint def testIs(x: OneOf(None, bool), y: OneOf(None, bool)): @@ -98,6 +103,7 @@ def testIs(x: OneOf(None, bool), y: OneOf(None, bool)): for v2 in vals: self.assertEqual(testIs(v1, v2), v1 is v2) + @pytest.mark.group_one def test_type_is(self): @Entrypoint def testSameType(x, y): diff --git a/typed_python/compiler/tests/pointer_to_compilation_test.py b/typed_python/compiler/tests/pointer_to_compilation_test.py index 8fb02c8c9..a8a1c3397 100644 --- a/typed_python/compiler/tests/pointer_to_compilation_test.py +++ b/typed_python/compiler/tests/pointer_to_compilation_test.py @@ -18,6 +18,7 @@ class TestPointerToCompilation(unittest.TestCase): + @pytest.mark.group_one def test_pointer_operations(self): T = ListOf(int) @@ -48,6 +49,7 @@ def testfun(x: T): self.assertEqual(l1[3], 21) self.assertEqual(l1[4], 0x3ff0000000000000) # hex representation of 64 bit float 1.0 + @pytest.mark.group_one def test_bytecount(self): def testfun(x): return _types.bytecount(type(x)) @@ -66,6 +68,7 @@ def check(x): check(ListOf(int)([10])) check(Tuple(int, int, int)((10, 10, 10))) + @pytest.mark.group_one def test_pointer_subtraction(self): T = ListOf(int) @@ -79,6 +82,7 @@ def testfun(x: T): self.assertEqual(testfun(T()), 1) self.assertEqual(compiledFun(T()), 1) + @pytest.mark.group_one def test_pointer_bool(self): T = ListOf(int) @@ -92,6 +96,7 @@ def testfun(x: T): self.assertEqual(testfun(T([1])), True) self.assertEqual(compiledFun(T([1])), True) + @pytest.mark.group_one def test_pointer_to_addition(self): aList = ListOf(int)() aList.resize(10) @@ -109,6 +114,7 @@ def iadd(x, y): self.assertEqual(iadd(p, 1), Entrypoint(iadd)(p, 1)) + @pytest.mark.group_one def test_pointer_setitem_works(self): def f(): x = ListOf(int)([1, 2, 3]) @@ -120,6 +126,7 @@ def f(): self.assertEqual(f(), 3) self.assertEqual(Entrypoint(f)(), 3) + @pytest.mark.group_one def test_initialize_with_unlike_type(self): def f(T, v): x = ListOf(T)() @@ -130,6 +137,7 @@ def f(T, v): self.assertEqual(f(int, 2.5), Entrypoint(f)(int, 2.5)) + @pytest.mark.group_one def test_initialize_with_class_without_default_init(self): def f(T, v): x = ListOf(T)() @@ -158,6 +166,7 @@ def __eq__(self, other): with self.assertRaisesRegex(Exception, "Cannot implicitly convert an object of type int to an instance of C"): f(C, 2) + @pytest.mark.group_one def test_pointer_destroy_in_interpreter(self): aList = ListOf(str)(["a", "b"]) @@ -173,6 +182,7 @@ def test_pointer_destroy_in_interpreter(self): assert aList[0] == "" + @pytest.mark.group_one def test_pointer_to_named_tuple(self): NT = NamedTuple(x=int, y=float) Lst = ListOf(NT) @@ -189,6 +199,7 @@ def ptrToX(p): assert lst.pointerUnsafe(0).x.get() == 10 assert ptrToX(lst.pointerUnsafe(0)).get() == 10 + @pytest.mark.group_one def test_type_of_element_of_pointer_to_set(self): P = PointerTo(Set(int)) diff --git a/typed_python/compiler/tests/python_object_of_type_compilation_test.py b/typed_python/compiler/tests/python_object_of_type_compilation_test.py index 09eefa149..cfe14fed6 100644 --- a/typed_python/compiler/tests/python_object_of_type_compilation_test.py +++ b/typed_python/compiler/tests/python_object_of_type_compilation_test.py @@ -50,9 +50,11 @@ def __bool__(self): class TestPythonObjectOfTypeCompilation(unittest.TestCase): + @pytest.mark.group_one def test_typeWrapper_for_object(self): self.assertIs(typedPythonTypeToTypeWrapper(object).typeRepresentation, object) + @pytest.mark.group_one def test_can_pass_object_in_and_out(self): @Compiled def f(x: object): @@ -61,6 +63,7 @@ def f(x: object): for thing in [0, 10, f, str]: self.assertIs(f(thing), thing) + @pytest.mark.group_one def test_can_assign(self): @Compiled def f(x: object): @@ -71,6 +74,7 @@ def f(x: object): for i in range(10000): self.assertIs(f(thing), thing) + @pytest.mark.group_one def test_member_access(self): @Compiled def f(x: object): @@ -81,6 +85,7 @@ def f(x: object): with self.assertRaises(Exception): f(10) + @pytest.mark.group_one def test_set_attribute(self): @Compiled def f_int(x: object, y: int): @@ -101,6 +106,7 @@ def f(x: object, y: object): with self.assertRaisesRegex(Exception, "'dict' object has no attribute 'a'"): f(dict(), "hi") + @pytest.mark.group_one def test_getitem(self): @Compiled def f(x: object): @@ -111,6 +117,7 @@ def f(x: object): with self.assertRaisesRegex(Exception, "string index out of range"): f("a") + @pytest.mark.group_one def test_delitem(self): @Compiled def f(x: object, item: object): @@ -124,6 +131,7 @@ def f(x: object, item: object): with self.assertRaisesRegex(KeyError, "1"): f(d, 1) + @pytest.mark.group_one def test_binary_ops(self): fcn = [] @@ -175,6 +183,7 @@ def mod(x: object, y: object): with self.assertRaises(Exception): compiled(2.5, "hi") + @pytest.mark.group_one def test_unary_ops(self): fcn = [] @@ -201,6 +210,7 @@ def objNot(x: object): self.assertEqual(compiled(0), f(0)) self.assertEqual(compiled(-1), f(-1)) + @pytest.mark.group_one def test_setitem(self): @Compiled def f(x: object, item: object, y: object): @@ -213,6 +223,7 @@ def f(x: object, item: object, y: object): with self.assertRaisesRegex(Exception, "unhashable type"): f({}, [], []) + @pytest.mark.group_one def test_call_with_args_and_kwargs(self): @Compiled def f(x: object, a: object, k: object): @@ -223,6 +234,7 @@ def aFunc(*args, **kwargs): self.assertEqual(f(aFunc, 'arg', 'the kwarg'), (('arg',), ({'keyword': 'the kwarg'}))) + @pytest.mark.group_one def test_len(self): @Compiled def f(x: object): @@ -230,6 +242,7 @@ def f(x: object): self.assertEqual(f([1, 2, 3]), 3) + @pytest.mark.group_one def test_convert_pyobj_to_oneof_with_string(self): @Function def toObject(x: object): @@ -241,6 +254,7 @@ def fro_and_to(x: object): self.assertEqual(fro_and_to("ab"), "ab") + @pytest.mark.group_one def test_object_conversions_2(self): T = ListOf(int) @@ -257,6 +271,7 @@ def to_and_fro(x: T) -> T: to_and_fro(t) self.assertEqual(refcount(t), 1) + @pytest.mark.group_one def test_object_conversions1(self): NT1 = NamedTuple(a=int, b=float, c=str, d=str) NT2 = NamedTuple(s=str, t=TupleOf(int)) @@ -331,6 +346,7 @@ def fro_and_to(x: object): self.assertTrue(finalMem < initMem + 2) + @pytest.mark.group_one def test_bool_cast_and_conv(self): IDict = Dict(int, int) @@ -459,6 +475,7 @@ def compiled_conv(x: T) -> bool: self.assertEqual(r1, r4) self.assertEqual(r1, r5) + @pytest.mark.group_one def test_obj_to_bool(self): def bool_f(x: object): @@ -550,6 +567,7 @@ class TPClassNoBoolOrLen(Class): self.assertEqual(r1, r3) self.assertEqual(r1, r4) + @pytest.mark.group_one def test_some_object_operations(self): @Compiled def f(x: object, y: object): @@ -565,6 +583,7 @@ def g(x: object, y: object): self.assertEqual(f(1, 2), 8) self.assertEqual(g("a", "b"), False) + @pytest.mark.group_one def test_create_lists(self): @Compiled def f(): @@ -573,6 +592,7 @@ def f(): res = f() self.assertEqual(res, [1, 2, 3, 4]) + @pytest.mark.group_one def test_create_tuples(self): @Compiled def f(): @@ -581,6 +601,7 @@ def f(): res = f() self.assertEqual(res, (1, 2, 3, 4)) + @pytest.mark.group_one def test_create_set(self): @Compiled def f(): @@ -589,6 +610,7 @@ def f(): res = f() self.assertEqual(res, {1, 2, 3, 4}) + @pytest.mark.group_one def test_create_dict(self): @Compiled def f(): @@ -597,6 +619,7 @@ def f(): res = f() self.assertEqual(res, {1: 2, "hi": "bye"}) + @pytest.mark.group_one def test_iterate_object(self): def toList(x: object): res = list() @@ -634,6 +657,7 @@ def generator(x): with self.assertRaisesRegex(Exception, "Boo!"): form(generator(10)) + @pytest.mark.group_one def test_bool_of_arbitrary(self): class C: def __bool__(self): @@ -649,6 +673,7 @@ def f(x: object): self.assertEqual(f([1]), True) self.assertEqual(f(C()), False) + @pytest.mark.group_one def test_int_of_arbitrary(self): class C: def __int__(self): @@ -661,6 +686,7 @@ def f(x: object): self.assertEqual(f(10), 10) self.assertEqual(f(C()), 123) + @pytest.mark.group_one def test_float_of_arbitrary(self): class C: def __float__(self): @@ -674,6 +700,7 @@ def f(x: object): self.assertEqual(f(10), 10.0) self.assertEqual(f(C()), 123.5) + @pytest.mark.group_one def test_str_of_arbitrary(self): class C: def __str__(self): @@ -687,6 +714,7 @@ def f(x: object): self.assertEqual(f([]), "[]") self.assertEqual(f(C()), "hihi") + @pytest.mark.group_one def test_bytes_of_arbitrary(self): class C: def __bytes__(self): @@ -700,6 +728,7 @@ def f(x: object): self.assertEqual(f(list(b"12")), b"12") self.assertEqual(f(C()), b"hihi") + @pytest.mark.group_one def test_exception_in_arbitrary_pyobj_conversion(self): class C: def __bool__(self): @@ -787,6 +816,7 @@ def callBytesTyped(x): with self.assertRaisesRegex(Exception, "bad float call"): callFloatTyped(C()) + @pytest.mark.group_one def test_invalid_return_value_in_arbitrary_pyobj_conversion(self): class C: def __bool__(self): @@ -839,6 +869,7 @@ def callBytes(x: object): with self.assertRaisesRegex(Exception, "__float__ returned non-float"): callFloat(C()) + @pytest.mark.group_one def test_check_is(self): @Entrypoint def g(x: object, y: object): @@ -851,6 +882,7 @@ def g(x: object, y: object): self.assertEqual(g([], aList), False) self.assertEqual(g(aList, aList), True) + @pytest.mark.group_one def test_instantiate_python_class(self): class C(): pass @@ -861,6 +893,7 @@ def makeAC(): self.assertTrue(isinstance(makeAC(), C)) + @pytest.mark.group_one def test_reverse_comparision_ops(self): @Entrypoint def ltOI(x: object, y: int): @@ -873,6 +906,7 @@ def ltIO(x: int, y: object): assert ltOI(1, 2) == ltIO(1, 2) assert ltOI(2, 1) == ltIO(2, 1) + @pytest.mark.group_one def test_call_type_object_from_interpreter(self): @Entrypoint def callIt(x: object): @@ -880,6 +914,7 @@ def callIt(x: object): assert callIt(Dict(int, int)) == Dict(int, int)() + @pytest.mark.group_one def test_gil_contention(self): @NotCompiled def f(x: int) -> int: @@ -909,6 +944,7 @@ def callInLoop(ct): t2.join() print(time.time() - t0, " to do 2mm in two threads") + @pytest.mark.group_one def test_slice_object(self): @Entrypoint def sliceIt(x: object) -> str: @@ -916,6 +952,7 @@ def sliceIt(x: object) -> str: assert sliceIt("hi") == "hi" + @pytest.mark.group_one def test_type_of_object_in_compiled_code_accurate(self): @Entrypoint def typeOf(x: object): @@ -924,6 +961,7 @@ def typeOf(x: object): assert typeOf(10) is int assert typeOf(object) is type + @pytest.mark.group_one def test_type_of_module_in_compiled_code_accurate(self): @Entrypoint def typeOf(): @@ -931,6 +969,7 @@ def typeOf(): assert typeOf() is type(threading) + @pytest.mark.group_one def test_type_of_global_fun_in_compiled_code_accurate(self): @Entrypoint def typeOf(): @@ -938,6 +977,7 @@ def typeOf(): assert typeOf() is type(globalFun) + @pytest.mark.group_one def test_type_of_print_in_compiled_code_accurate(self): @Entrypoint def typeOf(): @@ -945,6 +985,7 @@ def typeOf(): assert typeOf() is type(print) + @pytest.mark.group_one def test_isinstance_on_objects(self): @Entrypoint def isinstanceC(o: object, t: object): @@ -953,6 +994,7 @@ def isinstanceC(o: object, t: object): assert isinstanceC(10, int) assert not isinstanceC(10, str) + @pytest.mark.group_one def test_isinstance_on_objects_with_known_type(self): @Entrypoint def isinstanceC(o: object, t): @@ -961,6 +1003,7 @@ def isinstanceC(o: object, t): assert isinstanceC(10, int) assert not isinstanceC(10, str) + @pytest.mark.group_one def test_isinstance_on_objects_with_known_type_and_value(self): @Entrypoint def isinstanceC(o, t): @@ -969,6 +1012,7 @@ def isinstanceC(o, t): assert isinstanceC(10, int) assert not isinstanceC(10, str) + @pytest.mark.group_one def test_call_with_global_function(self): @Entrypoint def call(f: object): diff --git a/typed_python/compiler/tests/range_compilation_test.py b/typed_python/compiler/tests/range_compilation_test.py index 696d9def1..eac2af680 100644 --- a/typed_python/compiler/tests/range_compilation_test.py +++ b/typed_python/compiler/tests/range_compilation_test.py @@ -18,6 +18,7 @@ class TestRangeCompilation(unittest.TestCase): + @pytest.mark.group_one def test_construct_range(self): @Entrypoint def buildRange(x: int): @@ -25,6 +26,7 @@ def buildRange(x: int): assert buildRange(10) == 10 + @pytest.mark.group_one def test_sum_with_range(self): @Compiled def sumWithRange(x: int): @@ -36,6 +38,7 @@ def sumWithRange(x: int): for i in range(10): self.assertEqual(sumWithRange(i), sum(range(i+1))) + @pytest.mark.group_one def test_range_with_two_values(self): @Compiled def sumWithRangePair(x: int, y: int): @@ -48,6 +51,7 @@ def sumWithRangePair(x: int, y: int): for i2 in range(30): self.assertEqual(sumWithRangePair(i, i2), sum(range(i, i2))) + @pytest.mark.group_one def test_range_repeat(self): @Compiled def repeat(array: ListOf(int), times: int): @@ -74,6 +78,7 @@ def repeat(array: ListOf(int), times: int): self.assertEqual(repeat(aList, 2), aList + aList) self.assertEqual(repeat(aList, 3), aList + aList + aList) + @pytest.mark.group_one def test_range_type_str(self): def f(x): return str(type(x)) @@ -84,6 +89,7 @@ def f(x): r2 = Entrypoint(f)(x) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_range_with_step(self): def f(start, stop, step): res = ListOf(int)() @@ -115,6 +121,7 @@ def f(start, stop, step): ]: assert fCompiled(*args) == f(*args), args + @pytest.mark.group_one def test_range_perf(self): @Entrypoint def sumRangeAsInts(x): diff --git a/typed_python/compiler/tests/serialization_compilation_test.py b/typed_python/compiler/tests/serialization_compilation_test.py index 7075fd13d..6ca2a3af6 100644 --- a/typed_python/compiler/tests/serialization_compilation_test.py +++ b/typed_python/compiler/tests/serialization_compilation_test.py @@ -27,6 +27,7 @@ import time +@pytest.mark.group_one def test_can_serialize_under_entrypoint(): s = SerializationContext().withoutCompression() @@ -44,6 +45,7 @@ def check(inst, T): check(ListOf(str)(['hi']), ListOf(str)) +@pytest.mark.group_one def test_can_deserialize_under_entrypoint(): s = SerializationContext().withoutCompression() @@ -68,6 +70,7 @@ def check(inst, T): check(ListOf(str)(['hi']), ListOf(str)) +@pytest.mark.group_one def test_can_serialize_object_under_entrypoint(): s = SerializationContext() @@ -97,6 +100,7 @@ def timeInNThreads(f, args, threadCount): @pytest.mark.skipif('sys.platform=="darwin"') +@pytest.mark.group_one def test_serialization_perf(): s = SerializationContext().withoutCompression() @@ -142,6 +146,7 @@ def countBytes(aStr: str, times): assert compiledThreadScaling < 1.5 +@pytest.mark.group_one def test_can_serialize_with_or_without_out_context(): @Entrypoint def roundtripCompiled(T, x, sc): diff --git a/typed_python/compiler/tests/set_compilation_test.py b/typed_python/compiler/tests/set_compilation_test.py index 11b5e2dc0..42c454e42 100644 --- a/typed_python/compiler/tests/set_compilation_test.py +++ b/typed_python/compiler/tests/set_compilation_test.py @@ -49,6 +49,7 @@ def some_fibs(): class TestSetCompilation(unittest.TestCase): + @pytest.mark.group_one def test_can_copy_set(self): @Entrypoint def f(x: Set(int)): @@ -82,6 +83,7 @@ def reversedNative(x: ListOf(Set(int))): self.assertEqual(refcounts, refcounts2) + @pytest.mark.group_one def test_compile_iter_call_on_set(self): @Entrypoint def iterate(x: Set(int)): @@ -97,6 +99,7 @@ def iterate(x: Set(int)): assert set(iterate([1, 2, 3])) == set([1, 2, 3]) + @pytest.mark.group_one def test_compile_iterate_on_set(self): @Entrypoint def iterate(x: Set(int)): @@ -108,6 +111,7 @@ def iterate(x: Set(int)): assert set(iterate([1, 2, 3])) == set([1, 2, 3]) + @pytest.mark.group_one def test_set_length(self): @Entrypoint def set_len(x): @@ -127,6 +131,7 @@ def set_len(x): x.clear() self.assertEqual(set_len(x), 0) + @pytest.mark.group_one def test_set_in(self): @Entrypoint def set_in(x, y): @@ -152,6 +157,7 @@ def set_in(x, y): assert set_in(x1, 1) assert 1 in x1 + @pytest.mark.group_one def test_set_add(self): S = Set(int) @@ -212,6 +218,7 @@ def f(x: str): self.assertEqual(f("a"), {"initial", "value", "a", "aa"}) self.assertEqual(f("xyz" * 100), {"initial", "value", "xyz" * 100, "xyz" * 200}) + @pytest.mark.group_one def test_set_remove_discard(self): @Entrypoint def set_remove(s, k): @@ -269,6 +276,7 @@ def set_discard(s, k): set_discard(s, 'dd') self.assertEqual(s, set()) + @pytest.mark.group_one def test_set_clear(self): @Entrypoint def set_clear(s): @@ -288,6 +296,7 @@ def set_clear(s): set_clear(s2) self.assertEqual(len(s2), 0) + @pytest.mark.group_one def test_set_assign_and_copy(self): @Entrypoint @@ -309,6 +318,7 @@ def set_copy_and_modify_original(s, x, y): s = Set(str)(set("abc")) self.assertEqual(set_copy_and_modify_original(s, 'q', 'b'), set("abc")) + @pytest.mark.group_one def test_adding_to_sets(self): @Entrypoint @@ -328,6 +338,7 @@ def f(count): self.assertTrue(f(20000)) + @pytest.mark.group_one def test_set_destructors(self): @Entrypoint def f(): @@ -339,6 +350,7 @@ def f(): f() + @pytest.mark.group_one def test_set_pop(self): @Entrypoint def set_pop(s): @@ -374,6 +386,7 @@ def set_to_list(s: Set(int)) -> ListOf(int): self.assertEqual(original_set, new_set) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_set_perf(self): def set_copy_discard(s: Set(int), count: int): for i in range(2, count): @@ -401,6 +414,7 @@ def set_copy_discard(s: Set(int), count: int): print("Speedup was ", ratio) + @pytest.mark.group_one def test_set_binop(self): S = Set(int) sets = [] @@ -576,6 +590,7 @@ def symmetric_difference_update2(x: S, y: S, z: S): with self.assertRaises(TypeError): Compiled(symmetric_difference_update2)(S(x), S(y), S(z)) + @pytest.mark.group_one def test_set_iterable_comparisons(self): S = Set(int) @@ -628,6 +643,7 @@ def isdisjoint(x, y): with self.assertRaises(TypeError): Entrypoint(f)(s, v) + @pytest.mark.group_one def test_set_iterable_updates(self): S = Set(int) @@ -742,6 +758,7 @@ def is_disjoint(x, y): @flaky(max_runs=3, min_passes=1) @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_set_binop_perf(self): for T in [int, str]: S = Set(T) @@ -806,6 +823,7 @@ def symmetric_difference(x: S, y: S): # performance could be improved self.assertGreater(ratio, threshold) + @pytest.mark.group_one def test_set_iteration(self): def set_to_list(s: Set(str)) -> ListOf(str): result = ListOf(str)() @@ -818,6 +836,7 @@ def set_to_list(s: Set(str)) -> ListOf(str): r2 = Compiled(set_to_list)(s) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_set_refcounting(self): TOI = TupleOf(int) aTup = TOI((1, 2, 3)) @@ -859,6 +878,7 @@ def getItem(s, k): self.assertEqual(_types.refcount(aTup2), 1) self.assertEqual(_types.refcount(aTup3), 1) + @pytest.mark.group_one def test_set_pop_many(self): @Entrypoint def f(x: Set(str)): @@ -880,6 +900,7 @@ def f(x: Set(str)): self.assertEqual(len(x), 0) + @pytest.mark.group_one def test_set_up_and_down(self): @Entrypoint def f(targets): @@ -907,6 +928,7 @@ def f(targets): for i5 in range(C): f(ListOf(int)([i1, i2, i3, i4, i5])) + @pytest.mark.group_one def test_set_fuzz(self): # try adding and removing items repeatedly, in an effort to fill the table up @Entrypoint @@ -936,6 +958,7 @@ def f(actions: ListOf(Tuple(bool, int))): print(actions) raise + @pytest.mark.group_one def test_set_destructor_complex(self): NT = NamedTuple(x=TupleOf(str), y=TupleOf(str)) aTup = TupleOf(str)(['a']) @@ -953,6 +976,7 @@ def resizeZero(x): self.assertEqual(tupRefcount, _types.refcount(aTup)) + @pytest.mark.group_one def test_set_with_neg_one(self): # negative one is special because it hashes to -1. Python # treats a -1 as an error code (indicating there was @@ -978,6 +1002,7 @@ def set_in(x, s): set_remove(s, -1) self.assertFalse(set_in(-1, s)) + @pytest.mark.group_one def test_set_internal_functions(self): # These internal functions are already tested, as compiled python functions, in other tests # But these tests ensure that codecov counts these functions as "tested" @@ -1031,6 +1056,7 @@ def get(self): initialize_set_from_other_implicit_containers(p1, [1, 2], True) initialize_set_from_other_upcast_containers(p1, [1, 2], True) + @pytest.mark.group_one def test_compiled_set_constructors(self): def f_set(x): return Set(int)(x) @@ -1114,6 +1140,7 @@ def f_set_t(x): with self.assertRaises(TypeError): Entrypoint(f_set_t)({t1, t2, t4}) + @pytest.mark.group_one def test_set_aliasing(self): T = Set(int) @@ -1124,6 +1151,7 @@ def test_set_aliasing(self): assert len(t2) == 0 + @pytest.mark.group_one def test_set_aliasing_compiled(self): T = Set(int) @@ -1140,6 +1168,7 @@ def dup(x): assert len(t2) == 0 + @pytest.mark.group_one def test_set_adding_allows_container_upcast(self): T = Set(TupleOf(float)) @@ -1167,6 +1196,7 @@ def addIt(): aT.add([1, 2, "3"]) addIt() + @pytest.mark.group_one def test_set_size_change_during_iteration_raises(self): @Entrypoint def checkIt(): @@ -1179,6 +1209,7 @@ def checkIt(): with self.assertRaisesRegex(RuntimeError, "set size changed"): checkIt() + @pytest.mark.group_one def test_cant_convert_none_to_set(self): from typed_python import Class @@ -1192,6 +1223,7 @@ def callC(y: OneOf(None, Set(float))): callC([1]) + @pytest.mark.group_one def test_set_of_specific_alternative(self): A = Alternative( "A", diff --git a/typed_python/compiler/tests/string_compilation_test.py b/typed_python/compiler/tests/string_compilation_test.py index ba2b4fbf9..617b420fc 100644 --- a/typed_python/compiler/tests/string_compilation_test.py +++ b/typed_python/compiler/tests/string_compilation_test.py @@ -15,6 +15,7 @@ import pytest import unittest import time +import os from flaky import flaky from typed_python import _types, ListOf, TupleOf, Dict, ConstDict, Compiled, Entrypoint, OneOf @@ -23,7 +24,7 @@ strEndswith, strRangeEndswith, strEndswithTuple, strRangeEndswithTuple, \ strReplace, strPartition, strRpartition, strCenter, strRjust, strLjust, strExpandtabs, strZfill from typed_python.test_util import currentMemUsageMb, compilerPerformanceComparison -from typed_python.compiler.runtime import PrintNewFunctionVisitor +from typed_python.compiler.runtime import PrintNewFunctionVisitor, RuntimeEventVisitor someStrings = [ @@ -64,6 +65,7 @@ def callOrExceptNoType(f, *args): class TestStringCompilation(unittest.TestCase): + @pytest.mark.group_one def test_string_passing_and_refcounting(self): @Compiled def takeFirst(x: str, y: str): @@ -78,6 +80,7 @@ def takeSecond(x: str, y: str): self.assertEqual(s, takeFirst(s, s2)) self.assertEqual(s2, takeSecond(s, s2)) + @pytest.mark.group_one def test_string_len(self): @Compiled def compiledLen(x: str): @@ -86,6 +89,7 @@ def compiledLen(x: str): for s in someStrings: self.assertEqual(len(s), compiledLen(s)) + @pytest.mark.group_one def test_string_concatenation(self): @Compiled def concat(x: str, y: str): @@ -100,6 +104,7 @@ def concatLen(x: str, y: str): self.assertEqual(s+s2, concat(s, s2)) self.assertEqual(len(s+s2), concatLen(s, s2)) + @pytest.mark.group_one def test_string_comparison(self): @Compiled def lt(x: str, y: str): @@ -134,6 +139,7 @@ def neq(x: str, y: str): self.assertEqual(gt(s, s2), s > s2) self.assertEqual(lt(s, s2), s < s2) + @pytest.mark.group_one def test_string_constants(self): def makeConstantConcatenator(s): def returner(): @@ -146,6 +152,7 @@ def returner(): self.assertEqual(s, s_from_code, (repr(s), repr(s_from_code))) + @pytest.mark.group_one def test_string_getitem(self): @Compiled def getitem(x: str, y: int): @@ -155,6 +162,7 @@ def getitem(x: str, y: int): for i in range(-20, 20): self.assertEqual(callOrExcept(getitem, s, i), callOrExcept(lambda s, i: s[i], s, i), (s, i)) + @pytest.mark.group_one def test_string_ord(self): @Compiled def callOrd(x: str): @@ -168,6 +176,7 @@ def callOrd(x: str): with self.assertRaisesRegex(TypeError, "of length 4 found"): callOrd("asdf") + @pytest.mark.group_one def test_string_chr(self): @Compiled def callChr(x: int): @@ -176,6 +185,7 @@ def callChr(x: int): for i in range(0, 0x10ffff + 1): self.assertEqual(ord(callChr(i)), i) + @pytest.mark.group_one def test_string_startswith_endswith(self): def startswith(x: str, y: str): return x.startswith(y) @@ -213,6 +223,7 @@ def endswith_range(x: str, y: str, start: int, end: int): (s1, s2, start, end) ) + @pytest.mark.group_one def test_string_tuple_startswith_endswith(self): def startswith(x, y): return x.startswith(y) @@ -258,6 +269,7 @@ def endswith_range(x, y, start, end): (s, t, start, end) ) + @pytest.mark.group_one def test_string_replace(self): def replace(x: str, y: str, z: str): return x.replace(y, z) @@ -281,6 +293,7 @@ def replace2(x: str, y: str, z: str, i: int): for i in [-1, 0, 1, 2]: self.assertEqual(replace2(s1, s2, s3, i), replace2Compiled(s1, s2, s3, i), (s1, s2, s3, i)) + @pytest.mark.group_one def test_string_getitem_slice(self): def getitem1(x: str, y: int): return x[:y] @@ -303,6 +316,7 @@ def getitem3(x: str, y: int, y2: int): for j in range(-5, 10): self.assertEqual(getitem3(s, i, j), getitem3Compiled(s, i, j), (s, i, j)) + @pytest.mark.group_one def test_string_lower_upper(self): @Compiled @@ -349,6 +363,7 @@ def c_upper2(s: str, t: str): self.assertEqual(callOrExceptType(c_lower2, s, s), callOrExceptType(s.lower, s), s) self.assertEqual(callOrExceptType(c_upper2, s, s), callOrExceptType(s.upper, s), s) + @pytest.mark.group_one def test_string_find(self): @Compiled @@ -363,6 +378,7 @@ def c_find_3(s: str, sub: str, start: int): def c_find_2(s: str, sub: str): return s.find(sub) + @pytest.mark.group_one def test_find(t): substrings = ["", "x", "xyz", "a"*100, t[0:-2] + t[-1] if len(t) > 2 else ""] for start in range(0, min(len(t), 8)): @@ -417,6 +433,7 @@ def c_find_5(s: str, sub: str, start: int, end: int, extra: int): self.assertEqual(callOrExceptType(c_find_5, s, s, 0, 1, 2), callOrExceptType(s.find, s, 0, 1, 2)) self.assertEqual(callOrExceptType(c_find_1, s), callOrExceptType(s.find)) + @pytest.mark.group_one def test_string_find2(self): def f_find(x, sub): return x.find(sub) @@ -494,6 +511,7 @@ def f_rindex3(x, sub, start, end): with self.assertRaises(ValueError): Entrypoint(g)(v, sub, start, end) + @pytest.mark.group_one def test_string_count(self): def f_count(x, sub): return x.count(sub) @@ -525,6 +543,7 @@ def f_count3(x, sub, start, end): r2 = Entrypoint(f)(v, sub, start, end) self.assertEqual(r1, r2, (v, sub, start, end)) + @pytest.mark.group_one def test_string_from_float(self): @Compiled def toString(f: float): @@ -535,6 +554,7 @@ def toString(f: float): self.assertEqual(toString(1), "1.0") @pytest.mark.skipif("sys.version_info.minor >= 8", reason="differences in unicode handling between 3.7 and 3.8") + @pytest.mark.group_one def test_string_is_something(self): @Compiled def c_isalpha(s: str): @@ -621,6 +641,7 @@ def perform_comparison(s: str): self.assertEqual(c_istitle(s), s.istitle(), s) @pytest.mark.skipif("sys.version_info.minor >= 8", reason="differences in unicode handling between 3.7 and 3.8") + @pytest.mark.group_one def test_string_case(self): def f_lower(x): return x.lower() @@ -660,6 +681,7 @@ def f_casefold(x): r2 = Entrypoint(f)(v) self.assertEqual(r1, r2, (f, v)) + @pytest.mark.group_one def test_string_strip(self): @Compiled def strip(s: str): @@ -701,6 +723,7 @@ def rstrip2(s, p): self.assertEqual(r1, r2, (f, s, p)) @pytest.mark.skip(reason='just for comparing performance when changing implementation') + @pytest.mark.group_one def test_string_find_perf(self): @Compiled def c_find(c: str, s: str) -> int: @@ -721,6 +744,7 @@ def c_find(c: str, s: str) -> int: self.assertTrue(False) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_string_strip_perf(self): bigS = " " * 1000000 littleS = " " @@ -748,6 +772,7 @@ def stripMany(s: str, times: int): self.assertLess(ratio, expectedRatio) + @pytest.mark.group_one def test_string_split(self): def f_split(s: str, *args) -> ListOf(str): return s.split(*args) @@ -815,6 +840,7 @@ def f_rsplit(s: str, *args) -> ListOf(str): self.assertLess(endusage, startusage + 1) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_string_split_perf(self): def splitAndCount(s: str, sep: str, times: int): res = 0 @@ -836,6 +862,7 @@ def splitAndCount(s: str, sep: str, times: int): f"Compiler was {compiled / uncompiled} times slower." ) + @pytest.mark.group_one def test_type_of_string_split(self): def splitType(): return type("asdf".split("s")) @@ -892,6 +919,7 @@ def validate_joining_strings(self, function, make_obj): res = function(separator, make_obj(items)) self.assertEqual(expected, res, description) + @pytest.mark.group_one def test_string_join_for_tuple_of_str(self): # test passing tuple of strings @Compiled @@ -900,6 +928,7 @@ def f(sep: str, items: TupleOf(str)) -> str: self.validate_joining_strings(f, lambda items: TupleOf(str)(items)) + @pytest.mark.group_one def test_string_join_for_list_of_str(self): # test passing list of strings @Compiled @@ -908,6 +937,7 @@ def f(sep: str, items: ListOf(str)) -> str: self.validate_joining_strings(f, lambda items: ListOf(str)(items)) + @pytest.mark.group_one def test_string_join_for_dict_of_str(self): # test passing list of strings @Compiled @@ -916,6 +946,7 @@ def f(sep: str, items: Dict(str, str)) -> str: self.validate_joining_strings(f, lambda items: Dict(str, str)({i: "a" for i in items})) + @pytest.mark.group_one def test_string_join_for_const_dict_of_str(self): # test passing list of strings @Compiled @@ -924,6 +955,7 @@ def f(sep: str, items: ConstDict(str, str)) -> str: self.validate_joining_strings(f, lambda items: ConstDict(str, str)({i: "a" for i in items})) + @pytest.mark.group_one def test_string_join_for_bad_types(self): """str.join supports only joining ListOf(str) or TupleOf(str).""" @@ -943,6 +975,7 @@ def f_int(sep: str, items: ListOf(int)) -> str: with self.assertRaisesRegex(TypeError, ""): f_int(",", ListOf(int)([1, 2, 3])) + @pytest.mark.group_one def test_fstring(self): @Compiled def f(): @@ -957,6 +990,7 @@ def f(): # Note: this test fails with 1.23456 instead of 1.234567 # due to inexact representation of that value as 1.2345600000000001 + @pytest.mark.group_one def test_fstring_exception(self): @Compiled def f(): @@ -965,6 +999,7 @@ def f(): with self.assertRaisesRegex(Exception, "not_valid"): f() + @pytest.mark.group_one def test_string_contains_string(self): @Entrypoint def f(x, y): @@ -984,6 +1019,7 @@ def fNot(x, y): self.assertTrue(fNot("b", ListOf(str)(["asfd"]))) self.assertFalse(fNot("asdf", ListOf(str)(["asdf"]))) + @pytest.mark.group_one def test_string_of_global_function(self): def f(): return str(callOrExcept) @@ -995,6 +1031,7 @@ def callit(f): self.assertEqual(callit(f), str(callOrExcept)) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_compare_strings_to_constant(self): @Entrypoint def countEqualTo(z): @@ -1016,6 +1053,7 @@ def countEqualTo(z): # I get about .03 self.assertLess(elapsed, .1) + @pytest.mark.group_one def test_add_constants(self): @Entrypoint def addConstants(count): @@ -1032,6 +1070,7 @@ def addConstants(count): # llvm should recognize that this is just 'N' and so it should take no time. self.assertLess(time.time() - t0, 1e-4) + @pytest.mark.group_one def test_bad_string_index(self): @Entrypoint def doIt(x: OneOf(str, ConstDict(str, str))): @@ -1039,6 +1078,7 @@ def doIt(x: OneOf(str, ConstDict(str, str))): doIt({'bd': 'yes'}) + @pytest.mark.group_one def test_iterate_list_of_strings(self): @Entrypoint def sumSplit(x: str): @@ -1050,6 +1090,7 @@ def sumSplit(x: str): assert sumSplit("1") == 1 assert sumSplit("1,2") == 3 + @pytest.mark.group_one def test_can_split_result_of_split(self): @Entrypoint def sumSplit(x: str): @@ -1062,6 +1103,7 @@ def sumSplit(x: str): assert sumSplit("1") == 1 assert sumSplit("1.2,2") == 5 + @pytest.mark.group_one def test_can_index_into_result_of_split(self): @Entrypoint def sumSplit(x: str): @@ -1077,6 +1119,7 @@ def sumSplit(x: str): assert sumSplit("1.2,2") == 3 + @pytest.mark.group_one def test_call_int_on_object(self): @Entrypoint def f(x: object): @@ -1084,6 +1127,7 @@ def f(x: object): assert f("1") == 1 + @pytest.mark.group_one def test_string_iteration(self): def iter(x: str): r = ListOf(str)() @@ -1119,6 +1163,7 @@ def contains_space(x: str): r2 = Compiled(contains_space)(v) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_string_mult(self): def f_mult(x, n): return x * n @@ -1129,6 +1174,7 @@ def f_mult(x, n): r2 = Entrypoint(f_mult)(v, n) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_string_decode(self): # various permutation of parameters (positional, keyword, missing) def f_1(x, enc, err): @@ -1151,6 +1197,7 @@ def f_4(x, enc, err): r2 = callOrExceptType(Entrypoint(f), v, enc, err) self.assertEqual(r1, r2) + @pytest.mark.group_one def test_string_encode(self): # various permutation of parameters (positional, keyword, missing) def f_1(x, enc, err): @@ -1174,6 +1221,7 @@ def f_4(x, enc, err): self.assertEqual(r1, r2, (f, v, enc, err)) @pytest.mark.skip(reason='not performant') + @pytest.mark.group_one def test_string_codec(self): s1 = ''.join([chr(i) for i in range(0, 0x10ffff, 13) if i < 0xD800 or i > 0xDFFF]) s2 = ''.join([chr(i) for i in range(1, 0x10ffff, 17) if i < 0xD800 or i > 0xDFFF]) @@ -1201,6 +1249,7 @@ def f_endecode(s: str) -> bool: self.assertTrue(c_endecode(v)) @pytest.mark.skip(reason='not performant') + @pytest.mark.group_one def test_string_codec_perf(self): repeat = 500 s1 = ''.join([chr(i) for i in range(0, 0x10ffff, 13) if i < 0xD800 or i > 0xDFFF]) @@ -1255,6 +1304,7 @@ def f_endecode2(cases: ListOf(str)) -> bool: t3 = time.time() print("compiled2 ", t3 - t2) + @pytest.mark.group_one def test_string_partition(self): def f_partition(x, sep): return x.partition(sep) @@ -1275,6 +1325,7 @@ def f_rpartition(x, sep): with self.assertRaises(TypeError): Entrypoint(f)(v, b'abc') + @pytest.mark.group_one def test_string_just(self): def f_center(x, w, fill): if fill == ' ': @@ -1309,6 +1360,7 @@ def f_rjust(x, w, fill): with self.assertRaises(TypeError): Entrypoint(f)(v, w, b'X') + @pytest.mark.group_one def test_string_tabs(self): def f_expandtabs(x, t): return x.expandtabs(t) @@ -1335,6 +1387,7 @@ def f_splitlines(x, *a): r2 = Entrypoint(f_splitlines)(v, k) self.assertEqual(r1, r2, (v, k)) + @pytest.mark.group_one def test_string_zfill(self): def f_zfill(x, w): return x.zfill(w) @@ -1345,6 +1398,7 @@ def f_zfill(x, w): r2 = Entrypoint(f_zfill)(v, w) self.assertEqual(r1, r2, (v, w)) + @pytest.mark.group_one def test_string_translate(self): def f_translate(s, t): return s.translate(t) @@ -1364,6 +1418,7 @@ def f_translate(s, t): r2 = c_translate(s, t) self.assertEqual(r1, r2, s) + @pytest.mark.group_one def test_string_maketrans(self): def f_maketrans(*args): return str.maketrans(*args) @@ -1403,6 +1458,7 @@ def f_maketrans(*args): r4 = s.translate(r2[1]) self.assertEqual(r3, r4, args) + @pytest.mark.group_one def test_string_internal_fns(self): """ These are functions that are normally not called directly. @@ -1445,3 +1501,42 @@ def test_string_internal_fns(self): self.assertEqual(strExpandtabs(v, 8), v.expandtabs(8)) self.assertEqual(strZfill(v, 20), v.zfill(20)) self.assertEqual(strZfill('+123', 20), '+123'.zfill(20)) + + def test_fstring_of_string_doesnt_hit_interpreter(self): + # if the cache is on, this won't work + if os.getenv("TP_COMPILER_CACHE"): + return + + class Visitor(RuntimeEventVisitor): + """Base class for a Visitor that gets to see what's going on in the runtime. + + Clients should subclass this and pass it to 'addEventVisitor' in the runtime + to find out about events like function typing assignments. + """ + def onNewFunction( + self, + identifier, + functionConverter, + nativeFunction, + funcName, + funcCode, + funcGlobals, + closureVars, + inputTypes, + outputType, + yieldType, + variableTypes, + conversionType, + calledFunctions, + ): + if funcName == "toString": + self.nativeFunction = nativeFunction + + @Entrypoint + def toString(x: OneOf("hi", "bye")): # noqa + return f"its: {x}" + + with Visitor() as vis: + toString("hi") + + assert 'PythonObjectOfTypeWrapper' not in str(vis.nativeFunction) diff --git a/typed_python/compiler/tests/subclass_of_test.py b/typed_python/compiler/tests/subclass_of_test.py index 90179942b..934811f18 100644 --- a/typed_python/compiler/tests/subclass_of_test.py +++ b/typed_python/compiler/tests/subclass_of_test.py @@ -13,6 +13,7 @@ class C(B, Final): pass +@pytest.mark.group_one def test_can_cast_subclass_of_correctly(): @Function def f(c: SubclassOf(C)): diff --git a/typed_python/compiler/tests/time_compilation_test.py b/typed_python/compiler/tests/time_compilation_test.py index 907c360e3..cbfefe6be 100644 --- a/typed_python/compiler/tests/time_compilation_test.py +++ b/typed_python/compiler/tests/time_compilation_test.py @@ -18,6 +18,7 @@ import time +@pytest.mark.group_one def test_knows_its_a_float(): @Entrypoint def callTime(): @@ -29,6 +30,7 @@ def callTime(): assert abs(callTime() - time.time()) < 0.001 +@pytest.mark.group_one def test_call_perf(): @Entrypoint def callTimeNTimes(times): diff --git a/typed_python/compiler/tests/tuple_compilation_test.py b/typed_python/compiler/tests/tuple_compilation_test.py index 7fd745ae1..15f9f9c9d 100644 --- a/typed_python/compiler/tests/tuple_compilation_test.py +++ b/typed_python/compiler/tests/tuple_compilation_test.py @@ -23,6 +23,7 @@ class TestTupleCompilation(unittest.TestCase): + @pytest.mark.group_one def test_tuple_passing(self): T = Tuple(float, int, str) @@ -34,6 +35,7 @@ def f(x: T) -> T: t = T((0.0, 1, "hi")) self.assertEqual(f(t), t) + @pytest.mark.group_one def test_named_tuple_passing(self): NT = NamedTuple(a=float, b=int, c=str) @@ -45,6 +47,7 @@ def f(x: NT) -> NT: nt = NT(a=0.0, b=1, c="hi") self.assertEqual(f(nt), nt) + @pytest.mark.group_one def test_named_tuple_getattr(self): NT = NamedTuple(a=float, b=int, c=str) @@ -55,6 +58,7 @@ def f(x: NT) -> str: nt = NT(a=0.0, b=1, c="hi") self.assertEqual(f(nt), "hihi") + @pytest.mark.group_one def test_named_tuple_assignment_refcounting(self): class C(Class): x = Member(int) @@ -72,6 +76,7 @@ def f(x: NT): self.assertEqual(res.x, 20) self.assertEqual(_types.refcount(res), 2) + @pytest.mark.group_one def test_indexing(self): T = Tuple(int, str) @@ -93,6 +98,7 @@ def getIx(t, i): self.assertEqual(getIx(T((1, '2')), 0), 1) self.assertEqual(getIx(T((1, '2')), 1), '2') + @pytest.mark.group_one def test_iterating(self): @Entrypoint def tupToString(x): @@ -106,6 +112,7 @@ def tupToString(x): ["0", "a"] ) + @pytest.mark.group_one def test_named_tuple_replacing_error(self): """We should have errors for all the field names passed to the replacing function, if the fields are not in the tuple definition. @@ -127,6 +134,7 @@ def f2(x: NT) -> NT: with self.assertRaisesRegex(Exception, "The arguments list contain names 'c, d, e' which are not in the tuple definition."): f2(n1) + @pytest.mark.group_one def test_named_tuple_replacing_function(self): NT = NamedTuple(a=int, b=str) n1 = NT(a=1, b='x') @@ -150,6 +158,7 @@ def f2(x: NT, a: int, b: str) -> NT: self.assertEqual(n3.a, 123) self.assertEqual(n3.b, '345') + @pytest.mark.group_one def test_named_tuple_replacing_refcount(self): N = NamedTuple(x=ListOf(int)) N = NamedTuple(x=ListOf(int)) @@ -162,6 +171,7 @@ def test_named_tuple_replacing_refcount(self): nt = None self.assertEqual(_types.refcount(aList), 1) + @pytest.mark.group_one def test_named_tuple_construction(self): NT = NamedTuple(x=ListOf(int), y=float) @@ -189,6 +199,7 @@ def makeNtXY(x, y): with self.assertRaisesRegex(TypeError, "Couldn't initialize type ListOf.int. from float"): makeNtX(1.2) + @pytest.mark.group_one def test_compile_make_named_tuple(self): @Entrypoint def makeNt(x, y): @@ -197,6 +208,7 @@ def makeNt(x, y): self.assertEqual(makeNt(1, 2), makeNamedTuple(x=1, y=2)) self.assertEqual(makeNt(1, "2"), makeNamedTuple(x=1, y="2")) + @pytest.mark.group_one def test_compiled_tuple_construction(self): def makeNamed(x, y): return NamedTuple(x=type(x), y=type(y))((x, y)) @@ -216,6 +228,7 @@ def check(f, x, y): check(makeUnnamed, 1, 2) check(makeUnnamed, 1, "2") + @pytest.mark.group_one def test_compare_tuples(self): ClassWithCompare = Forward("ClassWithCompare") @@ -277,6 +290,7 @@ def check(l, expected=None): check(lambda: t1 == t2) check(lambda: t1 != t2) + @pytest.mark.group_one def test_negative_indexing(self): @Entrypoint def sliceAt(tup, ix): @@ -307,6 +321,7 @@ class B(Class): self.assertIs(Function(lambda tup: sliceAt(tup, -2)).resultTypeFor(type(tup)).interpreterTypeRepresentation, OneOf(A, B)) + @pytest.mark.group_one def test_construct_named_tuple_with_other_named_tuple(self): # we should be matching the names up correctly T1 = NamedTuple(x=int, y=str) @@ -330,6 +345,7 @@ def secondCheck(): with self.assertRaises(TypeError): secondCheck() + @pytest.mark.group_one def test_construct_named_tuple_with_incorrect_number_of_arguments(self): # we should be matching the names up correctly NT = NamedTuple(z=float, y=str, x=int) @@ -340,6 +356,7 @@ def checkIt(): assert checkIt().y == "" + @pytest.mark.group_one def test_cant_construct_named_tuple_with_non_default_initializable(self): # we should be matching the names up correctly C = Forward("C") @@ -360,6 +377,7 @@ def checkIt(): with self.assertRaisesRegex(TypeError, "Can't default initialize member 'c'"): checkIt() + @pytest.mark.group_one def test_create_tuple_uses_implicit_containers(self): def f(): res = Dict(object, object)({1: 2, 3: 4}) @@ -368,6 +386,7 @@ def f(): assert f() == Entrypoint(f)() + @pytest.mark.group_one def test_compile_in(self): for entrypoint in [ lambda x: x, @@ -382,6 +401,7 @@ def checkIn(x, t): assert checkIn('a', NamedTuple(x=str, y=str)(x='a', y='b')) assert not checkIn('c', NamedTuple(x=str, y=str)(x='a', y='b')) + @pytest.mark.group_one def test_compile_in_on_constant(self): @Entrypoint def checkIn(x): @@ -390,6 +410,7 @@ def checkIn(x): assert checkIn('1') assert not checkIn('c') + @pytest.mark.group_one def test_compile_in_all_constant(self): @Entrypoint def checkIn(): @@ -398,3 +419,18 @@ def checkIn(): return None assert checkIn.resultTypeFor().typeRepresentation == int + + def test_iterate_tuple(self): + T = Tuple(int, float, str) + + @Entrypoint + def iterateIt(x: T): + res = ListOf(OneOf(int, float, str))() + + for e in x: + res.append(e) + + return res + + tup = T((1, 2, '3')) + assert iterateIt(tup) == ListOf(OneOf(int, float, str))(tup) diff --git a/typed_python/compiler/tests/tuple_of_compilation_test.py b/typed_python/compiler/tests/tuple_of_compilation_test.py index ee91894dc..197103d98 100644 --- a/typed_python/compiler/tests/tuple_of_compilation_test.py +++ b/typed_python/compiler/tests/tuple_of_compilation_test.py @@ -38,6 +38,7 @@ def checkFunction(self, f, argsToCheck): self.assertEqual(fastval, slowval) return t_py, t_fast + @pytest.mark.group_one def test_tuple_of_float(self): def f(x: TupleOf(float), y: TupleOf(float)) -> float: j = 0 @@ -67,6 +68,7 @@ def f(x: TupleOf(float), y: TupleOf(float)) -> float: print(t_py / t_fast, " speedup") + @pytest.mark.group_one def test_tuple_passing(self): @Compiled def f(x: TupleOf(int)) -> int: @@ -74,6 +76,7 @@ def f(x: TupleOf(int)) -> int: self.assertEqual(f((1, 2, 3)), 0) + @pytest.mark.group_one def test_tuple_len(self): @Compiled def f(x: TupleOf(int)) -> int: @@ -81,6 +84,7 @@ def f(x: TupleOf(int)) -> int: self.assertEqual(f((1, 2, 3)), 3) + @pytest.mark.group_one def test_tuple_assign(self): @Compiled def f(x: TupleOf(int)) -> TupleOf(int): @@ -93,6 +97,7 @@ def f(x: TupleOf(int)) -> TupleOf(int): self.assertEqual(_types.refcount(t), 1) + @pytest.mark.group_one def test_tuple_indexing(self): @Compiled def f(x: TupleOf(int), y: int) -> int: @@ -103,6 +108,7 @@ def f(x: TupleOf(int), y: int) -> int: with self.assertRaises(Exception): f((1, 2, 3), 1000000000) + @pytest.mark.group_one def test_tuple_refcounting(self): @Function def f(x: TupleOf(int), y: TupleOf(int)) -> TupleOf(int): @@ -124,6 +130,7 @@ def f(x: TupleOf(int), y: TupleOf(int)) -> TupleOf(int): self.assertEqual(_types.refcount(intTup), 1) + @pytest.mark.group_one def test_bad_mod_generates_exception(self): @Compiled def f(x: int, y: int) -> int: @@ -132,6 +139,7 @@ def f(x: int, y: int) -> int: with self.assertRaises(Exception): f(0, 0) + @pytest.mark.group_one def test_tuple_of_adding(self): T = TupleOf(int) @@ -150,6 +158,7 @@ def f(x: T, y: T) -> T: self.assertEqual(res, t1+t2) + @pytest.mark.group_one def test_tuple_of_tuple_refcounting(self): T = TupleOf(int) TT = TupleOf(T) @@ -173,6 +182,7 @@ def f(x: TT) -> TT: aTT = None self.assertEqual(_types.refcount(t1), 1) + @pytest.mark.group_one def test_tuple_creation_doesnt_leak(self): T = TupleOf(int) @@ -191,6 +201,7 @@ def f(x: T, y: T) -> T: self.assertTrue(finalMem < initMem + 5) + @pytest.mark.group_one def test_create_tuple_of_directly_from_list(self): def makeT(): return TupleOf(int)([1, 2, 3, 4]) @@ -198,6 +209,7 @@ def makeT(): self.assertEqual(makeT(), Compiled(makeT)()) self.assertEqual(type(makeT()), type(Compiled(makeT)())) + @pytest.mark.group_one def test_create_tuple_of_directly_from_tuple(self): def makeT(): return TupleOf(int)((1, 2, 3, 4)) @@ -205,6 +217,7 @@ def makeT(): self.assertEqual(makeT(), Compiled(makeT)()) self.assertEqual(type(makeT()), type(Compiled(makeT)())) + @pytest.mark.group_one def test_create_tuple_of_from_untyped(self): def makeT(aList: object): return TupleOf(int)(aList) @@ -212,6 +225,7 @@ def makeT(aList: object): self.assertEqual(makeT([1, 2, 3, 4]), Compiled(makeT)([1, 2, 3, 4])) self.assertEqual(makeT({1: 2}), Compiled(makeT)({1: 2})) + @pytest.mark.group_one def test_tuple_of_from_list_of_empty(self): @Entrypoint def makeT(aList: ListOf(int)): @@ -219,6 +233,7 @@ def makeT(aList: ListOf(int)): assert len(makeT([])) == 0 + @pytest.mark.group_one def test_slice_list_of_compiled(self): @Entrypoint def sliceIt(aLst: ListOf(int), x: int): @@ -226,6 +241,7 @@ def sliceIt(aLst: ListOf(int), x: int): assert sliceIt((1, 2, 3), 1) == [1] + @pytest.mark.group_one def test_slice_tuple_of_compiled(self): @Entrypoint def sliceIt(aTup: TupleOf(int), x: int): @@ -233,6 +249,7 @@ def sliceIt(aTup: TupleOf(int), x: int): assert sliceIt((1, 2, 3), 1) == (1,) + @pytest.mark.group_one def test_add_untyped_tuple(self): @Entrypoint def addIt(aTup: TupleOf(int), x: int): @@ -245,6 +262,7 @@ def addItLst(aTup: TupleOf(int), x: int): assert addIt((1, 2), 3) == (1, 2, 3) assert addItLst((1, 2), 3) == (1, 2, 3) + @pytest.mark.group_one def test_add_untyped_tuple_reversed(self): @Entrypoint def addIt(aTup: TupleOf(int), x: int): diff --git a/typed_python/compiler/tests/type_conversion_test.py b/typed_python/compiler/tests/type_conversion_test.py index deadc6b55..ec461d5d9 100644 --- a/typed_python/compiler/tests/type_conversion_test.py +++ b/typed_python/compiler/tests/type_conversion_test.py @@ -176,6 +176,7 @@ def checkConversionToType(x, TargetType, expectedSuccessLevel): ) +@pytest.mark.group_one def test_register_conversion_semantics(): checkConversionToType(False, bool, ConversionLevel.Signature) checkConversionToType(False, UInt16, ConversionLevel.Upcast) @@ -208,10 +209,12 @@ def test_register_conversion_semantics(): checkConversionToType("0", str, ConversionLevel.Signature) +@pytest.mark.group_one def test_int_to_list_of_int(): checkConversionToType(1, ListOf(int), None) +@pytest.mark.group_one def test_untyped_dict_conversion_semantics(): aDict = {1: 2} checkConversionToType(aDict, Dict(int, int), ConversionLevel.ImplicitContainers) @@ -228,6 +231,7 @@ def test_untyped_dict_conversion_semantics(): checkConversionToType(aDict, Set(float), ConversionLevel.ImplicitContainers) +@pytest.mark.group_one def test_untyped_list_of_conversion_semantics(): aList = [1, 2] @@ -239,6 +243,7 @@ def test_untyped_list_of_conversion_semantics(): checkConversionToType(aList, Set(float), ConversionLevel.ImplicitContainers) +@pytest.mark.group_one def test_untyped_tuple_of_conversion_semantics(): aTup = (1, 2) @@ -250,6 +255,7 @@ def test_untyped_tuple_of_conversion_semantics(): checkConversionToType(aTup, Set(float), ConversionLevel.ImplicitContainers) +@pytest.mark.group_one def test_typed_dict_conversion_semantics(): aDict = Dict(int, float)({1: 2, 3: 4.5}) @@ -261,6 +267,7 @@ def test_typed_dict_conversion_semantics(): checkConversionToType(aDict, TupleOf(str), None) +@pytest.mark.group_one def test_numpy_scalar_conversion(): checkConversionToType(numpy.int64(1), int, ConversionLevel.Signature) checkConversionToType(numpy.int64(1), float, ConversionLevel.Upcast) @@ -278,6 +285,7 @@ def test_numpy_scalar_conversion(): checkConversionToType(numpy.int32(1), str, ConversionLevel.New) +@pytest.mark.group_one def test_convert_things_to_object(): checkConversionToType(test_convert_things_to_object, object, ConversionLevel.Signature) checkConversionToType(str, object, ConversionLevel.Signature) @@ -292,16 +300,19 @@ def test_convert_things_to_object(): checkConversionToType(Set(int)(), object, ConversionLevel.Signature) +@pytest.mark.group_one def test_list_of_conversion_semantics(): checkConversionToType(ListOf(int)([1, 2]), Set(int), ConversionLevel.ImplicitContainers) checkConversionToType(ListOf(float)([1, 2]), Set(int), ConversionLevel.New) checkConversionToType(ListOf(int)([1, 2]), Set(float), ConversionLevel.ImplicitContainers) +@pytest.mark.group_one def test_typed_set_conversion_semantics(): checkConversionToType({1}, Set(int), ConversionLevel.ImplicitContainers) +@pytest.mark.group_one def test_convert_containers_to_oneof(): checkConversionToType(ListOf(int)(), OneOf(None, ListOf(int)), ConversionLevel.Signature) checkConversionToType(ListOf(int)(), OneOf(None, ListOf(float)), ConversionLevel.ImplicitContainers) @@ -309,19 +320,23 @@ def test_convert_containers_to_oneof(): checkConversionToType(ListOf(str)(["1.0"]), OneOf(None, ListOf(float)), None) +@pytest.mark.group_one def test_convert_to_bytes(): checkConversionToType("hi", bytes, None) checkConversionToType(ListOf(int)([1, 2, 3]), bytes, ConversionLevel.New) +@pytest.mark.group_one def test_convert_numpy_to_listof(): checkConversionToType(numpy.array([1, 2]), ListOf(int), ConversionLevel.ImplicitContainers) +@pytest.mark.group_one def test_convert_type_to_type(): checkConversionToType(str, type, ConversionLevel.Signature) +@pytest.mark.group_one def test_convert_untyped_classes(): class C1: pass @@ -333,6 +348,7 @@ class C2(C1): checkConversionToType(C1(), C2, None) +@pytest.mark.group_one def test_convert_to_named_tuple(): checkConversionToType(NamedTuple(x=int)(x=1), NamedTuple(x=float), ConversionLevel.Upcast) checkConversionToType(NamedTuple(x=OneOf(int, float))(x=1), NamedTuple(x=int), ConversionLevel.Upcast) diff --git a/typed_python/compiler/tests/type_function_compilation_test.py b/typed_python/compiler/tests/type_function_compilation_test.py index 52d9ced55..a3f74127b 100644 --- a/typed_python/compiler/tests/type_function_compilation_test.py +++ b/typed_python/compiler/tests/type_function_compilation_test.py @@ -17,6 +17,7 @@ class CompileTypeFunctionTest(unittest.TestCase): + @pytest.mark.group_one def test_basic(self): @TypeFunction def List(T): @@ -31,6 +32,7 @@ def canInferType(T): ListOf(int) ) + @pytest.mark.group_one def test_pass_type_function_as_value(self): @TypeFunction def List(T): @@ -47,6 +49,7 @@ def inferType(TF, T): self.assertEqual(inferType(List, int), ListOf(int)) + @pytest.mark.group_one def test_instantiating_type_function_value(self): @TypeFunction def List(T): diff --git a/typed_python/compiler/tests/type_inference_test.py b/typed_python/compiler/tests/type_inference_test.py index eb4cb6141..795fff472 100644 --- a/typed_python/compiler/tests/type_inference_test.py +++ b/typed_python/compiler/tests/type_inference_test.py @@ -32,6 +32,7 @@ class TestTypeInference(unittest.TestCase): + @pytest.mark.group_one def test_basic_inference(self): @Function def f(x, y): @@ -41,6 +42,7 @@ def f(x, y): self.assertEqual(f.resultTypeFor(int, float).typeRepresentation, float) self.assertEqual(f.resultTypeFor(int, str), None) + @pytest.mark.group_one def test_sequential_assignment(self): @Function def f(x): @@ -50,6 +52,7 @@ def f(x): self.assertEqual(f.resultTypeFor(int).typeRepresentation, int) + @pytest.mark.group_one def test_if_short_circuit(self): @Function def f(x): @@ -61,6 +64,7 @@ def f(x): self.assertEqual(f.resultTypeFor(int).typeRepresentation, int) + @pytest.mark.group_one def test_if_merging(self): @Function def f(x): @@ -72,6 +76,7 @@ def f(x): self.assertEqual(set(f.resultTypeFor(int).typeRepresentation.Types), set([int, str])) + @pytest.mark.group_one def test_isinstance_propagates(self): @Function def f(x): @@ -82,6 +87,7 @@ def f(x): self.assertEqual(f.resultTypeFor(OneOf(str, int)).typeRepresentation, int) + @pytest.mark.group_one def test_alternative_inference(self): @Function def f(anA): @@ -89,6 +95,7 @@ def f(anA): self.assertEqual(set(f.resultTypeFor(A).typeRepresentation.Types), set([int, str])) + @pytest.mark.group_one def test_alternative_inference_with_branch(self): @Function def f(anA): @@ -99,6 +106,7 @@ def f(anA): self.assertEqual(f.resultTypeFor(A).typeRepresentation, int) + @pytest.mark.group_one def test_alternative_inference_with_nonsense_branch(self): @Function def f(anA): @@ -109,6 +117,7 @@ def f(anA): self.assertEqual(f.resultTypeFor(A).typeRepresentation, int) + @pytest.mark.group_one def test_no_result_from_while_true(self): @Function def f(x): @@ -120,6 +129,7 @@ def f(x): self.assertEqual(f.resultTypeFor(int).typeRepresentation, int) self.assertEqual(Entrypoint(f)(10), 10001) + @pytest.mark.group_one def test_infer_type_object(self): @Function def f(x): @@ -131,6 +141,7 @@ def f(x): set([Value(int), Value(str)]) ) + @pytest.mark.group_one def test_infer_result_of_uint8(self): @Entrypoint def f(x): @@ -138,6 +149,7 @@ def f(x): self.assertEqual(f.resultTypeFor(float).typeRepresentation, UInt8) + @pytest.mark.group_one def test_infer_result_of_uint8_constant(self): @Entrypoint def f(): @@ -145,6 +157,7 @@ def f(): self.assertEqual(f.resultTypeFor().typeRepresentation, UInt8) + @pytest.mark.group_one def test_infer_list_item(self): @Function def f(a: ListOf(str), x: int): @@ -157,6 +170,7 @@ def g(b, x: int): self.assertEqual(f.resultTypeFor(ListOf(str), int).typeRepresentation, str) self.assertEqual(g.resultTypeFor(object, int).typeRepresentation, object) + @pytest.mark.group_one def test_infer_conditional_eval_exception(self): @Function def exc(): @@ -198,6 +212,7 @@ def or3(x, y): self.assertEqual(set(or3.resultTypeFor(int, float).typeRepresentation.Types), set([int, float])) self.assertEqual(set(or3.resultTypeFor(float, int).typeRepresentation.Types), set([int, float])) + @pytest.mark.group_one def test_infer_type_of_assignment_with_guard(self): @Function def f(x): @@ -214,6 +229,7 @@ def f(x): self.assertEqual(f.resultTypeFor(None).typeRepresentation, int) self.assertEqual(f.resultTypeFor(float).typeRepresentation, int) + @pytest.mark.group_one def test_infer_type_of_nocompile(self): @NotCompiled def f() -> int: @@ -229,6 +245,7 @@ def f2(): self.assertEqual(f2.resultTypeFor().typeRepresentation, object) + @pytest.mark.group_one def test_compiler_can_see_through_explicitly_constructed_typed_tuples(self): @Entrypoint def returnTupElts(x): @@ -236,6 +253,7 @@ def returnTupElts(x): assert returnTupElts.resultTypeFor(int).typeRepresentation == int + @pytest.mark.group_one def test_compiler_can_see_through_untyped_tuples(self): @Entrypoint def returnTupElts(x): @@ -243,6 +261,7 @@ def returnTupElts(x): assert returnTupElts.resultTypeFor(int).typeRepresentation == int + @pytest.mark.group_one def test_compiler_can_merge_like_untyped_tuples(self): @Entrypoint def returnTupElts(x): @@ -255,6 +274,7 @@ def returnTupElts(x): assert returnTupElts.resultTypeFor(int).typeRepresentation == int + @pytest.mark.group_one def test_compiler_can_converts_unlike_untyped_tuples_to_object(self): @Entrypoint def returnTupElts(x): @@ -267,6 +287,7 @@ def returnTupElts(x): assert returnTupElts.resultTypeFor(int).typeRepresentation is tuple + @pytest.mark.group_one def test_tuple_as_variable_traces_properly(self): @Entrypoint def returnTupElts(x): @@ -276,6 +297,7 @@ def returnTupElts(x): assert returnTupElts.resultTypeFor(float).typeRepresentation is Tuple(int, int, float) + @pytest.mark.group_one def test_compiler_knows_type_of_arguments(self): @Entrypoint def returnTypeOfArgument(x): @@ -285,6 +307,7 @@ def returnTypeOfArgument(x): assert returnTypeOfArgument(10.5) is float assert returnTypeOfArgument(float) is Value(float) + @pytest.mark.group_one def test_compiler_knows_it_has_oneofs(self): @Entrypoint def returnTypeOfArgument(x): @@ -297,6 +320,7 @@ def returnTypeOfArgument(x): assert returnTypeOfArgument(10) is OneOf(float, int) + @pytest.mark.group_one def test_compiler_knows_that_isinstance_constrains_types(self): @Entrypoint def returnTypeOfArgument(x): @@ -313,6 +337,7 @@ def returnTypeOfArgument(x): assert returnTypeOfArgument(10) is int assert returnTypeOfArgument(0) is float + @pytest.mark.group_one def test_compiler_knows_local_variable_types(self): @Entrypoint def localVariableTypes(x): @@ -326,6 +351,7 @@ def localVariableTypes(x): res = localVariableTypes(10) assert res == dict(x=int, y=OneOf(float, int)) + @pytest.mark.group_one def test_type_inference_perf(self): t0 = time.time() f = Function(lambda o: o + 1) @@ -338,6 +364,7 @@ def test_type_inference_perf(self): # I get around 0.03 on my desktop with the caching, and .7 without it assert time.time() - t0 < .4 + @pytest.mark.group_one def test_type_inference_with_exceptions(self): # check that if we catch an arbitrary exception, then we can't really # know what the type of a variable coming out of the exception block. @@ -383,6 +410,7 @@ def check3(): assert check3()['y'] == OneOf(float, str) + @pytest.mark.group_one def test_restricts_based_on_isinstance(self): # check that the compiler understands how to restrict a OneOf based on 'is None' @Entrypoint @@ -393,6 +421,7 @@ def f(x: OneOf(None, str)): assert f("hi")['x'] == str @pytest.mark.skipif("sys.version_info.minor < 8") + @pytest.mark.group_one def test_restricts_based_on_None(self): # check that the compiler understands how to restrict a OneOf based on 'is None' @Entrypoint @@ -412,6 +441,7 @@ def f(x: OneOf(None, str)): assert f("hi")['x'] == str @pytest.mark.skipif("sys.version_info.minor < 8") + @pytest.mark.group_one def test_assertion_prunes_types(self): @Entrypoint def f(x: OneOf(None, str)): @@ -423,6 +453,7 @@ def f(x: OneOf(None, str)): assert f.resultTypeFor(type(None)).typeRepresentation is str @pytest.mark.skipif("sys.version_info.minor < 8") + @pytest.mark.group_one def test_branch_with_raise_prunes_types(self): @Entrypoint def f(x: OneOf(None, str)): diff --git a/typed_python/compiler/tests/type_of_instances_compilation_test.py b/typed_python/compiler/tests/type_of_instances_compilation_test.py index 337bdc3ff..dba8fdad8 100644 --- a/typed_python/compiler/tests/type_of_instances_compilation_test.py +++ b/typed_python/compiler/tests/type_of_instances_compilation_test.py @@ -1,6 +1,7 @@ from typed_python import Entrypoint, Alternative, Class +@pytest.mark.group_one def test_type_of_class_is_specific(): class C(Class): pass @@ -15,6 +16,7 @@ def typeOfArg(x: C): assert typeOfArg(B()) is B +@pytest.mark.group_one def test_type_of_alternative_is_specific(): for members in [{}, {'a': int}]: A = Alternative("A", A=members) @@ -26,6 +28,7 @@ def typeOfArg(x: A): assert typeOfArg(A.A()) is A.A +@pytest.mark.group_one def test_type_of_concrete_alternative_is_specific(): for members in [{}, {'a': int}]: A = Alternative("A", A=members) @@ -37,6 +40,7 @@ def typeOfArg(x: A.A): assert typeOfArg(A.A()) is A.A +@pytest.mark.group_one def test_type_name(): A = Alternative("A", X=dict(x=int), Y=dict(y=int)) diff --git a/typed_python/compiler/tests/typed_function_compilation_test.py b/typed_python/compiler/tests/typed_function_compilation_test.py index 291b8f2eb..6ed61c041 100644 --- a/typed_python/compiler/tests/typed_function_compilation_test.py +++ b/typed_python/compiler/tests/typed_function_compilation_test.py @@ -3,6 +3,7 @@ class TestCompileTypedFunctions(unittest.TestCase): + @pytest.mark.group_one def test_compile_function_with_no_ret_type(self): # this function definitely throws, and so it doesn't # have a return type. diff --git a/typed_python/compiler/type_wrappers/list_of_wrapper.py b/typed_python/compiler/type_wrappers/list_of_wrapper.py index 04e44a5e3..b101be9ed 100644 --- a/typed_python/compiler/type_wrappers/list_of_wrapper.py +++ b/typed_python/compiler/type_wrappers/list_of_wrapper.py @@ -360,13 +360,17 @@ def createEmptyList(self, context, out): out.expr.store( runtime_functions.malloc.call(28).cast(self.getNativeLayoutType()) ) - >> out.nonref_expr.ElementPtrIntegers(0, 0).store(native_ast.const_int_expr(1)) # refcount - >> out.nonref_expr.ElementPtrIntegers(0, 1).store(native_ast.const_int32_expr(-1)) # hash cache - >> out.nonref_expr.ElementPtrIntegers(0, 2).store(native_ast.const_int32_expr(0)) # count - >> out.nonref_expr.ElementPtrIntegers(0, 3).store(native_ast.const_int32_expr(1)) # reserved - >> out.nonref_expr.ElementPtrIntegers(0, 4).store( - runtime_functions.malloc.call(self.underlyingWrapperType.getBytecount()) - ) # data + >> out.nonref_expr.ElementPtrIntegers(0).store( + native_ast.Expression.MakeStruct( + args=( + ('refcount', native_ast.const_int_expr(1)), + ('hash_cache', native_ast.const_int32_expr(-1)), + ('count', native_ast.const_int32_expr(0)), + ('reserved', native_ast.const_int32_expr(1)), + ('data', runtime_functions.malloc.call(self.underlyingWrapperType.getBytecount())), + ) + ) + ) ) def convert_setitem(self, context, expr, index, item): diff --git a/typed_python/compiler/type_wrappers/none_wrapper.py b/typed_python/compiler/type_wrappers/none_wrapper.py index b7c25e9d3..4399e2741 100644 --- a/typed_python/compiler/type_wrappers/none_wrapper.py +++ b/typed_python/compiler/type_wrappers/none_wrapper.py @@ -29,6 +29,9 @@ def __init__(self): def getCompileTimeConstant(self): return None + def isIterable(self): + return False + def convert_default_initialize(self, context, target): pass diff --git a/typed_python/compiler/type_wrappers/one_of_wrapper.py b/typed_python/compiler/type_wrappers/one_of_wrapper.py index 822c77aa2..e39867c5f 100644 --- a/typed_python/compiler/type_wrappers/one_of_wrapper.py +++ b/typed_python/compiler/type_wrappers/one_of_wrapper.py @@ -57,6 +57,34 @@ def getNativeLayoutType(self): def convert_which_native(self, expr): return expr.ElementPtrIntegers(0, 0).load() + def get_iteration_expressions(self, context, expr): + itExprs = None + + for ix in range(len(self.typeRepresentation.Types)): + T = self.typeRepresentation.Types[ix] + + if typeWrapper(T).isIterable == "Maybe": + return + elif typeWrapper(T).isIterable is False: + pass + else: + # we don't know how to union two sets of iteration expressions + if itExprs is not None: + return None + + itExprs = typeWrapper(T).get_iteration_expressions(context, expr.refAs(ix)) + itExprIx = ix + + if itExprs is not None: + with context.ifelse(self.convert_which_native(expr.expr).eq(itExprIx)) as (ifTrue, ifFalse): + with ifFalse: + context.pushException( + TypeError, + "Instance of type {self.typeRepresentation.__name__} is not iterable" + ) + + return itExprs + def unwrap(self, context, expr, generator): """Call 'generator' on 'expr' cast down to each subtype and combine the results. """ diff --git a/typed_python/compiler/type_wrappers/runtime_functions.py b/typed_python/compiler/type_wrappers/runtime_functions.py index 9d9ead81c..026fee5a7 100644 --- a/typed_python/compiler/type_wrappers/runtime_functions.py +++ b/typed_python/compiler/type_wrappers/runtime_functions.py @@ -368,6 +368,15 @@ def unaryPyobjCallTarget(name, retType=Void.pointer()): Void.pointer() ) +call_pyobj_and_raise = externalCallTarget( + "nativepython_runtime_call_pyobj_and_raise", + Void, + Int64, + Int64, + varargs=True, + canThrow=True +) + call_pyobj = externalCallTarget( "nativepython_runtime_call_pyobj", Void.pointer(), diff --git a/typed_python/compiler/type_wrappers/string_wrapper.py b/typed_python/compiler/type_wrappers/string_wrapper.py index 585ac92db..0dc6f82cd 100644 --- a/typed_python/compiler/type_wrappers/string_wrapper.py +++ b/typed_python/compiler/type_wrappers/string_wrapper.py @@ -21,6 +21,7 @@ from typed_python.compiler.type_wrappers.typed_list_masquerading_as_list_wrapper import TypedListMasqueradingAsList import typed_python.compiler.type_wrappers.runtime_functions as runtime_functions from typed_python.compiler.type_wrappers.bound_method_wrapper import BoundMethodWrapper +from typed_python.compiler.conversion_level import ConversionLevel import typed_python.compiler.native_ast as native_ast import typed_python.compiler @@ -1010,7 +1011,31 @@ def _can_convert_to_type(self, targetType, conversionLevel): Float32, Int8, Int16, Int32, UInt8, UInt16, UInt32, UInt64, float, int, bool, str ) + def convert_to_self_with_target(self, context, targetVal, sourceVal, level: ConversionLevel, mayThrowOnFailure=False): + if sourceVal.expr_type.typeRepresentation is str: + targetVal.convert_copy_initialize(targetVal) + return context.constant(True) + + if level.isNewOrHigher(): + if not sourceVal.isReference: + sourceVal = context.pushMove(sourceVal) + + return context.pushPod( + bool, + runtime_functions.np_try_pyobj_to_str.call( + sourceVal.expr.cast(VoidPtr), + targetVal.expr.cast(VoidPtr), + context.getTypePointer(sourceVal.expr_type.typeRepresentation) + ) + ) + + return super().convert_to_self_with_target(context, targetVal, sourceVal, level, mayThrowOnFailure) + def convert_to_type_with_target(self, context, instance, targetVal, conversionLevel, mayThrowOnFailure=False): + if targetVal.expr_type.typeRepresentation is str: + targetVal.convert_copy_initialize(instance) + return context.constant(True) + if not conversionLevel.isNewOrHigher(): return super().convert_to_type_with_target(context, instance, targetVal, conversionLevel, mayThrowOnFailure) diff --git a/typed_python/compiler/type_wrappers/tuple_of_wrapper.py b/typed_python/compiler/type_wrappers/tuple_of_wrapper.py index d9bf75774..f1f7488b4 100644 --- a/typed_python/compiler/type_wrappers/tuple_of_wrapper.py +++ b/typed_python/compiler/type_wrappers/tuple_of_wrapper.py @@ -162,16 +162,23 @@ def initializeEmptyListExpr(self, out, length): runtime_functions.malloc.call(native_ast.const_int_expr(28)) .cast(self.tupleTypeWrapper.getNativeLayoutType()) ) >> - out.expr.load().ElementPtrIntegers(0, 4).store( - runtime_functions.malloc.call( - length.nonref_expr - .mul(native_ast.const_int_expr(self.underlyingWrapperType.getBytecount())) - ).cast(native_ast.UInt8Ptr) - ) >> - out.expr.load().ElementPtrIntegers(0, 0).store(native_ast.const_int_expr(1)) >> - out.expr.load().ElementPtrIntegers(0, 1).store(native_ast.const_int32_expr(-1)) >> - out.expr.load().ElementPtrIntegers(0, 2).store(native_ast.const_int32_expr(0)) >> - out.expr.load().ElementPtrIntegers(0, 3).store(length.nonref_expr.cast(native_ast.Int32)) + out.expr.load().ElementPtrIntegers(0).store( + native_ast.Expression.MakeStruct( + args=( + ('refcount', native_ast.const_int_expr(1)), + ('hash_cache', native_ast.const_int32_expr(-1)), + ('count', native_ast.const_int32_expr(0)), + ('reserved', length.nonref_expr.cast(native_ast.Int32)), + ( + 'data', + runtime_functions.malloc.call( + length.nonref_expr + .mul(native_ast.const_int_expr(self.underlyingWrapperType.getBytecount())) + ) + ), + ) + ) + ) ) @@ -318,6 +325,9 @@ def __init__(self, t): ('data', native_ast.UInt8Ptr) ), name='TupleOfLayout' if self.is_tuple else 'ListOfLayout').pointer() + def isIterable(self): + return True + def has_fastnext_iter(self): """If we call '__iter__' on instances of this type, will they support __fastnext__?""" return True diff --git a/typed_python/compiler/type_wrappers/tuple_wrapper.py b/typed_python/compiler/type_wrappers/tuple_wrapper.py index 0d1651b68..b5801d5c2 100644 --- a/typed_python/compiler/type_wrappers/tuple_wrapper.py +++ b/typed_python/compiler/type_wrappers/tuple_wrapper.py @@ -15,7 +15,8 @@ from typed_python.compiler.type_wrappers.wrapper import Wrapper from typed_python.compiler.merge_type_wrappers import mergeTypes from typed_python import ( - _types, Int32, Tuple, NamedTuple, Function, Dict, Set, ConstDict, ListOf, TupleOf + _types, Int32, Tuple, NamedTuple, Function, Dict, Set, ConstDict, ListOf, + TupleOf, PointerTo, pointerTo, TypeFunction, OneOf, Class, Member, Final ) import typed_python._types from typed_python.compiler.conversion_level import ConversionLevel @@ -195,6 +196,9 @@ def __init__(self, t): self._is_pod = all(typeWrapper(possibility).is_pod for possibility in self.subTypeWrappers) self.is_default_constructible = _types.is_default_constructible(t) + def isIterable(self): + return True + @property def unionType(self): if self._unionType is None and self.typeRepresentation.ElementTypes: @@ -220,6 +224,23 @@ def is_pod(self): def getNativeLayoutType(self): return self.layoutType + def convert_attribute(self, context, instance, attribute): + if attribute in ["__iter__"]: + return instance.changeType(BoundMethodWrapper.Make(self, attribute)) + + return super().convert_attribute(context, instance, attribute) + + def convert_method_call(self, context, instance, methodname, args, kwargs): + if methodname == '__iter__' and not args: + return typeWrapper(TupleIterator(self.typeRepresentation)).convert_type_call( + context, + None, + [], + dict(pos=context.constant(-1), tup=instance) + ) + + return super().convert_method_call(context, instance, methodname, args, kwargs) + def convert_initialize_from_args(self, context, target, *args): assert len(args) <= len(self.byteOffsets) @@ -495,10 +516,7 @@ def convert_to_self_with_target(self, context, targetVal, sourceVal, conversionL ) ) - return sourceVal.convert_to_type( - object, - ConversionLevel.Signature - ).convert_to_type_with_target(targetVal, conversionLevel, mayThrowOnFailure) + return super().convert_to_self_with_target(context, targetVal, sourceVal, conversionLevel, mayThrowOnFailure) def generateConvertOtherTupToSelf(self, context, _, targetVal, sourceVal, conversionLevel): convertedValues = [] @@ -608,6 +626,9 @@ def __init__(self, t): self.namesToIndices = {n: i for i, n in enumerate(t.ElementNames)} self.namesToTypes = {n: t.ElementTypes[i] for i, n in enumerate(t.ElementNames)} + def isIterable(self): + return True + def has_fastnext_iter(self): if self.isSubclassOfNamedTuple: return "__iter__" in self.typeRepresentation.__dict__ @@ -869,3 +890,24 @@ def convert_bin_op_reverse(self, context, r, op, l, inplace): return self.convert_method_call(context, r, magic, (l,), {}) return super().convert_bin_op_reverse(context, r, op, l, inplace) + + +@TypeFunction +def TupleIterator(T): + EltT = OneOf(*T.ElementTypes) + + class TupleIterator(Class, Final, __name__=f"TupleIterator({T.__name__})"): + pos = Member(int, nonempty=True) + elt = Member(EltT) + tup = Member(T, nonempty=True) + + def __fastnext__(self): + self.pos += 1 + + if self.pos < len(self.tup): + self.elt = self.tup[self.pos] + return pointerTo(self).elt + else: + return PointerTo(EltT)() + + return TupleIterator diff --git a/typed_python/compiler/type_wrappers/wrapper.py b/typed_python/compiler/type_wrappers/wrapper.py index 5ad007c9a..9d2d745ef 100644 --- a/typed_python/compiler/type_wrappers/wrapper.py +++ b/typed_python/compiler/type_wrappers/wrapper.py @@ -665,21 +665,6 @@ def convert_to_type_with_target(self, context, expr, targetVal, level: Conversio assert isinstance(level, ConversionLevel) assert targetVal.isReference - if level.isNewOrHigher() and targetVal.expr_type.typeRepresentation is str: - if not expr.isReference: - expr = context.pushMove(expr) - - expr = expr.convert_to_type(object, ConversionLevel.Signature) - - return context.pushPod( - bool, - runtime_functions.np_try_pyobj_to_str.call( - expr.expr.cast(VoidPtr), - targetVal.expr.cast(VoidPtr), - context.getTypePointer(expr.expr_type.typeRepresentation) - ) - ) - return targetVal.expr_type.convert_to_self_with_target(context, targetVal, expr, level, mayThrowOnFailure) def convert_to_self_with_target(self, context, targetVal, sourceVal, level: ConversionLevel, mayThrowOnFailure=False): diff --git a/typed_python/deep_bytecount_test.py b/typed_python/deep_bytecount_test.py index 2b1dfc03e..dff869b88 100644 --- a/typed_python/deep_bytecount_test.py +++ b/typed_python/deep_bytecount_test.py @@ -19,6 +19,7 @@ ) +@pytest.mark.group_one def test_deep_bytecount_listof(): l = ListOf(int)() @@ -27,6 +28,7 @@ def test_deep_bytecount_listof(): assert sz * 8 <= deepBytecount(l) <= 8 * sz + 112 +@pytest.mark.group_one def test_deep_bytecount_listof_aliasing(): NT = NamedTuple(a=ListOf(int), b=ListOf(int)) @@ -39,6 +41,7 @@ def test_deep_bytecount_listof_aliasing(): assert 1000 * 8 <= deepBytecount(x) <= 1000 * 8 + 112 +@pytest.mark.group_one def test_deep_bytecount_sees_into_basic_python_objects(): l = ListOf(int)() l.resize(1000) @@ -58,6 +61,7 @@ def __init__(self, x): assert deepBytecount((l, l, l)) < 9000 +@pytest.mark.group_one def test_deep_bytecount_sees_into_Class_objects(): class C(Class): x = Member(ListOf(int)) @@ -65,13 +69,16 @@ class C(Class): assert deepBytecount(C(x=ListOf(int)(range(1000)))) > 1000 +@pytest.mark.group_one def test_deep_bytecount_sees_into_Dict_objects(): assert deepBytecount(Dict(int, ListOf(int))({1: ListOf(int)(range(1000))})) +@pytest.mark.group_one def test_deep_bytecount_sees_into_ConstDict_objects(): assert deepBytecount(ConstDict(int, ListOf(int))({1: ListOf(int)(range(1000))})) +@pytest.mark.group_one def test_deep_bytecount_of_empty_constDict(): assert deepBytecount(ConstDict(int, int)()) == 0 diff --git a/typed_python/deepcopy_test.py b/typed_python/deepcopy_test.py index 2a6305c25..22e4864ed 100644 --- a/typed_python/deepcopy_test.py +++ b/typed_python/deepcopy_test.py @@ -81,26 +81,32 @@ def checkDeepcopySimple(obj, requiresSlab, objectIsSlabRoot=False): assert currentMemUsageMb() - m0 < 1.0 +@pytest.mark.group_one def test_deepcopy_pod_tuple(): checkDeepcopySimple(Tuple(int, int)(), False) +@pytest.mark.group_one def test_deepcopy_named_tuple(): checkDeepcopySimple(NamedTuple(x=int, y=str)(x=10, y="hi"), True) +@pytest.mark.group_one def test_deepcopy_listof(): checkDeepcopySimple(ListOf(int)(range(1000)), True, True) +@pytest.mark.group_one def test_deepcopy_setof(): checkDeepcopySimple(Set(int)(range(1000)), True, True) +@pytest.mark.group_one def test_deepcopy_tupleof(): checkDeepcopySimple(TupleOf(int)(range(1000)), True, True) +@pytest.mark.group_one def test_deepcopy_oneof(): checkDeepcopySimple( TupleOf(OneOf(None, "hi", int))(list(range(1000)) + ["hi", None, "hi", 3]), @@ -108,38 +114,47 @@ def test_deepcopy_oneof(): ) +@pytest.mark.group_one def test_deepcopy_pystring(): checkDeepcopySimple("hi", False, True) +@pytest.mark.group_one def test_deepcopy_tupleof_str(): checkDeepcopySimple(TupleOf(str)(["hi"]), True, True) +@pytest.mark.group_one def test_deepcopy_empty_tup(): checkDeepcopySimple((), False) +@pytest.mark.group_one def test_deepcopy_pytuple(): checkDeepcopySimple((1, 2, 3), False) +@pytest.mark.group_one def test_deepcopy_pylist(): checkDeepcopySimple([1, 2, 3], False) +@pytest.mark.group_one def test_deepcopy_pydict(): checkDeepcopySimple({1: 2, 3: 4}, False) +@pytest.mark.group_one def test_deepcopy_pyset(): checkDeepcopySimple({1, 2, 3, 4}, False) +@pytest.mark.group_one def test_untyped_holding_typed(): checkDeepcopySimple([ListOf(int)(range(100))], True) +@pytest.mark.group_one def test_deepcopy_Class(): class C(Class): x = Member(ListOf(int)) @@ -153,6 +168,7 @@ def __eq__(self, other): checkDeepcopySimple(C(x=ListOf(int)(range(1000))), True, True) +@pytest.mark.group_one def test_deepcopy_PySubClass(): class C(NamedTuple(x=int)): pass @@ -160,6 +176,7 @@ class C(NamedTuple(x=int)): checkDeepcopySimple(ListOf(C)([C(x=10)]), True, True) +@pytest.mark.group_one def test_deepcopy_PySubClassWithSlabStuff(): class C(NamedTuple(x=ListOf(int))): pass @@ -167,6 +184,7 @@ class C(NamedTuple(x=ListOf(int))): checkDeepcopySimple(C(x=ListOf(int)([10])), True, False) +@pytest.mark.group_one def test_deepcopy_class(): class C: def __init__(self, x): @@ -178,6 +196,7 @@ def __eq__(self, other): checkDeepcopySimple(C(10), False, True) +@pytest.mark.group_one def test_holding_interior_item_keeps_slab_alive(): initSlabBytes = totalBytesAllocatedInSlabs() @@ -197,6 +216,7 @@ def test_holding_interior_item_keeps_slab_alive(): assert totalBytesAllocatedInSlabs() == initSlabBytes +@pytest.mark.group_one def test_deepcopy_with_external_pyobj_doesnt_leak(): mem = currentMemUsageMb() @@ -206,6 +226,7 @@ def test_deepcopy_with_external_pyobj_doesnt_leak(): assert currentMemUsageMb() - mem < 10 +@pytest.mark.group_one def test_deepcopy_with_tuple_doesnt_leak(): mem = currentMemUsageMb() @@ -215,6 +236,7 @@ def test_deepcopy_with_tuple_doesnt_leak(): assert currentMemUsageMb() - mem < 10 +@pytest.mark.group_one def test_deepcopy_with_mutually_recursive_objects_doesnt_leak(): mem = currentMemUsageMb() @@ -229,6 +251,7 @@ def test_deepcopy_with_mutually_recursive_objects_doesnt_leak(): assert currentMemUsageMb() - mem < 10 +@pytest.mark.group_one def test_deepcopy_with_Class(): initSlabBytes = totalBytesAllocatedInSlabs() @@ -255,6 +278,7 @@ class D(C): assert totalBytesAllocatedInSlabs() == initSlabBytes +@pytest.mark.group_one def test_deepcopy_with_Dict(): initSlabBytes = totalBytesAllocatedInSlabs() mem = currentMemUsageMb() @@ -276,6 +300,7 @@ def test_deepcopy_with_Dict(): assert totalBytesAllocatedInSlabs() == initSlabBytes +@pytest.mark.group_one def test_deepcopy_with_Set(): initSlabBytes = totalBytesAllocatedInSlabs() mem = currentMemUsageMb() @@ -294,6 +319,7 @@ def test_deepcopy_with_Set(): assert totalBytesAllocatedInSlabs() == initSlabBytes +@pytest.mark.group_one def test_deepcopy_with_ConstDict(): initSlabBytes = totalBytesAllocatedInSlabs() mem = currentMemUsageMb() @@ -312,6 +338,7 @@ def test_deepcopy_with_ConstDict(): assert totalBytesAllocatedInSlabs() == initSlabBytes +@pytest.mark.group_one def test_deepcopy_with_Alternative(): initSlabBytes = totalBytesAllocatedInSlabs() mem = currentMemUsageMb() @@ -335,6 +362,7 @@ def test_deepcopy_with_Alternative(): assert totalBytesAllocatedInSlabs() == initSlabBytes +@pytest.mark.group_one def test_see_slabs(): list1 = deepcopyContiguous(ListOf(int)(range(1000)), trackInternalTypes=True) list2 = deepcopyContiguous(ListOf(int)(range(1000)), trackInternalTypes=True) @@ -347,6 +375,7 @@ def test_see_slabs(): assert slab.allocCount() +@pytest.mark.group_one def test_deepcopy_class_with_dual_references(): class C(Class): x = Member(Dict(int, int)) @@ -363,6 +392,7 @@ class C(Class): assert refcount(c2.x) == 3 +@pytest.mark.group_one def test_bytes_on_free_store_basic(): bytecount0 = totalBytesAllocatedOnFreeStore() @@ -387,6 +417,7 @@ def test_bytes_on_free_store_basic(): assert bytecount0 == totalBytesAllocatedOnFreeStore() +@pytest.mark.group_one def test_deepcopy_perf(): x = ListOf(str)() @@ -410,6 +441,7 @@ def test_deepcopy_perf(): print("deepcopyContiguous", t1 - t0) +@pytest.mark.group_one def test_deepcopy_typeMap(): aTup = ([1], [2]) @@ -422,6 +454,7 @@ def mapper(aLst): assert res[1] == [2, 2] +@pytest.mark.group_one def test_deepcopy_typeMap_typed(): class C(Class): x = Member(int) @@ -434,6 +467,7 @@ def mapper(i): assert res.x == 11 +@pytest.mark.group_one def test_deepcopy_typeMap_baseclass(): class C(object): def __init__(self, x): @@ -450,6 +484,7 @@ def mapper(c): assert res.x == 11 +@pytest.mark.group_one def test_deepcopy_typeMap_baseclass_tp_type(): class C(Class): x = Member(int) @@ -465,6 +500,7 @@ def mapper(c): assert res.x == 11 +@pytest.mark.group_one def test_deepcopy_empty_alternatives(): X = Alternative("X", A=dict(), B=dict()) Y = Alternative("Y", C=dict(x=X)) @@ -472,6 +508,7 @@ def test_deepcopy_empty_alternatives(): print(deepcopy(y)) +@pytest.mark.group_one def test_deepcopy_class_subclass(): class Base(Class): pass @@ -484,12 +521,14 @@ class Child(Base): deepcopyContiguous(x) +@pytest.mark.group_one def test_deepcopy_tuple_of_strings(): for i in range(100): x = ListOf(OneOf(str, float))(['h'] * i) deepcopyContiguous(x) +@pytest.mark.group_one def test_deepcopy_numpy_array(): x = numpy.array([1, 2, 3]) @@ -513,6 +552,7 @@ def __setstate__(self, state): self.state = state[0] +@pytest.mark.group_one def test_deepcopy_class_with_custom_reduce(): c = ClassWithReduce("state") @@ -532,6 +572,7 @@ def setState(self, state): self.state = state[0] +@pytest.mark.group_one def test_deepcopy_class_with_custom_setState(): c = ClassWithCustomSetState("state") @@ -555,6 +596,7 @@ def __setitem__(self, x, y): self.kvs[x] = y +@pytest.mark.group_one def test_deepcopy_class_with_custom_reduce_iterators(): c = ClassWithIterators() diff --git a/typed_python/forward_types_test.py b/typed_python/forward_types_test.py index 7fec65b49..692599e48 100644 --- a/typed_python/forward_types_test.py +++ b/typed_python/forward_types_test.py @@ -22,6 +22,7 @@ class ForwardTypesTests(unittest.TestCase): + @pytest.mark.group_one def test_basic_forward_type_resolution(self): f = Forward("f") T = TupleOf(f) @@ -32,6 +33,7 @@ def test_basic_forward_type_resolution(self): self.assertEqual(f.get(), int) + @pytest.mark.group_one def test_class_in_forward(self): class C(Class): x = Member(int) @@ -41,6 +43,7 @@ class C(Class): Fwd(C()) + @pytest.mark.group_one def test_recursive_forwards(self): Value = Forward("Value") Value.define(OneOf( @@ -48,6 +51,7 @@ def test_recursive_forwards(self): ConstDict(str, Value) )) + @pytest.mark.group_one def test_forward_type_resolution_sequential(self): F0 = Forward("f0") T0 = TupleOf(F0) @@ -60,6 +64,7 @@ def test_forward_type_resolution_sequential(self): self.assertEqual(T1.__name__, "TupleOf(TupleOf(int))") + @pytest.mark.group_one def test_recursive_alternative(self): List = Forward("List") List = List.define(Alternative( @@ -77,6 +82,7 @@ def test_recursive_alternative(self): self.assertEqual(list(lst.unpack()), list(reversed(range(100)))) + @pytest.mark.group_one def test_mutually_recursive_classes(self): B0 = Forward("B") @@ -95,6 +101,7 @@ class B(Class): self.assertTrue(a.bvals[0].avals[0] == a) + @pytest.mark.group_one def test_recursives_held_infinitely_throws(self): X = Forward("X") @@ -107,6 +114,7 @@ def test_recursives_held_infinitely_throws(self): with self.assertRaisesRegex(Exception, "type-containment cycle"): X = X.define(Tuple(X)) + @pytest.mark.group_one def test_tuple_of_one_of(self): X = Forward("X") T = TupleOf(OneOf(None, X)) @@ -123,6 +131,7 @@ def test_tuple_of_one_of(self): self.assertEqual(anotherX[0], anX) + @pytest.mark.group_one def test_deep_forwards_work(self): X = Forward("X") X = X.define(TupleOf(TupleOf(TupleOf(TupleOf(OneOf(None, X)))))) @@ -135,6 +144,7 @@ def test_deep_forwards_work(self): self.assertEqual(anotherX[0][0][0][0], anX) + @pytest.mark.group_one def test_recursive_dicts(self): D = Forward("D") D = D.define(Dict(int, OneOf(int, D))) @@ -150,6 +160,7 @@ def test_recursive_dicts(self): self.assertEqual(dInst, dInst[10]) + @pytest.mark.group_one def test_forward_types_not_instantiatable(self): F = Forward("int") F.define(int) @@ -157,6 +168,7 @@ def test_forward_types_not_instantiatable(self): with self.assertRaisesRegex(Exception, "Can't construct"): F(10) + @pytest.mark.group_one def test_recursive_alternatives(self): X = Forward("X") X = X.define( @@ -172,6 +184,7 @@ def test_recursive_alternatives(self): self.assertEqual(anX.y, 21) self.assertTrue(anX.x.matches.B) + @pytest.mark.group_one def test_recursive_oneof(self): OneOfTupleOfSelf = Forward("OneOfTupleOfSelf") OneOfTupleOfSelf = OneOfTupleOfSelf.define(OneOf(None, TupleOf(OneOfTupleOfSelf))) @@ -186,6 +199,7 @@ def test_recursive_oneof(self): self.assertTrue(isRecursive(TO.ElementType)) self.assertEqual(TO.ElementType.__qualname__, "OneOf(None, TO)") + @pytest.mark.group_one def test_forward_types_identity_container(self): for ContainerKind in [TupleOf]: module = Module("M") @@ -196,6 +210,7 @@ def test_forward_types_identity_container(self): self.assertEqual(type(aRecursiveThing), module.RecursiveThing.Types[1]) self.assertEqual(type(aRecursiveThing), ContainerKind(module.RecursiveThing)) + @pytest.mark.group_one def test_forward_types_identity_dict(self): for DictKind in [Dict, ConstDict]: module = Module("M") @@ -207,6 +222,7 @@ def test_forward_types_identity_dict(self): aRecursiveThing = module.RecursiveThing({None: 1}) self.assertEqual(type(aRecursiveThing), DictKind(module.RecursiveThing, int)) + @pytest.mark.group_one def test_forward_types_twice(self): module = Module("M") module.RecursiveThing = OneOf( @@ -222,6 +238,7 @@ def test_forward_types_twice(self): module.RecursiveThing.Types[2].ValueType, TupleOf(module.RecursiveThing) ) + @pytest.mark.group_one def test_forwards_resolve_to_forward_in_cycle(self): Fs = [Forward(f"f{i}") for i in range(4)] @@ -232,6 +249,7 @@ def test_forwards_resolve_to_forward_in_cycle(self): with self.assertRaisesRegex(TypeError, "Can't resolve a forward to itself!"): Fs[3].define(Fs[0]) + @pytest.mark.group_one def test_forwards_resolve_to_forward(self): Intermediate1 = Forward("Intermediate1") Intermediate2 = Forward("Intermediate2") @@ -248,6 +266,7 @@ def test_forwards_resolve_to_forward(self): T0(((1, 2), (3, 4))) + @pytest.mark.group_one def test_check_recursive_group(self): module = Module("M") @@ -264,6 +283,7 @@ class B(Class): self.assertTrue(A in recursiveTypeGroup(A)) self.assertTrue(B in recursiveTypeGroup(A)) + @pytest.mark.group_one def test_call_function_with_unresolved_forward_fails(self): X = Forward("X") diff --git a/typed_python/function_signature_test.py b/typed_python/function_signature_test.py index 193442e93..15bf3d728 100644 --- a/typed_python/function_signature_test.py +++ b/typed_python/function_signature_test.py @@ -17,6 +17,7 @@ class FunctionSignatureTest(unittest.TestCase): + @pytest.mark.group_one def test_function_with_signature(self): @Function def f(x) -> lambda X: ListOf(X): @@ -24,6 +25,7 @@ def f(x) -> lambda X: ListOf(X): assert f.overloads[0].signatureFunction(int) == ListOf(int) + @pytest.mark.group_one def test_function_signature_casts(self): @Function def f(x) -> lambda X: int: @@ -31,6 +33,7 @@ def f(x) -> lambda X: int: assert isinstance(f(1.0), int) + @pytest.mark.group_one def test_function_signature_result_not_convertible(self): def notAType(): pass @@ -42,6 +45,7 @@ def f(x) -> lambda X: notAType: with self.assertRaisesRegex(Exception, "Cannot convert .* to"): f(10) + @pytest.mark.group_one def test_function_signature_sig_func_throws(self): def sigFunc(X): raise Exception("Error in signature function") @@ -53,6 +57,7 @@ def f(x) -> sigFunc: with self.assertRaisesRegex(Exception, "Error in signature function"): f(10) + @pytest.mark.group_one def test_function_signature_sig_func_wrong_number_of_arguments(self): def sigFunc(X, Y): return X @@ -64,6 +69,7 @@ def f(x) -> sigFunc: with self.assertRaisesRegex(Exception, "missing 1 required positional argument: 'Y'"): f(10) + @pytest.mark.group_one def test_function_signature_compiles(self): def sigFunc(X, Y): return X @@ -87,6 +93,7 @@ def callFAsObject(x: object, y): assert callFAsObject.resultTypeFor(int, float).typeRepresentation is object assert callFAsObject(1, 1.5) == 2 + @pytest.mark.group_one def test_compile_function_signature_with_value(self): @Entrypoint def f(x, y) -> lambda X, Y: 1: @@ -99,6 +106,7 @@ def callF(x, y): assert callF.resultTypeFor(int, float).typeRepresentation.Value == 1 assert callF(1, 1.5) == 1 + @pytest.mark.group_one def test_compile_function_with_oneof(self): @Entrypoint def f(x) -> lambda X: X: @@ -110,6 +118,7 @@ def callF(x): assert callF.resultTypeFor(OneOf(int, float)).typeRepresentation is object + @pytest.mark.group_one def test_compile_function_with_overloads(self): @Entrypoint def f(x: int, y: float) -> lambda X, Y: X: @@ -131,6 +140,7 @@ def callF(x, y): assert callF(1, 1.5) == 1 assert callF(1.5, 1) == 1.5 + @pytest.mark.group_one def test_compile_function_with_overloads_indeterminate(self): @Entrypoint def f(x: int, y) -> lambda X, Y: Y: @@ -151,6 +161,7 @@ def callF(x, y: object): assert callF(1, 1.5) == 1.0 assert callF(1.5, 1) == 1 + @pytest.mark.group_one def test_nocompile_function_with_signatures(self): @NotCompiled def f(x, y) -> lambda X, Y: X: @@ -174,6 +185,7 @@ def callFAsObject(x, y: object): assert callFAsObject(1, 1.5) == 1 assert callFAsObject(1.5, 1) == 1.5 + @pytest.mark.group_one def test_class_function_signatures_work(self): class AClass(Class): def f(self, x) -> lambda SELF, X: X: @@ -181,6 +193,7 @@ def f(self, x) -> lambda SELF, X: X: assert AClass().f(10) == 10 + @pytest.mark.group_one def test_compiling_final_class_method_with_signature(self): class AClass(Class, Final): def f(self, x, y) -> lambda SELF, X, Y: Y: @@ -192,6 +205,7 @@ def callIt(x, y): assert callIt.resultTypeFor(int, float).typeRepresentation is float + @pytest.mark.group_one def test_compiling_final_class_method_with_signature_and_overloads(self): class AClass(Class, Final): def f(self, x: float, y) -> lambda SELF, X, Y: Y: @@ -206,6 +220,7 @@ def callIt(x, y): assert callIt.resultTypeFor(OneOf(int, float), float).typeRepresentation is float + @pytest.mark.group_one def test_compiling_nonfinal_signature_methods(self): class BaseClass(Class): def f(self, x, y) -> lambda SELF, X, Y: Y: @@ -229,6 +244,7 @@ def callItAsBase(inst: BaseClass, x, y): assert callItAsBase(BaseClass(), 1.5, 1) == 1 assert callItAsBase(ChildClass(), 1.5, 1) == 2 + @pytest.mark.group_one def test_compiling_nonfinal_signature_methods_with_type_change(self): class BaseClass(Class): def f(self, x, y) -> lambda SELF, X, Y: Y: @@ -267,6 +283,7 @@ def callItAsBase(inst: BaseClass, x, y): with self.assertRaisesRegex(Exception, "promised a return type"): assert callItAsBase(ChildClass(), 1.5, 1) == 2 + @pytest.mark.group_one def test_conflicting_types_dont_affect_refined_filters(self): class BaseClass(Class): def f(self, x: int) -> int: @@ -281,6 +298,7 @@ def f(self, x) -> str: with self.assertRaisesRegex(Exception, "promised a return type"): ChildClass().f(0) + @pytest.mark.group_one def test_compiler_honors_elided_suclass_return_type(self): class BaseClass(Class): def f(self) -> int: @@ -304,6 +322,7 @@ def callItAsBase(c: BaseClass): assert callItAsBase(BaseClass()) == 1 assert callItAsBase(ChildClass()) == 2 + @pytest.mark.group_one def test_dispatch_to_function_overload(self): @Function def f(x: str): @@ -324,6 +343,7 @@ def callF(x: OneOf(int, str)): assert callF("a") == "str" assert callF(0) == "int" + @pytest.mark.group_one def test_invalid_multi_dispatch(self): class BaseClass(Class): def f(self, x) -> int: @@ -357,6 +377,7 @@ def f(self, x: int) -> int: assert callIt(ChildChildClass(), 1) == 1 + @pytest.mark.group_one def test_type_signature_conflict(self): class A(Class): pass @@ -479,6 +500,7 @@ def callIt(c: T1, x: T2): with self.assertRaisesRegex(TypeError, "proposed to return 'str'"): callItAs(ChildClass, A)(ChildClass(), Both()) + @pytest.mark.group_one def test_type_inference_classes(self): class A(Class): pass @@ -494,6 +516,7 @@ def f(x): assert f.resultTypeFor(A).typeRepresentation != ListOf(A) assert f.resultTypeFor(B).typeRepresentation == ListOf(B) + @pytest.mark.group_one def test_typeof(self): @Function def f(x) -> TypeOf(lambda x: x + x): @@ -502,6 +525,7 @@ def f(x) -> TypeOf(lambda x: x + x): assert f.resultTypeFor(int).typeRepresentation == int assert f.resultTypeFor(float).typeRepresentation == float + @pytest.mark.group_one def test_typeof_with_class_arg(self): class A(Class): def f(self, x) -> float: @@ -514,6 +538,7 @@ def f(a, x) -> TypeOf(lambda a, x: a.f(x)): assert f.resultTypeFor(A, int).typeRepresentation == float assert f.resultTypeFor(A, float).typeRepresentation == float + @pytest.mark.group_one def test_typeof_with_mutual_recursion(self): class A(Class): def f(self, x) -> TypeOf(lambda self, x: B().f(x - 1) + 1 if x > 0 else x): diff --git a/typed_python/function_types_test.py b/typed_python/function_types_test.py index 1ae9e947c..70d4aefde 100644 --- a/typed_python/function_types_test.py +++ b/typed_python/function_types_test.py @@ -21,6 +21,7 @@ def thisIsAFunction(): class NativeFunctionTypesTests(unittest.TestCase): + @pytest.mark.group_one def test_function_names_correct(self): assert type(thisIsAFunction).__name__ == 'thisIsAFunction' assert type(thisIsAFunction).__module__ == NativeFunctionTypesTests.__module__ @@ -30,6 +31,7 @@ def test_function_names_correct(self): assert thisIsAFunction.__module__ == NativeFunctionTypesTests.__module__ assert thisIsAFunction.__qualname__ == "thisIsAFunction" + @pytest.mark.group_one def test_create_simple_function(self): @Function def f(x: int) -> int: @@ -53,6 +55,7 @@ def f(x: int) -> int: self.assertEqual(o.args[0].isStarArg, False) self.assertEqual(o.args[0].isKwarg, False) + @pytest.mark.group_one def test_create_function_with_kwargs_and_star_args_and_defaults(self): @Function def f(x: int, @@ -72,6 +75,7 @@ def f(x: int, self.assertEqual([a.isStarArg for a in o.args], [False, False, False, True, False]) self.assertEqual([a.isKwarg for a in o.args], [False, False, False, False, True]) + @pytest.mark.group_one def test_instantiate_function_type_with_untyped_closure(self): x = 10 @@ -84,6 +88,7 @@ def f(): # an empty cell, which throws a name error type(f)()() + @pytest.mark.group_one def test_instantiate_function_type_with_entrypointed_closure(self): x = 10 @@ -96,6 +101,7 @@ def f(): with self.assertRaises(NameError): fInst() + @pytest.mark.group_one def test_instantiate_function_type_with_typed_closure(self): @Entrypoint def makeF(x): diff --git a/typed_python/lib/datetime/chrono_test.py b/typed_python/lib/datetime/chrono_test.py index 5cfab60bc..0e3f6f930 100644 --- a/typed_python/lib/datetime/chrono_test.py +++ b/typed_python/lib/datetime/chrono_test.py @@ -17,6 +17,7 @@ class TestChrono(unittest.TestCase): + @pytest.mark.group_one def test_is_leap_year_valid(self): leap_years = [ 2000, @@ -37,12 +38,14 @@ def test_is_leap_year_valid(self): for year in leap_years: assert Chrono.is_leap_year(year), year + @pytest.mark.group_one def test_is_leap_year_invalid(self): not_leap_years = [1700, 1800, 1900, 1997, 1999, 2100, 2022] for year in not_leap_years: assert not Chrono.is_leap_year(year), year + @pytest.mark.group_one def test_is_date_valid(self): # y, m, d dates = [(1997, 1, 1), (2020, 2, 29)] # random date # Feb 29 on leap year @@ -50,6 +53,7 @@ def test_is_date_valid(self): for date in dates: assert Chrono.is_valid_date(date[0], date[1], date[2]), date + @pytest.mark.group_one def test_is_date_invalid(self): # y, m, d dates = [ @@ -70,6 +74,7 @@ def test_is_date_invalid(self): for date in dates: assert not Chrono.is_valid_date(date[0], date[1], date[2]), date + @pytest.mark.group_one def test_is_time_valid(self): # h, m, s times = [ @@ -80,6 +85,7 @@ def test_is_time_valid(self): for time in times: assert Chrono.is_valid_time(time[0], time[1], time[2]), time + @pytest.mark.group_one def test_is_time_invalid(self): # h, m, s times = [ @@ -94,6 +100,7 @@ def test_is_time_invalid(self): for time in times: assert not Chrono.is_valid_time(time[0], time[1], time[2]), time + @pytest.mark.group_one def test_days_from_civil(self): for (year, month, day) in [(1999, 2, 15), (2022, 12, 23), (0, 1, 1), (-1, 1, 1)]: days = Chrono.days_from_civil(year, month, day) diff --git a/typed_python/lib/datetime/date_formatter_test.py b/typed_python/lib/datetime/date_formatter_test.py index d14770795..c03b12405 100644 --- a/typed_python/lib/datetime/date_formatter_test.py +++ b/typed_python/lib/datetime/date_formatter_test.py @@ -48,6 +48,7 @@ def get_years_in_range(start, end): class TestDateFormatter(unittest.TestCase): + @pytest.mark.group_one def test_isoformat(self): seconds = get_datetimes_in_range( start=datetime(2020, 2, 29, 13, 17, 0, 0, pytz.UTC), @@ -61,6 +62,7 @@ def test_isoformat(self): "%Y-%m-%dT%H:%M:%S" ) + @pytest.mark.group_one def test_format_directives(self): seconds = get_datetimes_in_range( start=datetime(2020, 2, 29, 13, 17, 0, 0, pytz.UTC), @@ -74,6 +76,7 @@ def test_format_directives(self): "%Y-%m-%dT%H:%M:%S" ) + @pytest.mark.group_one def test_format_directive_a(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -86,6 +89,7 @@ def test_format_directive_a(self): datetime.timestamp(day), UTC, "%a" ) == day.strftime("%a"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_A(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -98,6 +102,7 @@ def test_format_directive_A(self): datetime.timestamp(day), UTC, "%A" ) == day.strftime("%A"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_w(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -110,6 +115,7 @@ def test_format_directive_w(self): datetime.timestamp(day), UTC, "%w" ) == day.strftime("%w"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_d(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -122,6 +128,7 @@ def test_format_directive_d(self): datetime.timestamp(day), UTC, "%d" ) == day.strftime("%d"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_b(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -134,6 +141,7 @@ def test_format_directive_b(self): datetime.timestamp(day), UTC, "%b" ) == day.strftime("%b"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_B(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -146,6 +154,7 @@ def test_format_directive_B(self): datetime.timestamp(day), UTC, "%B" ) == day.strftime("%B"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_m(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -158,6 +167,7 @@ def test_format_directive_m(self): datetime.timestamp(day), UTC, "%m" ) == day.strftime("%m"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_y(self): years = get_years_in_range(1999, 2022) for year in years: @@ -165,6 +175,7 @@ def test_format_directive_y(self): datetime.timestamp(year), UTC, "%y" ) == year.strftime("%y"), year.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_H(self): minutes = get_datetimes_in_range( start=datetime(2020, 2, 29, 0, 17, 0, 0, pytz.UTC), @@ -176,6 +187,7 @@ def test_format_directive_H(self): datetime.timestamp(minute), UTC, "%H" ) == minute.strftime("%H"), minute.strftime("%Y-%m-%dT%H:%M:%S") + @pytest.mark.group_one def test_format_directive_I(self): minutes = get_datetimes_in_range( start=datetime(2020, 2, 29, 0, 17, 0, 0, pytz.UTC), @@ -193,6 +205,7 @@ def test_format_directive_I(self): timezone = FixedOffsetTimezone(offset_hours=offset_hours) assert dt.strftime("%I") == DateFormatter.format(unixtime, timezone, "%I") + @pytest.mark.group_one def test_format_directive_p(self): minutes = get_datetimes_in_range( start=datetime(2020, 2, 29, 0, 17, 0, 0, pytz.UTC), @@ -204,6 +217,7 @@ def test_format_directive_p(self): datetime.timestamp(minute), UTC, "%p" ) == minute.strftime("%p"), minute.strftime("%Y-%m-%dT%H:%M:%S") + @pytest.mark.group_one def test_format_directive_M(self): minutes = get_datetimes_in_range( start=datetime(2020, 2, 29, 10, 17, 0, 0, pytz.UTC), @@ -215,6 +229,7 @@ def test_format_directive_M(self): datetime.timestamp(minute), UTC, "%M" ) == minute.strftime("%M"), minute.strftime("%Y-%m-%dT%H:%M:%S") + @pytest.mark.group_one def test_format_directive_S(self): seconds = get_datetimes_in_range( start=datetime(2020, 2, 29, 13, 17, 0, 0, pytz.UTC), @@ -226,6 +241,7 @@ def test_format_directive_S(self): datetime.timestamp(second), UTC, "%S" ) == second.strftime("%S"), second.strftime("%Y-%m-%dT%H:%M:%S") + @pytest.mark.group_one def test_format_directive_Z(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -238,6 +254,7 @@ def test_format_directive_Z(self): DateFormatter.format(datetime.timestamp(day), UTC, "%Z") == "UTC" ), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_z(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -250,6 +267,7 @@ def test_format_directive_z(self): DateFormatter.format(datetime.timestamp(day), UTC, "%z") == "+0000" ), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_C(self): years = get_years_in_range(1999, 2022) @@ -258,6 +276,7 @@ def test_format_directive_C(self): datetime.timestamp(year), UTC, "%C" ) == year.strftime("%C"), year.strftime("%Y") + @pytest.mark.group_one def test_format_directive_Y(self): years = get_years_in_range(1999, 2022) for year in years: @@ -265,6 +284,7 @@ def test_format_directive_Y(self): datetime.timestamp(year), UTC, "%Y" ) == year.strftime("%Y"), year.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_u(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -277,6 +297,7 @@ def test_format_directive_u(self): datetime.timestamp(day), UTC, "%u" ) == day.strftime("%u"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_percent(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -289,6 +310,7 @@ def test_format_directive_percent(self): datetime.timestamp(day), UTC, "%%" ) == day.strftime("%%"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_directive_doy(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -301,6 +323,7 @@ def test_format_directive_doy(self): datetime.timestamp(day), UTC, "%j" ) == day.strftime("%j"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_string_Ymd(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -313,6 +336,7 @@ def test_format_string_Ymd(self): datetime.timestamp(day), UTC, "%Y-%m-%d" ) == day.strftime("%Y-%m-%d"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_string_ymd(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -325,6 +349,7 @@ def test_format_string_ymd(self): datetime.timestamp(day), UTC, "%y-%m-%d" ) == day.strftime("%y-%m-%d"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_string_abdY(self): days = get_datetimes_in_range( start=datetime(2019, 1, 1, 0, 0, 0, 0, pytz.UTC), @@ -337,6 +362,7 @@ def test_format_string_abdY(self): datetime.timestamp(day), UTC, "%a %b %d, %Y" ) == day.strftime("%a %b %d, %Y"), day.strftime("%Y-%m-%d") + @pytest.mark.group_one def test_format_string_YmdHMS(self): minutes = get_datetimes_in_range( start=datetime(2020, 2, 29, 10, 17, 0, 0, pytz.UTC), @@ -350,6 +376,7 @@ def test_format_string_YmdHMS(self): "%Y-%m-%dT%H:%M:%S" ) + @pytest.mark.group_one def test_format_string_YmdTHMS(self): minutes = get_datetimes_in_range( start=datetime(2020, 2, 29, 10, 17, 0, 0, pytz.UTC), diff --git a/typed_python/lib/datetime/date_parser_test.py b/typed_python/lib/datetime/date_parser_test.py index f61ef114e..913f38f64 100644 --- a/typed_python/lib/datetime/date_parser_test.py +++ b/typed_python/lib/datetime/date_parser_test.py @@ -97,6 +97,7 @@ class TestDateParser(unittest.TestCase): # This set of tests exercises the parse() entrypoint # ------------------------------------------------------- + @pytest.mark.group_one def test_parse(self): # test parse() without a format string seconds = get_datetimes_in_range( @@ -149,18 +150,22 @@ def test_parse(self): second ), second.strftime(format) + @pytest.mark.group_one def test_empty_string(self): with pytest.raises(ValueError): DateParser.parse("") + @pytest.mark.group_one def test_fails_on_random_text(self): with pytest.raises(ValueError): DateParser.parse("scuse me while i kiss the sky") + @pytest.mark.group_one def test_fails_with_extra_text(self): with pytest.raises(ValueError): DateParser.parse("1997-01-01 and some more text") + @pytest.mark.group_one def test_parse_invalid_year(self): days = [ "a997", # not 4 digit number @@ -170,12 +175,14 @@ def test_parse_invalid_year(self): with pytest.raises(ValueError): DateParser.parse(day) + @pytest.mark.group_one def test_parse_ambiguous_date(self): days = ["22-12-13", "12-12-12"] for day in days: with pytest.raises(ValueError): DateParser.parse(day) + @pytest.mark.group_one def test_parse_valid_year(self): years = ["1997", "2020", "9999", "0000"] for year in years: @@ -185,6 +192,7 @@ def test_parse_valid_year(self): # This set of tests exercises the parse_iso method # ------------------------------------------------------- + @pytest.mark.group_one def test_parse_invalid_date(self): days = [ "1997-01-00", # day < 1 @@ -203,12 +211,14 @@ def test_parse_invalid_date(self): with pytest.raises(ValueError): DateParser.parse_iso_str(day) + @pytest.mark.group_one def test_parse_iso_invalid_month(self): days = ["1997-00", "1997-13", "1997-ab"] for day in days: with pytest.raises(ValueError): DateParser.parse_iso_str(day) + @pytest.mark.group_one def test_parse_iso_yyyy(self): years = get_years_in_range(1942, 1970) + get_years_in_range(2001, 2022) for year in years: @@ -216,6 +226,7 @@ def test_parse_iso_yyyy(self): year ), year.strftime("%Y") + @pytest.mark.group_one def test_parse_iso_yyyymm(self): months = get_months_in_year(1999) + get_months_in_year(2020) formats = [ @@ -229,6 +240,7 @@ def test_parse_iso_yyyymm(self): month.strftime(format) ) == datetime.timestamp(month), month.strftime(format) + @pytest.mark.group_one def test_parse_iso_yyyymmdd(self): # all days in non leap year and leap year days = get_datetimes_in_range( @@ -247,6 +259,7 @@ def test_parse_iso_yyyymmdd(self): day.strftime(format) ) == datetime.timestamp(day), day.strftime(format) + @pytest.mark.group_one def test_parse_iso_yyyymmddhh(self): # all hours in feb 2020 hours = get_datetimes_in_range( @@ -273,6 +286,7 @@ def test_parse_iso_yyyymmddhh(self): hour.strftime(format) ) == datetime.timestamp(hour), hour.strftime(format) + @pytest.mark.group_one def test_parse_iso_yyyymmddhhmm(self): minutes = get_datetimes_in_range( start=datetime(2020, 2, 29, 13, 0, 0, 0, pytz.UTC), @@ -298,6 +312,7 @@ def test_parse_iso_yyyymmddhhmm(self): minute.strftime(format) ) == datetime.timestamp(minute), minute.strftime(format) + @pytest.mark.group_one def test_parse_iso_yyyymmddhhmmss(self): seconds = get_datetimes_in_range( start=datetime(2020, 2, 29, 13, 17, 0, 0, pytz.UTC), @@ -323,6 +338,7 @@ def test_parse_iso_yyyymmddhhmmss(self): second.strftime(format) ) == datetime.timestamp(second), second.strftime(format) + @pytest.mark.group_one def test_parse_iso_yyyymmddhhmmsssss(self): seconds = get_datetimes_in_range( start=datetime(2020, 2, 29, 13, 17, 0, 0, pytz.UTC), @@ -349,6 +365,7 @@ def test_parse_iso_yyyymmddhhmmsssss(self): == datetime.timestamp(second) + 0.123 ), second.strftime(format) + @pytest.mark.group_one def test_parse_non_iso_mmddyyyy(self): # all days in non leap year and leap year days = get_datetimes_in_range( @@ -379,6 +396,7 @@ def test_parse_non_iso_mmddyyyy(self): .timestamp() ) + @pytest.mark.group_one def test_parse_non_iso_ddmonthyyyy(self): # all days in non leap year and leap year days = get_datetimes_in_range( @@ -396,6 +414,7 @@ def test_parse_non_iso_ddmonthyyyy(self): day.strftime(format) ) == datetime.timestamp(day), day.strftime(format) + @pytest.mark.group_one def test_parse_iso_with_tz_offset(self): hours = get_datetimes_in_range( start=datetime(2020, 2, 1, 0, 0, 0, 0, pytz.UTC), @@ -417,6 +436,7 @@ def test_parse_iso_with_tz_offset(self): == datetime.timestamp(hour) - tz_offset ), hour.strftime(format) + @pytest.mark.group_one def test_parse_iso_with_tz_offset_ist(self): ymdhms = (2022, 1, 1, 12, 0, 0) @@ -442,6 +462,7 @@ def test_parse_iso_with_tz_offset_ist(self): # This group of tests exercise the parse_non_iso method # ------------------------------------------------------- + @pytest.mark.group_one def test_parse_non_iso_valid_month_string(self): months = [ "Jan", @@ -473,6 +494,7 @@ def test_parse_non_iso_valid_month_string(self): for month in months: DateParser.parse_non_iso(month + " 1, 1997") + @pytest.mark.group_one def test_parse_non_iso_invalid_month_string(self): months = ["not a month", "Jane", "Movember", "&*&"] @@ -480,6 +502,7 @@ def test_parse_non_iso_invalid_month_string(self): with pytest.raises(ValueError): DateParser.parse_non_iso(month + " 1, 1997") + @pytest.mark.group_one def test_parse_non_iso_with_whitespace(self): hours = get_datetimes_in_range( start=datetime(2020, 2, 1, 0, 0, 0, 0, pytz.UTC), @@ -498,6 +521,7 @@ def test_parse_non_iso_with_whitespace(self): hour ), hour.strftime(format) + @pytest.mark.group_one def test_parse_non_iso_dates(self): # all days in non leap year and leap year days = get_datetimes_in_range( @@ -539,6 +563,7 @@ def test_parse_non_iso_dates(self): day.strftime(format) ) == datetime.timestamp(day), day.strftime(format) + @pytest.mark.group_one def test_parse_non_iso_yyyymmddhhmm(self): minutes = get_datetimes_in_range( start=datetime(2020, 2, 29, 13, 0, 0, 0, pytz.UTC), @@ -579,6 +604,7 @@ def test_parse_non_iso_yyyymmddhhmm(self): minute.strftime(format) ) == datetime.timestamp(minute), minute.strftime(format) + @pytest.mark.group_one def test_parse_non_iso_yyyymmddhhmmss(self): seconds = get_datetimes_in_range( start=datetime(2020, 2, 29, 13, 17, 0, 0, pytz.UTC), @@ -619,6 +645,7 @@ def test_parse_non_iso_yyyymmddhhmmss(self): second.strftime(format) ) == datetime.timestamp(second), second.strftime(format) + @pytest.mark.group_one def test_parse_non_iso_pm_indicator(self): times = get_datetimes_in_range( start=datetime(2020, 2, 29, 13, 0, 0, 0, pytz.UTC), @@ -638,6 +665,7 @@ def test_parse_non_iso_pm_indicator(self): t.strftime(format) ) == datetime.timestamp(t), t.strftime(format) + @pytest.mark.group_one def test_parse_non_iso_am_indicator(self): times = get_datetimes_in_range( start=datetime(2020, 2, 29, 0, 0, 0, 0, pytz.UTC), @@ -657,20 +685,24 @@ def test_parse_non_iso_am_indicator(self): t.strftime(format) ) == datetime.timestamp(t), t.strftime(format) + @pytest.mark.group_one def test_parse_non_iso_invalid_day(self): with pytest.raises(ValueError): DateParser.parse_non_iso("1997 Jan 32") with pytest.raises(ValueError): DateParser.parse_non_iso("1997 Jan 0") + @pytest.mark.group_one def test_parse_non_iso_invalid_month(self): with pytest.raises(ValueError): DateParser.parse_non_iso("Janeary 01 1997") + @pytest.mark.group_one def test_nyc_tz(self): assert 1666355040 == DateParser.parse("2022-10-21t08:24:00NYC") assert 1671629040 == DateParser.parse("2022-12-21t08:24:00NYC") + @pytest.mark.group_one def test_compare_parse_iso_perf(self): runs = 100000 date_strings = make_list_of_iso_datestrings(runs) @@ -709,6 +741,7 @@ def test_compare_parse_iso_perf(self): # This group of tests exercise the parse_format method # ------------------------------------------------------- + @pytest.mark.group_one def test_parse_format_yyyy(self): years = get_years_in_range(1942, 1970) + get_years_in_range(2001, 2022) for year in years: @@ -720,6 +753,7 @@ def test_parse_format_yyyy(self): year.strftime("%Y"), "%Y", UTC ) == datetime.timestamp(year), year.strftime("%Y") + @pytest.mark.group_one def test_parse_format_yyyymm(self): months = get_months_in_year(1999) + get_months_in_year(2020) formats = [ @@ -737,6 +771,7 @@ def test_parse_format_yyyymm(self): month.strftime(format), format, UTC ) == datetime.timestamp(month), month.strftime(format) + @pytest.mark.group_one def test_parse_format_yyyymmdd(self): # all days in non leap year and leap year days = get_datetimes_in_range( @@ -759,6 +794,7 @@ def test_parse_format_yyyymmdd(self): day.strftime(format), format, UTC ) == datetime.timestamp(day), day.strftime(format) + @pytest.mark.group_one def test_parse_format_yyyymmddhh(self): # all hours in feb 2020 hours = get_datetimes_in_range( @@ -789,6 +825,7 @@ def test_parse_format_yyyymmddhh(self): hour.strftime(format), format, UTC ) == datetime.timestamp(hour), hour.strftime(format) + @pytest.mark.group_one def test_parse_format_yyyymmddhhmm(self): minutes = get_datetimes_in_range( start=datetime(2020, 2, 29, 13, 0, 0, 0, pytz.UTC), @@ -829,6 +866,7 @@ def test_parse_format_yyyymmddhhmm(self): minute.strftime(format), format ) == datetime.timestamp(minute), minute.strftime(format) + @pytest.mark.group_one def test_parse_format_yyyymmddhhmmss(self): seconds = get_datetimes_in_range( start=datetime(2020, 2, 29, 13, 17, 0, 0, pytz.UTC), @@ -863,6 +901,7 @@ def test_parse_format_yyyymmddhhmmss(self): "2022-01-15T12:40:25nyc", "%Y-%m-%dT%H:%M:%S%Z", NYC ) + @pytest.mark.group_one def test_parse_format_with_timezone(self): way1 = DateParser.parse_with_format( "2022-01-15 18:01:02nyc", "%Y-%m-%dT%H:%M:%S%Z" @@ -872,6 +911,7 @@ def test_parse_format_with_timezone(self): ) assert way1 == way2 + @pytest.mark.group_one def test_parse_non_iso_edge(self): res = DateParser.parse_non_iso("02/19/1993 18:00:00", NYC) expected = ( @@ -888,6 +928,7 @@ def test_parse_non_iso_edge(self): .timestamp() ) + @pytest.mark.group_one def test_parse_non_iso_YYYYMMDD(self): res = DateParser.parse_non_iso("2021/01/01", NYC) expected = ( @@ -897,6 +938,7 @@ def test_parse_non_iso_YYYYMMDD(self): ) assert res == expected + @pytest.mark.group_one def test_parse_non_iso_YYYYMMDD_together(self): res = DateParser.parse_non_iso("20210101-07:37:07", NYC) expected = ( @@ -906,6 +948,7 @@ def test_parse_non_iso_YYYYMMDD_together(self): ) assert res == expected, (expected - res) / 3600 + @pytest.mark.group_one def test_parse_non_iso_ampm(self): res = DateParser.parse_non_iso("2019/08/04 6:59 PM", NYC) expected = ( @@ -915,6 +958,7 @@ def test_parse_non_iso_ampm(self): ) assert res == expected + @pytest.mark.group_one def test_compare_parse_format_perf(self): runs = 100000 date_strings = make_list_of_iso_datestrings(runs) diff --git a/typed_python/lib/datetime/date_time.py b/typed_python/lib/datetime/date_time.py index 634a624c7..5b189b6f8 100644 --- a/typed_python/lib/datetime/date_time.py +++ b/typed_python/lib/datetime/date_time.py @@ -269,7 +269,7 @@ def firstOfMonth(self): return Date(self.year, self.month, 1) def quarterOfYear(self): - return (self.date.month - 1) // 3 + 1 + return (self.month - 1) // 3 + 1 def next(self, step: int = 1): """Returns the date `step` days ahead of `self`. diff --git a/typed_python/lib/datetime/date_time_test.py b/typed_python/lib/datetime/date_time_test.py index 1e7e3f1be..9d7a59ece 100644 --- a/typed_python/lib/datetime/date_time_test.py +++ b/typed_python/lib/datetime/date_time_test.py @@ -1,6 +1,7 @@ import pytest import pytz import datetime +from typed_python import NamedTuple from typed_python.lib.datetime.date_time import ( Date, DateTime, @@ -15,10 +16,11 @@ OneFoldOnlyError, PytzTimezone, ) -from typed_python import Timestamp, NamedTuple from typed_python.lib.datetime.date_parser_test import get_datetimes_in_range +from typed_python.lib.timestamp import Timestamp +@pytest.mark.group_one def test_last_weekday_of_month(): assert last_weekday_of_month(2023, 1, 2) == Date(2023, 1, 31) assert last_weekday_of_month(2023, 1, 1) == Date(2023, 1, 30) @@ -37,10 +39,12 @@ def test_last_weekday_of_month(): assert last_weekday_of_month(1965, 2, 1) == Date(1965, 2, 22) +@pytest.mark.group_one def test_DateTime_str(): assert str(DateTime(2022, 1, 10, 10, 7, 45.12432)) == "2022-01-10 10:07:45" +@pytest.mark.group_one def test_DateTime_to_timestamp(): ymdhms = (2022, 12, 23, 18, 40, 46) dateTime = DateTime(*ymdhms) @@ -53,6 +57,7 @@ def test_DateTime_to_timestamp(): assert timestamp == ts +@pytest.mark.group_one def test_DateTime_nonexistent_DateTime(): dateTime = DateTime(2022, 3, 13, 2, 30, 0) @@ -60,6 +65,7 @@ def test_DateTime_nonexistent_DateTime(): NYC.timestamp(dateTime) +@pytest.mark.group_one def test_DateTime_from_timestamp(): dateTime = DateTime(2022, 11, 6, 1, 30, 0) @@ -68,6 +74,7 @@ def test_DateTime_from_timestamp(): assert newDateTime == dateTime +@pytest.mark.group_one def test_DateTime_to_timestamp_daylight_savings(): utcDateTime = DateTime(2022, 11, 6, 5, 30, 0) oneThirtyAmNycFirstFold = UTC.timestamp(utcDateTime) @@ -81,6 +88,7 @@ def test_DateTime_to_timestamp_daylight_savings(): ) +@pytest.mark.group_one def test_fixed_offset(): ymdhms = (2022, 11, 6, 5, 30, 0) @@ -93,6 +101,7 @@ def test_fixed_offset(): assert ts == res +@pytest.mark.group_one def test_datetime_to_timestamp_and_back(): for tz in [NYC, EST, UTC]: dtime = DateTime(2022, 11, 6, 1, 30, 0) @@ -101,6 +110,7 @@ def test_datetime_to_timestamp_and_back(): assert dtime == dtime2 +@pytest.mark.group_one def test_EST_against_datetime(): tz = pytz.timezone("America/Atikokan") externalTimestamp = tz.localize( @@ -112,6 +122,7 @@ def test_EST_against_datetime(): ) +@pytest.mark.group_one def test_timestamp_parse_around_daylight_savings_switch(): nycDateStringsToUtcDateStrings = { "2022-03-12 00:30:00nyc": "2022-03-12 05:30:00", @@ -233,6 +244,7 @@ def test_timestamp_parse_around_daylight_savings_switch(): assert res == expected, (res, expected) +@pytest.mark.group_one def test_TimeOfDay(): assert TimeOfDay(12, 3, 30) < TimeOfDay(12, 3, 31) assert TimeOfDay(11, 10, 30) < TimeOfDay(12, 3, 31) @@ -249,6 +261,7 @@ def test_TimeOfDay(): TimeOfDay(hour, minute, second) +@pytest.mark.group_one def test_afterFold_dst_end(): with pytest.raises(OneFoldOnlyError): NYC.timestamp(DateTime(2022, 11, 2, 1, 30, 0), afterFold=True) @@ -263,6 +276,7 @@ def test_afterFold_dst_end(): assert NYC.timestamp(DateTime(*ymdhms), afterFold=True) == tsSecondFold +@pytest.mark.group_one def test_nyc_1918_10_27(): nycDateStringsToUtcDateStrings = { "1918-10-27 00:30:00nyc": "1918-10-27 04:30:00", @@ -278,6 +292,7 @@ def test_nyc_1918_10_27(): assert res == expected, (res, expected) +@pytest.mark.group_one def test_nyc_since_1902(): nyc = pytz.timezone("America/New_York") NYC = PytzTimezone.fromName("America/New_York") @@ -319,6 +334,7 @@ def test_nyc_since_1902(): ) +@pytest.mark.group_one def test_nyc_vs_chi(): ts_chi = PytzTimezone.fromName("America/Chicago").timestamp( DateTime(2019, 7, 2, 8, 30, 0) @@ -327,6 +343,7 @@ def test_nyc_vs_chi(): assert ts_nyc - ts_chi == -3600 +@pytest.mark.group_one def test_Date_methods(): assert Date(1970, 1, 1).daysSinceEpoch() == 0 assert Date(1970, 1, 2).daysSinceEpoch() == 1 @@ -339,10 +356,12 @@ def test_Date_methods(): Date(2022, 2, 29) +@pytest.mark.group_one def test_Date_0000(): Date(0, 1, 1) +@pytest.mark.group_one def test_DateTime_add_and_subtract(): assert DateTime(2022, 1, 1, 2, 30, 17) - 17 == DateTime(2022, 1, 1, 2, 30, 0) assert DateTime(2022, 1, 1, 2, 30, 17) - 18 - 30 * 60 - 2 * 3600 == DateTime( @@ -350,6 +369,7 @@ def test_DateTime_add_and_subtract(): ) +@pytest.mark.group_one def test_PytzTimezone(): # check time ymdhms = (2022, 1, 11, 18, 0, 0) @@ -385,6 +405,7 @@ def test_PytzTimezone(): assert dt_them.second == dt_us.timeOfDay.second +@pytest.mark.group_one def test_Date_next(): assert Date(2023, 1, 12).next() == Date(2023, 1, 13) assert Date(2023, 1, 12).next(2) == Date(2023, 1, 14) @@ -399,6 +420,7 @@ def test_Date_next(): assert Date(2024, 2, 29).nextYear(-1) == Date(2023, 2, 28) +@pytest.mark.group_one def test_asNamedTuple(): x = Date(2023, 1, 12).asNamedTuple() assert isinstance(x, NamedTuple) diff --git a/typed_python/lib/datetime/date_time_util_test.py b/typed_python/lib/datetime/date_time_util_test.py index 9ff704381..448e4ea71 100644 --- a/typed_python/lib/datetime/date_time_util_test.py +++ b/typed_python/lib/datetime/date_time_util_test.py @@ -3,6 +3,7 @@ from typed_python.lib.datetime.date_time import Date +@pytest.mark.group_one def test_daterange(): # days by 1 assert daterange(Date(2022, 1, 2), Date(2022, 1, 10)) == ListOf(Date)( diff --git a/typed_python/lib/map_test.py b/typed_python/lib/map_test.py index 4dd15a93e..1b0e8ecea 100644 --- a/typed_python/lib/map_test.py +++ b/typed_python/lib/map_test.py @@ -21,6 +21,7 @@ class TestMap(unittest.TestCase): + @pytest.mark.group_one def test_map(self): def f(x): return x + 1 @@ -45,6 +46,7 @@ def compiledMap(f, tup): self.assertEqual(type(compiledMap(f, aNamedTup)), NamedTuple(x=int, y=float)) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_map_perf(self): @Function def addOne(x): @@ -76,6 +78,7 @@ def doit(tup, times): # which has to recreate the type object each time, is very slow. self.assertGreater(speedup, 100) + @pytest.mark.group_one def test_transpose_lists(self): @Entrypoint def transposeLists(tupOfLists): @@ -97,6 +100,7 @@ def transposeLists(tupOfLists): self.assertEqual(res[0], makeNamedTuple(x=0, y=0.0)) + @pytest.mark.group_one def test_map_with_multiple_outputs(self): @Entrypoint def f(x) -> OneOf(int, float): diff --git a/typed_python/lib/pmap_test.py b/typed_python/lib/pmap_test.py index 85e914853..e5f5d0e53 100644 --- a/typed_python/lib/pmap_test.py +++ b/typed_python/lib/pmap_test.py @@ -40,6 +40,7 @@ def isPrimeLC(x): return res +@pytest.mark.group_one def test_pmap_correct(): def addOne(x): return x + 1 @@ -48,6 +49,7 @@ def addOne(x): @flaky(max_runs=3, min_passes=1) +@pytest.mark.group_one def test_pmap_perf(): # disable this test on travis, as extra cores aren't guaranteed. if os.environ.get('TRAVIS_CI', None) is not None: @@ -78,6 +80,7 @@ def test_pmap_perf(): assert speedup > 1.5 +@pytest.mark.group_one def test_pmap_with_exceptions(): def sometimesThrows(x): if x % 100 == 93: @@ -99,6 +102,7 @@ def doSomething(x): assert 'sometimesThrows' in stringTb +@pytest.mark.group_one def test_pmap_returning_wrong_type(): def makesFloat(x): return float(x) @@ -109,6 +113,7 @@ def makesFloat(x): ) +@pytest.mark.group_one def test_pmap_with_uninitializable(): class C(Class, Final): x = Member(int) @@ -129,6 +134,7 @@ def tryResize(x, ct): tryResize(someCs, 101) +@pytest.mark.group_one def test_pmap_with_lots_of_work(): def makesOne(x): return 1 @@ -139,6 +145,7 @@ def makesOne(x): assert r == 1 +@pytest.mark.group_one def test_pmap_with_no_output(): aList = ListOf(int)() aList.resize(100) @@ -152,6 +159,7 @@ def setIt(x): assert aList[i] == i +@pytest.mark.group_one def test_recursive_pmap(): tq = TypedQueue(Tuple(int, int))() @@ -173,6 +181,7 @@ def doIt(xy): assert len(tq) == 1111 +@pytest.mark.group_one def test_pmap_arg_refcounts(): def f(x) -> int: return 0 @@ -187,6 +196,7 @@ def f(x) -> int: assert refcount(lst) == 1 +@pytest.mark.group_one def test_pmap_value_refcounts(): def f(x) -> ListOf(int): return ListOf(int)() @@ -200,6 +210,7 @@ def f(x) -> ListOf(int): assert refcount(lst) == 1 +@pytest.mark.group_one def test_pmap_func_refcounts(): x = ListOf(int)() diff --git a/typed_python/lib/reduce_test.py b/typed_python/lib/reduce_test.py index 94e95cbcf..ea2ea308d 100644 --- a/typed_python/lib/reduce_test.py +++ b/typed_python/lib/reduce_test.py @@ -22,6 +22,7 @@ class TestReduce(unittest.TestCase): + @pytest.mark.group_one def test_reduce(self): def f(x, y=0.0): return x + y @@ -40,6 +41,7 @@ def compiledReduce(f, tup): self.assertEqual(compiledReduce(f, aNamedTup), 3.5) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_reduce_perf(self): def doit(tup, times): res = 0.0 diff --git a/typed_python/lib/sorted_dict_test.py b/typed_python/lib/sorted_dict_test.py index 87cfbb66e..a6fb77b24 100644 --- a/typed_python/lib/sorted_dict_test.py +++ b/typed_python/lib/sorted_dict_test.py @@ -5,6 +5,7 @@ from typed_python.lib.sorted_dict import SortedDict +@pytest.mark.group_one def test_sorted_dict_basic(): d = SortedDict(int, int)() @@ -42,6 +43,7 @@ def test_sorted_dict_basic(): assert d.setdefault(11, 20) == 20 +@pytest.mark.group_one def test_sorted_dict_insert(): d = SortedDict(int, int)() @@ -64,6 +66,7 @@ def test_sorted_dict_insert(): d._checkInvariants() +@pytest.mark.group_one def test_sorted_dict_size_on_repeat_set(): d = SortedDict(int, int)() for i in range(10): @@ -72,6 +75,7 @@ def test_sorted_dict_size_on_repeat_set(): assert len(d) == 10 +@pytest.mark.group_one def test_sorted_dict_invariants(): numpy.random.seed(42) @@ -117,6 +121,7 @@ def checkIt(d, items: ListOf(int)): d._checkInvariants() +@pytest.mark.group_one def test_sorted_dict_comparator(): d = SortedDict(int, int, lambda x, y: y < x)() @@ -128,6 +133,7 @@ def test_sorted_dict_comparator(): assert list(d) == list(reversed(range(10))) +@pytest.mark.group_one def test_sorted_dict_compiled_iter(): d = SortedDict(int, int)() diff --git a/typed_python/lib/sorting_test.py b/typed_python/lib/sorting_test.py index f4eb445ea..a32327188 100644 --- a/typed_python/lib/sorting_test.py +++ b/typed_python/lib/sorting_test.py @@ -23,6 +23,7 @@ class TestSorting(unittest.TestCase): @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_perf_not_quadratic(self): length = 100000 @@ -58,22 +59,26 @@ def test_perf_not_quadratic(self): self.assertLess(inReverseOrder, inRandomOrder * 10) self.assertLess(allEqualTiming, inRandomOrder * 10) + @pytest.mark.group_one def test_quicksort_float_correct(self): x = ListOf(float)(numpy.random.uniform(size=1000)) self.assertEqual(ListOf(float)(sorted(x)), sorting.sorted(x)) + @pytest.mark.group_one def test_quicksort_int_correct(self): x = ListOf(int)(numpy.random.choice(1000, 1000, replace=False)) self.assertEqual(ListOf(int)(sorted(x)), sorting.sorted(x)) + @pytest.mark.group_one def test_quicksort_int_correct_with_repeated_values(self): x = ListOf(int)(numpy.random.choice(100, size=1000, replace=True)) self.assertEqual(ListOf(int)(sorted(x)), sorting.sorted(x)) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_sort_perf_simple(self): x = ListOf(float)(numpy.random.uniform(size=1000000)) @@ -91,6 +96,7 @@ def test_sort_perf_simple(self): self.assertGreater(speedup, 1.5) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_sort_perf_tuples(self): x = ListOf(Tuple(float, float))() @@ -110,6 +116,7 @@ def test_sort_perf_tuples(self): # I get about 9 self.assertGreater(speedup, 2) + @pytest.mark.group_one def test_sort_with_key(self): x = ListOf(int)(range(100)) diff --git a/typed_python/lib/timestamp_test.py b/typed_python/lib/timestamp_test.py index fc8af8d88..83cac6c8b 100644 --- a/typed_python/lib/timestamp_test.py +++ b/typed_python/lib/timestamp_test.py @@ -114,6 +114,7 @@ def formatDatetimes(datetimes: ListOf(datetime)): class TestTimestamp(unittest.TestCase): + @pytest.mark.group_one def test_demo_usage(self): # create timestamp from unixtime @@ -142,6 +143,7 @@ def test_demo_usage(self): ts = Timestamp.make(time.time()) ts.format(format="%Y-%m-%d") + @pytest.mark.group_one def test_eq(self): # The following commented block of code sometimes unexpectedly errors with something like # AssertionError: assert Held(Timestamp)(ts=2,) == Held(Timestamp)(ts=2,) @@ -159,6 +161,7 @@ def inner(): inner() + @pytest.mark.group_one def test_ge(self): # The following commented block of unexpectedly errors with something like # AssertionError: assert Held(Timestamp)(ts=1.6694e+09,) >= Held(Timestamp)(ts=1.6694e+09,) @@ -177,12 +180,14 @@ def inner(): inner() + @pytest.mark.group_one def test_gt(self): unixtime = time.time() ts1 = Timestamp.make(unixtime) ts2 = Timestamp.make(unixtime - 1) assert ts1 > ts2 + @pytest.mark.group_one def test_le(self): # See comments in test_ge above @Entrypoint @@ -196,6 +201,7 @@ def inner(): inner() + @pytest.mark.group_one def test_lt(self): unixtime = time.time() ts1 = Timestamp.make(unixtime) @@ -203,6 +209,7 @@ def test_lt(self): assert ts1 < ts2 + @pytest.mark.group_one def test_ne(self): unixtime = time.time() ts1 = Timestamp.make(unixtime) @@ -212,6 +219,7 @@ def test_ne(self): assert ts1 != ts2 assert ts1 != ts3 + @pytest.mark.group_one def test_add(self): unixtime = time.time() ts1 = Timestamp.make(unixtime) @@ -219,6 +227,7 @@ def test_add(self): ts3 = ts1 + ts2.ts assert ts3.ts == unixtime + 5 + @pytest.mark.group_one def test_sub(self): unixtime = time.time() ts1 = Timestamp.make(unixtime) @@ -226,6 +235,7 @@ def test_sub(self): ts3 = ts1 - ts2 assert ts3 == unixtime - 5 + @pytest.mark.group_one def test_format_default(self): # Just a superficial test. format proxies to DateFormatter.format # which has more extensive testing @@ -234,6 +244,7 @@ def test_format_default(self): dt = datetime.fromtimestamp(unixtime) assert dt.isoformat(timespec="seconds").replace("T", " ") == timestamp.format() + @pytest.mark.group_one def test_format(self): # Just a superficial test. format proxies to DateFormatter.format # which has more extensive testing @@ -244,6 +255,7 @@ def test_format(self): format="%Y-%m-%dT%H:%M:%S" ) + @pytest.mark.group_one def test_parse(self): unixtime = time.time() timestamp = Timestamp.make(unixtime) @@ -253,16 +265,19 @@ def test_parse(self): assert int(timestamp) == int(parsed_timestamp) + @pytest.mark.group_one def test_parse_ampm(self): res = Timestamp.parse_nyc('2019/08/04 6:59 PM').ts expected = pytz.timezone('America/New_York').localize(datetime(2019, 8, 4, 18, 59, 0, 0)).timestamp() assert res == expected + @pytest.mark.group_one def test_parse_single_digit_day(self): res = Timestamp.parse_nyc('2020/12/1 14:15').ts expected = pytz.timezone('America/New_York').localize(datetime(2020, 12, 1, 14, 15, 0)).timestamp() assert res == expected + @pytest.mark.group_one def test_compare_timestamp_datetime_from_unixtime(self): runs = 10000000 @@ -290,6 +305,7 @@ def test_compare_timestamp_datetime_from_unixtime(self): # assert speedup > 30 and speedup < 40, speedup + @pytest.mark.group_one def test_compare_timestamp_datetime_from_string(self): runs = 100000 date_strings = make_list_of_iso_datestrings(runs) @@ -324,6 +340,7 @@ def test_compare_timestamp_datetime_from_string(self): ) # assert speedup > 7 and speedup < 8 + @pytest.mark.group_one def test_compare_timestamp_datetime_format(self): runs = 1000000 timestamps = listOfTimestamps(runs) @@ -361,6 +378,7 @@ def test_compare_timestamp_datetime_format(self): assert dtTime > tsTime and (speedup > 1 and speedup <= 4) + @pytest.mark.group_one def test_compare_timestamp_nyc_datetime_from_string(self): runs = 100000 date_strings = make_list_of_iso_datestrings(runs) diff --git a/typed_python/macro_test.py b/typed_python/macro_test.py index 815ef70d4..e3ce470a1 100644 --- a/typed_python/macro_test.py +++ b/typed_python/macro_test.py @@ -8,6 +8,7 @@ class TestMacro(unittest.TestCase): + @pytest.mark.group_one def test_main(self): @Macro def A(T): @@ -33,6 +34,7 @@ def A(T): self.assertFalse(A(str) is A(A(str))) self.assertFalse(A(str) is A(float)) + @pytest.mark.group_one def test_more(self): @TypeFunction def F(S, T): @@ -65,6 +67,7 @@ def H(S, T): with self.assertRaises(NameError): H(int, float) + @pytest.mark.group_one def test_another(self): @Macro def A(S, T): @@ -93,6 +96,7 @@ def A(S, T): print(a) print(a.do()) + @pytest.mark.group_one def test_lazy_named_tuple_row(self): @Macro def lazyWindow(T): @@ -141,6 +145,7 @@ def return_b(lazy): with PrintNewFunctionVisitor(): self.assertEqual(return_b(lazy), 'b') + @pytest.mark.group_one def test_exception(self): @Macro def f(T): @@ -163,6 +168,7 @@ def f(T): with self.assertRaises(NameError): f(int) + @pytest.mark.group_one def test_namespace(self): @Macro def f(T): diff --git a/typed_python/marker_collector_plugin.py b/typed_python/marker_collector_plugin.py new file mode 100644 index 000000000..ea5ac97ba --- /dev/null +++ b/typed_python/marker_collector_plugin.py @@ -0,0 +1,23 @@ +import pytest + + +def pytest_addoption(parser): + parser.addoption( + "--collect-tests-and-markers", + action="store_true", + help="Collect all tests and their markers", + ) + + +class MarkerCollectorPlugin: + def pytest_collection_finish(self, session): + if session.config.getoption("--collect-tests-and-markers"): + items = session.items # The filtered collection of test items + for item in items: + print(f"{item.nodeid}::{'|'.join(x.name for x in item.own_markers)}") + pytest.exit("Done collecting tests and markers", returncode=0) + + +def pytest_configure(config): + if config.getoption("--collect-tests-and-markers"): + config.pluginmanager.register(MarkerCollectorPlugin()) diff --git a/typed_python/module_representation_test.py b/typed_python/module_representation_test.py index 9d9380eb7..a2ce2f18f 100644 --- a/typed_python/module_representation_test.py +++ b/typed_python/module_representation_test.py @@ -32,11 +32,13 @@ def evaluateInto(module, code, codeDir=None): class TestModuleRepresentation(unittest.TestCase): + @pytest.mark.group_one def test_construction(self): mr = ModuleRepresentation("module") assert mr.getDict()['__name__'] == 'module' + @pytest.mark.group_one def test_addExternal(self): mr = ModuleRepresentation("module") @@ -49,6 +51,7 @@ def test_addExternal(self): with self.assertRaisesRegex(Exception, ""): mr.addExternal("hi2", "bye2") + @pytest.mark.group_one def test_otherModulesAreExternal(self): mr = ModuleRepresentation("module") @@ -58,6 +61,7 @@ def test_otherModulesAreExternal(self): assert mr.oidFor(os) is None assert mr.oidFor(os.path) is None + @pytest.mark.group_one def test_copy_into_basic(self): mr = ModuleRepresentation("module") evaluateInto(mr, "y = 10") @@ -67,6 +71,7 @@ def test_copy_into_basic(self): assert mr2.getDict()['y'] == 10 + @pytest.mark.group_one def test_copy_into_other_module(self): mr = ModuleRepresentation("module") @@ -88,6 +93,7 @@ def test_copy_into_other_module(self): assert mr.getDict()['f']() == 20 assert mr2.getDict()['f']() == 10 + @pytest.mark.group_one def test_duplication_of_functions(self): mr = ModuleRepresentation("module") @@ -107,6 +113,7 @@ def test_duplication_of_functions(self): assert mr2.getDict()['f'].__globals__ is mr2.getDict() assert mr3.getDict()['f'].__globals__ is mr3.getDict() + @pytest.mark.group_one def test_duplication_of_mutually_recursive_functions(self): mr = ModuleRepresentation("module") @@ -123,6 +130,7 @@ def test_duplication_of_mutually_recursive_functions(self): assert mr2.getDict()['f'].__globals__ is mr2.getDict() assert mr2.getDict()['g'].__globals__ is mr2.getDict() + @pytest.mark.group_one def test_duplication_of_classes(self): mr = ModuleRepresentation("module") @@ -190,6 +198,7 @@ def test_duplication_of_classes(self): assert mr2.getDict()['C'].classMeth() == 10 assert mr2.getDict()['C'].staticMeth() == 10 + @pytest.mark.group_one def test_tp_functions(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -225,6 +234,7 @@ def test_tp_functions(self): assert identityHash(mr.getDict()['f']) != identityHash(mr2.getDict()['f']) + @pytest.mark.group_one def test_tp_classes(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -279,6 +289,7 @@ def test_tp_classes(self): assert mr2.getDict()['C'](10).staticF(10) == 12 assert mr2.getDict()['C'](10).propF == 13 + @pytest.mark.group_one def test_tp_class_hierarchy(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -306,6 +317,7 @@ def test_tp_class_hierarchy(self): assert mr2.getDict()['Child'].BaseClasses[0] is not mr.getDict()['Base'] assert mr2.getDict()['Child'].BaseClasses[0] is mr2.getDict()['Base'] + @pytest.mark.group_one def test_tp_class_mutually_recursive_child_and_base(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -339,6 +351,7 @@ def test_tp_class_mutually_recursive_child_and_base(self): assert type(Base() + Base()) is Child + @pytest.mark.group_one def test_copy_into_doesnt_duplicate_unnecessarily(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -359,6 +372,7 @@ def test_copy_into_doesnt_duplicate_unnecessarily(self): assert mr.getDict()['list1'] is mr2.getDict()['list1'] assert mr.getDict()['list2'] is not mr2.getDict()['list2'] + @pytest.mark.group_one def test_duplicated_class_object_module_and_name(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -383,6 +397,7 @@ def test_duplicated_class_object_module_and_name(self): assert C1.__doc__ == C2.__doc__ assert C1.__module__ == C2.__module__ + @pytest.mark.group_one def test_class_method_closures_get_copied(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -416,6 +431,7 @@ def test_class_method_closures_get_copied(self): assert C2().c() is C2 assert C2().c() is not C1 + @pytest.mark.group_one def test_copy_in_native_base_class(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -440,6 +456,7 @@ def test_copy_in_native_base_class(self): assert issubclass(Child, Base) + @pytest.mark.group_one def test_copy_in_tp_base_class(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -465,6 +482,7 @@ def test_copy_in_tp_base_class(self): assert issubclass(Child, Base) + @pytest.mark.group_one def test_defining_subclass_referenced_in_base_class(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -483,6 +501,7 @@ def test_defining_subclass_referenced_in_base_class(self): assert issubclass(mr3.getDict()['Child'], mr3.getDict()['Base']) + @pytest.mark.group_one def test_defining_subclass_referenced_in_base_class_2(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -505,6 +524,7 @@ def test_defining_subclass_referenced_in_base_class_2(self): assert issubclass(mr3.getDict()['Child1'], mr3.getDict()['Base']) assert issubclass(mr3.getDict()['Child2'], mr3.getDict()['Base']) + @pytest.mark.group_one def test_copying_classes_with_methods_is_transitive(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -528,6 +548,7 @@ def test_copying_classes_with_methods_is_transitive(self): assert mr3.getDict()['C'].f.__globals__ is not mr2.getDict() assert mr3.getDict()['C'].f.__globals__ is mr3.getDict() + @pytest.mark.group_one def test_duplicate_class_with_functions(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -560,6 +581,7 @@ def test_duplicate_class_with_functions(self): assert mr3.getDict()['C'].f.__globals__ is not mr2.getDict() assert mr3.getDict()['C'].f.__globals__ is mr3.getDict() + @pytest.mark.group_one def test_add_base_class_as_inactive_preserves_identity(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -603,6 +625,7 @@ def test_add_base_class_as_inactive_preserves_identity(self): assert issubclass(mr4.getDict()['C'], mr3.getDict()['O']) + @pytest.mark.group_one def test_assign_to_global_scope_updates_class_and_subclass(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -645,6 +668,7 @@ def test_assign_to_global_scope_updates_class_and_subclass(self): assert mr3.getDict()['Base'].__init__.__globals__ is not mr2.getDict() assert mr3.getDict()['Base'].__init__.__globals__ is mr3.getDict() + @pytest.mark.group_one def test_duplicated_child_class_interchangeable(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") @@ -682,6 +706,7 @@ def test_duplicated_child_class_interchangeable(self): # its the 'type identical' ListOf(Base2)([Child1()]) + @pytest.mark.group_one def test_serialization_robust_to_module_ordering(self): with tempfile.TemporaryDirectory() as td: mr = ModuleRepresentation("module") diff --git a/typed_python/module_test.py b/typed_python/module_test.py index d192b61a0..6859a78ff 100644 --- a/typed_python/module_test.py +++ b/typed_python/module_test.py @@ -17,6 +17,7 @@ class ModuleTest(unittest.TestCase): + @pytest.mark.group_one def test_definining_members(self): m = Module("M") m.Int = int @@ -28,6 +29,7 @@ def test_definining_members(self): self.assertEqual(m.T, TupleOf(int)) + @pytest.mark.group_one def test_defining_classes(self): m = Module("M") @@ -44,6 +46,7 @@ class Y(Class): self.assertTrue(y.x.y.x is None) + @pytest.mark.group_one def test_cant_assign_lower_case(self): m = Module("M") with self.assertRaises(AttributeError): @@ -52,6 +55,7 @@ def test_cant_assign_lower_case(self): with self.assertRaises(AttributeError): m._int = int + @pytest.mark.group_one def test_freezing_prevents_defining(self): m = Module("M") m.Int = int @@ -60,6 +64,7 @@ def test_freezing_prevents_defining(self): with self.assertRaises(Exception): m.Float = float + @pytest.mark.group_one def test_freezing_fails_if_undefined(self): m = Module("M") m.T = TupleOf(m.I) diff --git a/typed_python/python_ast_test.py b/typed_python/python_ast_test.py index 1dbe097e9..b1bdd3353 100644 --- a/typed_python/python_ast_test.py +++ b/typed_python/python_ast_test.py @@ -24,6 +24,7 @@ class TestPythonAst(unittest.TestCase): + @pytest.mark.group_one def test_basic_parsing(self): pyast = python_ast.convertFunctionToAlgebraicPyAst(lambda: X) # noqa: F821 @@ -43,6 +44,7 @@ def reverseParseCheck(self, f): return f2 + @pytest.mark.group_one def test_reverse_parse(self): self.reverseParseCheck(lambda: X) # noqa: F821 self.reverseParseCheck(lambda x: X) # noqa: F821 @@ -65,6 +67,7 @@ def f(x): self.reverseParseCheck(f) + @pytest.mark.group_one def test_ast_for_function_with_decorator(self): # check that the ast for a function with a decorator doesn't actually # include the decorator, as the decorator isn't part of the function @@ -81,6 +84,7 @@ def f(x): assert pyast.matches.FunctionDef assert not pyast.decorator_list + @pytest.mark.group_one def test_reverse_parse_classdef(self): def f(): class A: @@ -98,6 +102,7 @@ def z(self, z: int, *args: list, **kwargs: dict) -> float: self.reverseParseCheck(f) + @pytest.mark.group_one def test_reverse_parse_functions_with_keywords(self): def f(): def g(x=10, y=20, *args, q=30): @@ -106,6 +111,7 @@ def g(x=10, y=20, *args, q=30): self.reverseParseCheck(f) + @pytest.mark.group_one def test_reverse_parse_comprehensions(self): def f(): [x for x in y] # noqa: F821 @@ -126,12 +132,14 @@ def reverseParseAndEvalCheck(self, f, args): self.assertEqual(f(*args), f_2(*args)) + @pytest.mark.group_one def test_reverse_parse_eval(self): def f(x): return x+x self.reverseParseAndEvalCheck(f, 10) self.reverseParseAndEvalCheck(lambda x: x+x, 10) + @pytest.mark.group_one def test_reverse_parse_eval_withblock(self): def f(x, filename): with open(filename, 'r'): @@ -140,12 +148,14 @@ def f(x, filename): self.reverseParseAndEvalCheck(f, (10, ownName)) + @pytest.mark.group_one def test_reverse_parse_eval_import(self): def f(x): from numpy import float64 return float(float64(x)) self.reverseParseAndEvalCheck(f, 10) + @pytest.mark.group_one def test_parsing_fstring(self): """ This code generates: @@ -154,18 +164,21 @@ def test_parsing_fstring(self): """ self.reverseParseCheck(lambda x: f" - {x} - ") + @pytest.mark.group_one def test_parsing_assert(self): """This code generates ast.Assert node.""" def f(x): assert x == 1 self.reverseParseCheck(f) + @pytest.mark.group_one def test_parsing_yield_from(self): """This code generates ast.YieldFrom.""" def f(x): yield from x self.reverseParseCheck(f) + @pytest.mark.group_one def test_parsing_async(self): """This code generates: - ast.AsyncFunctionDef @@ -185,6 +198,7 @@ async def f(x, y): self.reverseParseCheck(f) + @pytest.mark.group_one def test_parsing_nonlocal(self): """This code generates: ast.Nonlocal.""" def f(): @@ -200,6 +214,7 @@ def inner(): self.reverseParseCheck(f) + @pytest.mark.group_one def test_parsing_matmul(self): """This code generates: ast.MatMult.""" def f(a, b): @@ -208,6 +223,7 @@ def f(a, b): self.reverseParseCheck(f) + @pytest.mark.group_one def test_parsing_annotated_assignment(self): """This code generates: ast.AddAssign.""" def f(): @@ -216,12 +232,14 @@ def f(): self.reverseParseCheck(f) + @pytest.mark.group_one def test_parsing_bytes(self): def f(): return b"aaa" self.reverseParseCheck(f) + @pytest.mark.group_one def test_converting_lambdas_in_expressions(self): def identity(x): return x @@ -238,12 +256,14 @@ def identity(x): for lam in someLambdas: self.assertEqual(self.reverseParseCheck(lam)(10), lam(10)) + @pytest.mark.group_one def test_converting_two_lambdas_on_same_line(self): someLambdas = (lambda x: x + 1, lambda x: x + 2) for lam in someLambdas: self.assertEqual(self.reverseParseCheck(lam)(10), lam(10)) + @pytest.mark.group_one def test_converting_two_lambdas_with_similar_bodies_but_different_args_on_same_line(self): # shouldn't matter which one we pick someLambdas = (lambda x, y: x + 1, lambda x, z: x + 1) @@ -251,6 +271,7 @@ def test_converting_two_lambdas_with_similar_bodies_but_different_args_on_same_l for lam in someLambdas: self.assertEqual(self.reverseParseCheck(lam)(10, 11), lam(10, 11)) + @pytest.mark.group_one def test_converting_two_identical_lambdas_on_same_line(self): # shouldn't matter which one we pick someLambdas = (lambda x: x + 1, lambda x: x + 1) @@ -258,6 +279,7 @@ def test_converting_two_identical_lambdas_on_same_line(self): for lam in someLambdas: self.assertEqual(self.reverseParseCheck(lam)(10), lam(10)) + @pytest.mark.group_one def test_converting_lambdas_pulled_out_of_binding(self): # shouldn't matter which one we pick aLambda = (lambda x: (lambda y: x + y))(10) @@ -267,6 +289,7 @@ def test_converting_lambdas_pulled_out_of_binding(self): self.assertEqual(aLambda(11), aLambda2(11)) + @pytest.mark.group_one def test_converting_lambda_with_double_star_dicts(self): def f(): x = {1: 2} @@ -275,6 +298,7 @@ def f(): self.assertEqual(self.reverseParseCheck(f)(), f()) + @pytest.mark.group_one def test_conflicting_code_objects_for_list_comps(self): with tempfile.TemporaryDirectory() as tf: fname1 = os.path.join(tf, "a.py") diff --git a/typed_python/type_function_test.py b/typed_python/type_function_test.py index 47d740174..29a48f6c1 100644 --- a/typed_python/type_function_test.py +++ b/typed_python/type_function_test.py @@ -75,6 +75,7 @@ def next(self): class TypeFunctionTest(unittest.TestCase): + @pytest.mark.group_one def test_basic(self): @TypeFunction def List(T): @@ -96,11 +97,13 @@ def List(T): with self.assertRaises(TypeError): List(int).Node(head=10, tail=l_f) + @pytest.mark.group_one def test_name_and_qualname(self): assert TfLevelMethod.__name__ == 'TfLevelMethod' assert TfLevelMethod.__module__ == 'typed_python.type_function_test' assert TfLevelMethod.__qualname__ == 'TfLevelMethod' + @pytest.mark.group_one def test_mutually_recursive(self): @TypeFunction def X(T): @@ -127,6 +130,7 @@ class Y(Class): with self.assertRaises(TypeError): anX.y = Y(float)() + @pytest.mark.group_one def test_can_serialize_type_functions(self): @TypeFunction def List(T): @@ -159,6 +163,7 @@ def List(T): l_l ) + @pytest.mark.group_one def test_type_function_on_typed_lists(self): @TypeFunction def SumThem(x): @@ -176,6 +181,7 @@ class C: self.assertEqual(SumThem(ListOf(int)([1, 2, 3])).X, 6) + @pytest.mark.group_one def test_type_functions_with_recursive_annotations(self): @TypeFunction def Boo(T): @@ -188,6 +194,7 @@ def f(self) -> Boo(T): self.assertEqual(boo, boo.f()) + @pytest.mark.group_one def test_compile_typefunc_staticmethod(self): @TypeFunction def A(T): @@ -220,6 +227,7 @@ def callAFunc(): # trip the assertion on isCompiled self.assertEqual(A(float).aFunc(ListOf(float)([1, 2])), [1, 2]) + @pytest.mark.group_one def test_typefunc_in_staticmethod_annotation(self): @TypeFunction def makeClass(T): @@ -231,6 +239,7 @@ def f() -> makeClass(T): makeClass(int)() + @pytest.mark.group_one def test_typefunc_in_staticmethod_annotation_notcompiled(self): @TypeFunction def makeClass(T): @@ -243,6 +252,7 @@ def f() -> makeClass(T): makeClass(int)() + @pytest.mark.group_one def test_compiled_method_in_tf_closure(self): timesCompiled = Runtime.singleton().timesCompiled @@ -251,6 +261,7 @@ def test_compiled_method_in_tf_closure(self): assert Runtime.singleton().timesCompiled - timesCompiled < 10 + @pytest.mark.group_one def test_pass_function_with_reference_doesnt_recompile(self): timesCompiled = Runtime.singleton().timesCompiled @@ -270,9 +281,11 @@ def callIt(aFun, anArg): assert Runtime.singleton().timesCompiled - timesCompiled < 10 + @pytest.mark.group_one def test_module_level_type_function_name(self): assert SerializationContext().nameForObject(TfLevelMethod) is not None + @pytest.mark.group_one def test_deserialize_type_functions_usable(self): @TypeFunction def TF(T): @@ -289,6 +302,7 @@ class TF(Class): assert TFInt(x=20).x == 20 + @pytest.mark.group_one def test_classes_binding_methods_with_closures(self): def makeF(boundvalue): def f(): @@ -313,6 +327,7 @@ def callIt(T): self.assertEqual(callIt(makeFClass((1, 2))), (1, 2)) self.assertEqual(callIt(makeFClass((1, 3))), (1, 3)) + @pytest.mark.group_one def test_can_compile_function_taking_type_function_output_bound_to_function(self): def makeMultiplier(val): def f(x): @@ -336,6 +351,7 @@ def instantiateAndCall(SomeCls): assert instantiateAndCall(C2) == 30.0 assert instantiateAndCall(C3) == 20.0 + @pytest.mark.group_one def test_call_type_function_with_constant(self): # if the cache is on, this won't work if os.getenv("TP_COMPILER_CACHE"): @@ -380,12 +396,14 @@ def do(): assert vis.variableTypes['T'] is not object + @pytest.mark.group_one def test_serialize_type_function_results(self): # confirm that when we serialize a TF Class we don't serialize the contents of the # class! sc = SerializationContext().withoutCompression() assert b'thisIsAMethod' not in sc.serialize(IntLevelClass(10)) + @pytest.mark.group_one def test_compiled_type_function_sees_through_constants(self): @Entrypoint def callNext(c): @@ -396,6 +414,7 @@ def callNext(c): assert compilerInferredNextType is intendedType + @pytest.mark.group_one def test_type_functions_are_classes(self): @TypeFunction def Temp(C): @@ -410,6 +429,7 @@ def __init__(self, y): assert issubclass(Temp(int), Temp) assert issubclass(Temp, TypeFunction) + @pytest.mark.group_one def test_serialize_regular_class_output(self): C = RegularPythonClass(int) diff --git a/typed_python/type_identity_test.py b/typed_python/type_identity_test.py index d32bb736e..620bda8c1 100644 --- a/typed_python/type_identity_test.py +++ b/typed_python/type_identity_test.py @@ -85,6 +85,7 @@ def returnSerializedValue(filesToWrite, expression, printComments=False): ) +@pytest.mark.group_one def test_identity_ignores_function_file_accesses(): # make sure these functions succeed assert looksAtFilename() @@ -97,11 +98,13 @@ def test_identity_ignores_function_file_accesses(): assert '__file__' not in walk2 +@pytest.mark.group_one def test_identities_of_basic_types_different(): assert identityHash(int) != identityHash(float) assert identityHash(TupleOf(int)) != identityHash(TupleOf(float)) +@pytest.mark.group_one def test_object_graph_instability_is_noticed(): class C: pass @@ -116,6 +119,7 @@ class C: resetCompilerVisibleObjectHashCache() +@pytest.mark.group_one def test_object_graph_instability_is_noticed_globally(): class C: pass @@ -129,6 +133,7 @@ class C: resetCompilerVisibleObjectHashCache() +@pytest.mark.group_one def test_identity_of_function_with_annotation(): def f(x: int): pass @@ -155,6 +160,7 @@ def functionAccessingModuleLevelThreadLocal(): return hasattr(moduleLevelThreadLocal, "anything") +@pytest.mark.group_one def test_identity_of_function_accessing_thread_local(): print(typesAndObjectsVisibleToCompilerFrom(type(functionAccessingModuleLevelThreadLocal))) @@ -169,11 +175,13 @@ def test_identity_of_function_accessing_thread_local(): raise Exception("hash instability found") +@pytest.mark.group_one def test_identity_of_method_descriptors(): assert identityHash(ListOf(int).append) != identityHash(ListOf(float).append) assert identityHash(ListOf(int).append) != identityHash(ListOf(int).extend) +@pytest.mark.group_one def test_class_and_held_class_in_group(): class C(Class): pass @@ -187,6 +195,7 @@ class C(Class): assert C in recursiveTypeGroup(C) +@pytest.mark.group_one def test_identity_of_register_types(): assert isinstance(identityHash(UInt64), bytes) assert len(identityHash(UInt64)) == 20 @@ -194,12 +203,14 @@ def test_identity_of_register_types(): assert identityHash(UInt64) != identityHash(UInt32) +@pytest.mark.group_one def test_identity_of_list_of(): assert identityHash(ListOf(int)) != identityHash(ListOf(float)) assert identityHash(ListOf(int)) == identityHash(ListOf(int)) assert identityHash(ListOf(int)) != identityHash(TupleOf(int)) +@pytest.mark.group_one def test_identity_of_named_tuple_and_tuple(): assert identityHash(NamedTuple(x=int)) != identityHash(NamedTuple(x=float)) assert identityHash(NamedTuple(x=int)) == identityHash(NamedTuple(x=int)) @@ -209,15 +220,18 @@ def test_identity_of_named_tuple_and_tuple(): assert identityHash(NamedTuple(x=int, y=float)) != identityHash(NamedTuple(y=float, x=int)) +@pytest.mark.group_one def test_identity_of_dict(): assert identityHash(Dict(int, float)) != identityHash(Dict(int, int)) assert identityHash(Dict(int, float)) != identityHash(Dict(float, int)) +@pytest.mark.group_one def test_identity_of_oneof(): assert identityHash(OneOf(None, int)) != identityHash(OneOf(None, float)) +@pytest.mark.group_one def test_identity_of_recursive_types(): X = Forward("X") X = X.define(TupleOf(OneOf(int, X))) @@ -232,6 +246,7 @@ def test_identity_of_recursive_types(): assert identityHash(X3) != identityHash(X) +@pytest.mark.group_one def test_identity_of_recursive_types_2(): X = Forward("X") X = X.define(TupleOf(OneOf(int, TupleOf(X)))) @@ -239,6 +254,7 @@ def test_identity_of_recursive_types_2(): identityHash(X) +@pytest.mark.group_one def test_identity_of_recursive_types_produced_same_way(): def make(name, T): X = Forward(name) @@ -249,6 +265,7 @@ def make(name, T): assert identityHash(make("X", int)) != identityHash(make("X2", int)) +@pytest.mark.group_one def test_identity_of_lambda_functions(): @Entrypoint def makeAdder(a): @@ -263,10 +280,12 @@ def makeAdder(a): assert identityHash(type(makeAdder(10))) != identityHash(type(makeAdder(10.5))) +@pytest.mark.group_one def test_checkHash_works(): assert checkHash({"x.py": "A = TupleOf(int)\n"}, 'x.A') == Hash(identityHash(TupleOf(int))) +@pytest.mark.group_one def test_mutually_recursive_group_basic(): assert recursiveTypeGroup(TupleOf(int)) == [TupleOf(int)] @@ -276,6 +295,7 @@ def test_mutually_recursive_group_basic(): assert recursiveTypeGroup(X) == [X, OneOf(int, X)] +@pytest.mark.group_one def test_mutually_recursive_group_through_functions_in_closure(): @Entrypoint def f(x): @@ -291,6 +311,7 @@ def g(x): assert recursiveTypeGroup(gType) == [gType, fType] +@pytest.mark.group_one def test_mutually_recursive_group_through_functions_at_module_level(): assert set(recursiveTypeGroup(type(gModuleLevel))) == set([ fModuleLevel, type(fModuleLevel), gModuleLevel, type(gModuleLevel) @@ -301,6 +322,7 @@ def test_mutually_recursive_group_through_functions_at_module_level(): ]) +@pytest.mark.group_one def test_recursive_group_of_function_values(): @Entrypoint def f(x): @@ -313,6 +335,7 @@ def g(x): assert recursiveTypeGroup(f) +@pytest.mark.group_one def test_checkHash_lambdas_stable(): contents = {"x.py": "@Entrypoint\ndef f(x):\n return x + 1\n"} @@ -322,6 +345,7 @@ def test_checkHash_lambdas_stable(): assert h1 == checkHash(contents, 'type(x.f)') +@pytest.mark.group_one def test_checkHash_lambdas_hash_code_correctly(): contents1 = {"x.py": "@Entrypoint\ndef f(x):\n return x + 1\n"} contents2 = {"x.py": "@Entrypoint\ndef f(x):\n return x + 2\n"} @@ -329,6 +353,7 @@ def test_checkHash_lambdas_hash_code_correctly(): assert checkHash(contents1, 'type(x.f)') != checkHash(contents2, 'type(x.f)') +@pytest.mark.group_one def test_checkHash_mutable_global_constants(): contents1 = {"x.py": "G=Dict(int, int)({1:2})\n@Entrypoint\ndef g(x):\n return G[x]\n"} contents2 = {"x.py": "G=Dict(int, int)({1:3})\n@Entrypoint\ndef g(x):\n return G[x]\n"} @@ -338,6 +363,7 @@ def test_checkHash_mutable_global_constants(): assert checkHash(contents1, 'type(x.g)') != checkHash(contents3, 'type(x.g)') +@pytest.mark.group_one def test_checkHash_lambdas_hash_dependent_functions_correctly(): contents1 = {"x.py": "@Entrypoint\ndef g(x):\n return x + 1\n@Entrypoint\ndef f(x):\n return g(x)\n"} contents2 = {"x.py": "@Entrypoint\ndef g(x):\n return x + 2\n@Entrypoint\ndef f(x):\n return g(x)\n"} @@ -345,6 +371,7 @@ def test_checkHash_lambdas_hash_dependent_functions_correctly(): assert checkHash(contents1, 'type(x.f)') != checkHash(contents2, 'type(x.f)') +@pytest.mark.group_one def test_checkHash_lambdas_hash_mutually_recursive_correctly(): contents1 = {"x.py": "@Entrypoint\ndef g(x):\n return f(x + 1)\n@Entrypoint\ndef f(x):\n return g(x)\n"} contents2 = {"x.py": "@Entrypoint\ndef g(x):\n return f(x + 2)\n@Entrypoint\ndef f(x):\n return g(x)\n"} @@ -352,6 +379,7 @@ def test_checkHash_lambdas_hash_mutually_recursive_correctly(): assert checkHash(contents1, 'type(x.f)') != checkHash(contents2, 'type(x.f)') +@pytest.mark.group_one def test_checkHash_class_member_access(): contents1 = {"x.py": "class C:\n x=1\n@Entrypoint\ndef g(x):\n return C.x\n"} contents2 = {"x.py": "class C:\n x=2\n@Entrypoint\ndef g(x):\n return C.x\n"} @@ -360,6 +388,7 @@ def test_checkHash_class_member_access(): assert checkHash(contents1, 'type(x.g)') != checkHash(contents2, 'type(x.g)') +@pytest.mark.group_one def test_checkHash_function_body(): contents1 = {"x.py": "def f(x): return x + 1\n@Entrypoint\ndef g(x):\n return f(x)\n"} contents2 = {"x.py": "def f(x): return x + 2\n@Entrypoint\ndef g(x):\n return f(x)\n"} @@ -367,6 +396,7 @@ def test_checkHash_function_body(): assert checkHash(contents1, 'type(x.g)') != checkHash(contents2, 'type(x.g)') +@pytest.mark.group_one def test_checkHash_function_arg_types(): contents1 = {"x.py": "@Entrypoint\ndef g(x: int):\n return f(x)\n"} contents2 = {"x.py": "@Entrypoint\ndef g(x: float):\n return f(x)\n"} @@ -374,6 +404,7 @@ def test_checkHash_function_arg_types(): assert checkHash(contents1, 'type(x.g)') != checkHash(contents2, 'type(x.g)') +@pytest.mark.group_one def test_checkHash_function_arg_default_vals(): contents1 = {"x.py": "@Entrypoint\ndef g(x=1):\n return f(x)\n"} contents2 = {"x.py": "@Entrypoint\ndef g(x=2):\n return f(x)\n"} @@ -381,6 +412,7 @@ def test_checkHash_function_arg_default_vals(): assert checkHash(contents1, 'type(x.g)') != checkHash(contents2, 'type(x.g)') +@pytest.mark.group_one def test_checkHash_function_arg_default_vals_string(): contents1 = {"x.py": "@Entrypoint\ndef g(x='1'):\n return f(x)\n"} contents2 = {"x.py": "@Entrypoint\ndef g(x='2'):\n return f(x)\n"} @@ -388,6 +420,7 @@ def test_checkHash_function_arg_default_vals_string(): assert checkHash(contents1, 'type(x.g)') != checkHash(contents2, 'type(x.g)') +@pytest.mark.group_one def test_hash_of_oneof(): oneOfs = [ OneOf(None, 1), @@ -402,10 +435,12 @@ def test_hash_of_oneof(): assert len(hashes) == len(oneOfs) +@pytest.mark.group_one def test_identityHash_of_none(): assert not Hash(identityHash(type(None))).isPoison() +@pytest.mark.group_one def test_identityHash_of_a_typefunction(): def L(t): return ListOf(t) @@ -418,6 +453,7 @@ def L(t): assert identityHash(L1) == identityHash(L2) +@pytest.mark.group_one def test_hash_of_TP_produced_lambdas_with_different_closure_types(): @Entrypoint def returnIt(x): @@ -433,6 +469,7 @@ def f(): assert identityHash(returnIt(1)) != identityHash(returnIt(2.0)) +@pytest.mark.group_one def test_hash_of_native_lambdas_with_different_closure_types(): def returnIt(x): def f(): @@ -447,6 +484,7 @@ def f(): assert identityHash(t1) != identityHash(t3) +@pytest.mark.group_one def test_checkHash_type_functions(): contents1 = {"x.py": "@TypeFunction\ndef L(t):\n return ListOf(t)\n\n@Entrypoint\ndef f(x):\n return L(type(x))()"} contents2 = {"x.py": "@TypeFunction\ndef L(t):\n return TupleOf(t)\n@Entrypoint\ndef f(x):\n return L(type(x))()"} @@ -456,6 +494,7 @@ def test_checkHash_type_functions(): assert checkHash(contents1, 'type(x.f)') == checkHash(contents3, 'type(x.f)') +@pytest.mark.group_one def test_checkHash_mutually_recursive_function_bodies(): contents1 = {"x.py": "def f(x): return g(x + 1)\ndef g(x):\n return f(x)\n@Entrypoint\ndef h(x):\n return f(x)"} contents2 = {"x.py": "def f(x): return g(x + 2)\ndef g(x):\n return f(x)\n@Entrypoint\ndef h(x):\n return f(x)"} @@ -463,6 +502,7 @@ def test_checkHash_mutually_recursive_function_bodies(): assert checkHash(contents1, 'type(x.h)') != checkHash(contents2, 'type(x.h)') +@pytest.mark.group_one def test_checkHash_methods(): contents1 = {"x.py": "class N(Class):\n def f(self): return 1\n"} contents2 = {"x.py": "class N(Class):\n def f(self): return 2\n"} @@ -470,6 +510,7 @@ def test_checkHash_methods(): assert checkHash(contents1, 'x.N.f') != checkHash(contents2, 'x.N.f') +@pytest.mark.group_one def test_checkHash_methods_on_class(): contents1 = {"x.py": "class N(Class):\n def f(self): return 1\n"} contents2 = {"x.py": "class N(Class):\n def f(self): return 2\n"} @@ -477,6 +518,7 @@ def test_checkHash_methods_on_class(): assert checkHash(contents1, 'x.N') != checkHash(contents2, 'x.N') +@pytest.mark.group_one def test_checkHash_methods_on_empty_python_class(): contents1 = {"x.py": "class N1:\n pass\n"} contents2 = {"x.py": "class N2:\n pass\n"} @@ -484,6 +526,7 @@ def test_checkHash_methods_on_empty_python_class(): assert checkHash(contents1, 'x.N1') != checkHash(contents2, 'x.N2') +@pytest.mark.group_one def test_checkHash_methods_on_python_class(): contents1 = {"x.py": "class N:\n def f(self): return 1\n"} contents2 = {"x.py": "class N:\n def f(self): return 2\n"} @@ -491,6 +534,7 @@ def test_checkHash_methods_on_python_class(): assert checkHash(contents1, 'x.N') != checkHash(contents2, 'x.N') +@pytest.mark.group_one def test_checkHash_methods_on_named_tuple_subclass(): contents1 = {"x.py": "class N(NamedTuple()):\n def f(self): return 1\n"} contents2 = {"x.py": "class N(NamedTuple()):\n def f(self): return 2\n"} @@ -507,6 +551,7 @@ def f(y): """ +@pytest.mark.group_one def test_checkHash_references_to_typed_free_objects(): contents1 = {"x.py": FUNCMAKER + "A = makeAdder(1)\ndef f(x):\n return A(x)"} contents2 = {"x.py": FUNCMAKER + "A = makeAdder(2)\ndef f(x):\n return A(x)"} @@ -516,10 +561,12 @@ def test_checkHash_references_to_typed_free_objects(): assert checkHash(contents1, 'x.f') != checkHash(contents3, 'x.f') +@pytest.mark.group_one def test_hash_of_builtins(): assert not Hash(identityHash(isinstance)).isPoison() +@pytest.mark.group_one def test_hash_of_classObj(): class C(Class, Final): x = Member(int) @@ -594,24 +641,28 @@ def deserializeTwiceAndConfirmEquivalent(rep): } +@pytest.mark.group_one def test_repeated_deserialize_externally_defined_named_tuple(): ser = returnSerializedValue(MODULE, 'x.NT') assert SerializationContext().deserialize(ser) is SerializationContext().deserialize(ser) +@pytest.mark.group_one def test_repeated_deserialize_externally_defined_class_is_stable(): ser = returnSerializedValue(MODULE, 'x.S()') assert SerializationContext().deserialize(ser) is SerializationContext().deserialize(ser) +@pytest.mark.group_one def test_repeated_deserialize_externally_defined_alternative_is_stable(): ser = returnSerializedValue(MODULE, 'x.MakeA()') assert SerializationContext().deserialize(ser) is SerializationContext().deserialize(ser) +@pytest.mark.group_one def test_repeated_deserialize_externally_defined_anonymous_classes(): ser = returnSerializedValue(MODULE, 'x.C()') @@ -621,6 +672,7 @@ def test_repeated_deserialize_externally_defined_anonymous_classes(): ) +@pytest.mark.group_one def test_serialization_of_anonymous_functions_preserves_references(): ser = returnSerializedValue(MODULE, 'x.addToTypedGlobalMaker()') @@ -635,6 +687,7 @@ def test_serialization_of_anonymous_functions_preserves_references(): assert vals == (1, 2) +@pytest.mark.group_one def test_hash_stability(): idHash = evaluateExprInFreshProcess({ 'x.py': 'from typed_python.compiler.native_ast import NamedCallTarget\n' @@ -651,6 +704,7 @@ def test_hash_stability(): assert idHash == idHashDeserialized +@pytest.mark.group_one def test_deserialize_external_recursive_class(): ser = returnSerializedValue(MODULE, 'x.RecursiveClass()') @@ -661,6 +715,7 @@ def test_deserialize_external_recursive_class(): ) +@pytest.mark.group_one def test_dot_accesses(): def f(): return typed_python._types @@ -682,6 +737,7 @@ def f3(): assert getCodeGlobalDotAccesses(f3.__code__) == [['typed_python', 'f']] +@pytest.mark.group_one def test_identity_of_entrypointed_functions(): def f(): return 0 @@ -689,10 +745,12 @@ def f(): assert identityHash(Function(f)) != identityHash(Entrypoint(f)) +@pytest.mark.group_one def test_identity_of_singleton_classes(): assert identityHash(A) != identityHash(B) +@pytest.mark.group_one def test_type_walk_for_named_tuple_subclass(): class N(NamedTuple()): def f(self): diff --git a/typed_python/typed_queue_test.py b/typed_python/typed_queue_test.py index 4ed164154..02459c450 100644 --- a/typed_python/typed_queue_test.py +++ b/typed_python/typed_queue_test.py @@ -24,6 +24,7 @@ class TypedQueueTests(unittest.TestCase): + @pytest.mark.group_one def test_basic(self): queue = TypedQueue(float)() @@ -57,6 +58,7 @@ def test_basic(self): self.assertEqual(queue.peek(), None) self.assertEqual(queue.getNonblocking(), None) + @pytest.mark.group_one def test_threading(self): queue1 = TypedQueue(float)() queue2 = TypedQueue(float)() @@ -73,6 +75,7 @@ def pong(): thread1.join() @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_queue_perf(self): untypedQueue1 = queue.Queue() untypedQueue2 = queue.Queue() @@ -155,6 +158,7 @@ def getFloats(q, count): queue1.put(1.0) thread1.join() + @pytest.mark.group_one def test_create_in_compiler(self): def f(): q = TypedQueue(float)() @@ -166,6 +170,7 @@ def f(): self.assertEqual(f(), 10) self.assertEqual(Entrypoint(f)(), 10) + @pytest.mark.group_one def test_create_in_compiler_and_use_in_other_thread(self): @Entrypoint def f(): @@ -186,6 +191,7 @@ def otherThread(q): t.join() + @pytest.mark.group_one def test_many_append(self): @Entrypoint def f(): @@ -200,6 +206,7 @@ def otherThread(q): otherThread(q) + @pytest.mark.group_one def test_typed_queue_refcounts(self): x = TypedQueue(ListOf(int))() a = ListOf(int)() diff --git a/typed_python/types_metadata_test.py b/typed_python/types_metadata_test.py index 205b96acf..448d715de 100644 --- a/typed_python/types_metadata_test.py +++ b/typed_python/types_metadata_test.py @@ -19,6 +19,7 @@ class TypesMetadataTest(unittest.TestCase): + @pytest.mark.group_one def test_type_relationships(self): assert issubclass(ListOf, Type) @@ -38,6 +39,7 @@ class A(Class): assert issubclass(A, Class) + @pytest.mark.group_one def test_tupleOf(self): self.assertEqual(TupleOf(int), TupleOf(int)) self.assertEqual(TupleOf(int).ElementType, int) @@ -48,17 +50,21 @@ def test_tupleOf(self): self.assertEqual(TupleOf(object).ElementType, object) self.assertEqual(TupleOf(10).ElementType.__typed_python_category__, "Value") + @pytest.mark.group_one def test_tuple(self): self.assertEqual(Tuple(int, int, OneOf(10, 20)).ElementTypes, (int, int, OneOf(10, 20))) + @pytest.mark.group_one def test_named_tuple(self): self.assertEqual(NamedTuple(x=int, y=int, z=OneOf(10, 20)).ElementTypes, (int, int, OneOf(10, 20))) self.assertEqual(NamedTuple(x=int, y=int, z=OneOf(10, 20)).ElementNames, ('x', 'y', 'z')) + @pytest.mark.group_one def test_const_dict(self): self.assertEqual(ConstDict(str, int).KeyType, str) self.assertEqual(ConstDict(str, int).ValueType, int) + @pytest.mark.group_one def test_alternatives(self): X = Forward("X") X = X.define(Alternative( @@ -79,6 +85,7 @@ def test_alternatives(self): self.assertEqual(Right.ElementType.ElementNames, ('x', 'val')) self.assertEqual(Right.ElementType.ElementTypes, (X, int)) + @pytest.mark.group_one def test_oneof(self): someInts = TupleOf(int)((1, 2)) diff --git a/typed_python/types_named_tuple_test.py b/typed_python/types_named_tuple_test.py index fae3443f6..b6857dcbb 100644 --- a/typed_python/types_named_tuple_test.py +++ b/typed_python/types_named_tuple_test.py @@ -17,6 +17,7 @@ class NamedTupleTests(unittest.TestCase): + @pytest.mark.group_one def test_named_tuple(self): t = NamedTuple(a=int, b=int) @@ -33,6 +34,7 @@ def test_named_tuple(self): self.assertEqual(t(a=1, b=2).a, 1) self.assertEqual(t(a=1, b=2).b, 2) + @pytest.mark.group_one def test_error_message_when_assigning_bad_attributes(self): T = NamedTuple(a=int) @@ -54,6 +56,7 @@ class A(T): with self.assertRaisesRegex(AttributeError, "Cannot set attributes on instance of type 'A' because it is immutable"): A().a = 20 + @pytest.mark.group_one def test_named_tuple_construction(self): t = NamedTuple(a=int, b=int) @@ -72,6 +75,7 @@ def test_named_tuple_construction(self): with self.assertRaises(TypeError): t(c=10) + @pytest.mark.group_one def test_named_tuple_construction_bad_args(self): T = NamedTuple(a=int, b=str) @@ -81,6 +85,7 @@ def test_named_tuple_construction_bad_args(self): with self.assertRaisesRegex(TypeError, "member 'a'"): T(a="hi") + @pytest.mark.group_one def test_named_tuple_str(self): t = NamedTuple(a=str, b=str) @@ -92,6 +97,7 @@ def test_named_tuple_str(self): self.assertEqual(t().a, '') self.assertEqual(t().b, '') + @pytest.mark.group_one def test_named_tuple_subclass(self): class X(NamedTuple(x=int)): pass @@ -101,6 +107,7 @@ class X(NamedTuple(x=int)): str(NamedTuple(x=int)(x=10)) ) + @pytest.mark.group_one def test_named_tuple_subclass_magic_methods(self): hashCalled = [] hashWantsException = False @@ -148,6 +155,7 @@ def __hash__(self): hashWantsException = False hash(B()) + @pytest.mark.group_one def test_named_tuple_from_dict(self): N = NamedTuple(x=int, y=str, z=OneOf(None, "hihi")) self.assertEqual(N().x, 0) @@ -168,6 +176,7 @@ def test_named_tuple_from_dict(self): N({'y': 'hi', 'z': "not hihi"}) N({'a': 0, 'b': 0, 'c': 0, 'd': 0}) + @pytest.mark.group_one def test_named_tuple_comparison(self): N = NamedTuple(x=OneOf(None, int), y=OneOf(None, int)) @@ -182,6 +191,7 @@ class S(N): self.assertNotEqual(S(x=1, y=2), S(x=1, y=3)) self.assertFalse(S(x=1, y=2) == S(x=1, y=3)) + @pytest.mark.group_one def test_named_tuple_replacing_argument_errors(self): N = NamedTuple(a=int, b=str) n = N(a=10, b='20') @@ -201,6 +211,7 @@ def test_named_tuple_replacing_argument_errors(self): self.assertTrue("Argument 'c' is not in the tuple definition." in str(context.exception), str(context.exception)) + @pytest.mark.group_one def test_named_tuple_replacing_function(self): N = NamedTuple(a=int, b=str) @@ -236,6 +247,7 @@ def test_named_tuple_replacing_function(self): self.assertEqual(n3.a, 3) self.assertEqual(n3.b, 'yy') + @pytest.mark.group_one def test_named_tuple_replacing_refcount(self): N = NamedTuple(x=ListOf(int)) aList = ListOf(int)([1, 2, 3]) @@ -247,6 +259,7 @@ def test_named_tuple_replacing_refcount(self): nt = None self.assertEqual(_types.refcount(aList), 1) + @pytest.mark.group_one def test_named_tuple_replacing_subclass(self): class NTSubclass(NamedTuple(x=int, y=str)): def f(self, y): @@ -258,11 +271,13 @@ def f(self, y): self.assertIsInstance(nt2.f("a string"), NTSubclass) self.assertEqual(nt2.f("a string").y, "a string") + @pytest.mark.group_one def test_construct_named_tuple_from_tuple(self): NT = NamedTuple(x=int, y=str) self.assertEqual(NT((1, "2")), NT(x=1, y="2")) + @pytest.mark.group_one def test_repr_of_string_in_named_tuple(self): NT = NamedTuple(x=str) @@ -271,6 +286,7 @@ def test_repr_of_string_in_named_tuple(self): self.assertEqual(repr(NT(x="asdf\tbsdf")), '(x="asdf\\tbsdf",)') self.assertEqual(repr(NT(x="asdf\x12bsdf")), '(x="asdf\\x12bsdf",)') + @pytest.mark.group_one def test_subclassing(self): BaseTuple = NamedTuple(x=int, y=float) diff --git a/typed_python/types_serialization_format_test.py b/typed_python/types_serialization_format_test.py index 947487cca..24456eeb6 100644 --- a/typed_python/types_serialization_format_test.py +++ b/typed_python/types_serialization_format_test.py @@ -166,6 +166,7 @@ def zigZag(x): The root-level serialization always has an initial fieldNumber of 0. """ + @pytest.mark.group_one def test_single_values(self): # each value we produce should consist of a single field number (0) # encoding a value @@ -191,6 +192,7 @@ def test_single_values(self): # strings encoded as utf-8 self.assertEqual(serialize(str, "123"), BYTES(0) + unsignedVarint(3) + b"123") + @pytest.mark.group_one def test_message_validation(self): self.assertEqual(validateSerializedObject(EMPTY(0)), None) self.assertEqual(validateSerializedObject(EMPTY(100)), None) @@ -223,6 +225,7 @@ def test_message_validation(self): self.assertEqual(validateSerializedObject(BYTES(0) + unsignedVarint(2) + b" "), None) self.assertEqual(validateSerializedObject(BYTES(0) + unsignedVarint(10) + b" " * 10), None) + @pytest.mark.group_one def test_roundtrip_strings(self): # strings are encoded as utf8. @@ -271,6 +274,7 @@ def test(s): test(s+s2) test(s+s2+s) + @pytest.mark.group_one def test_message_decoding(self): self.assertEqual(decodeSerializedObject(VARINT(0) + signedVarint(100)), 100) self.assertEqual(decodeSerializedObject(EMPTY(0)), []) @@ -287,6 +291,7 @@ def test_message_decoding(self): [(100, -200), (200, -400)] ) + @pytest.mark.group_one def test_message_validation_fuzzer(self): def randomMessage(depth=0, maxDepth=8): x = numpy.random.uniform() @@ -333,6 +338,7 @@ def randomMessage(depth=0, maxDepth=8): # most random submessage messages should be bad. self.assertTrue(badSubmessageCount > goodSubmessageCount * 10) + @pytest.mark.group_one def test_tuples(self): # tuples are a compound with indices on item numbers T = TupleOf(int) @@ -364,6 +370,7 @@ def test_tuples(self): ) + END_COMPOUND() ) + @pytest.mark.group_one def test_oneof(self): # tuples are a compound with indices on item numbers T = OneOf(None, int, float, "HI", TupleOf(int)) @@ -391,6 +398,7 @@ def test_oneof(self): ) + END_COMPOUND() ) + @pytest.mark.group_one def test_alternative(self): A = Alternative( "A", @@ -408,6 +416,7 @@ def test_alternative(self): SINGLE(0) + BEGIN_COMPOUND(1) + BITS_64(0) + floatToBits(10) + BITS_64(1) + floatToBits(20.2) + END_COMPOUND() ) + @pytest.mark.group_one def test_recursive_list(self): L = Forward("L") L = L.define(ListOf(OneOf(int, L))) @@ -428,6 +437,7 @@ def test_recursive_list(self): ) + END_COMPOUND() ) + @pytest.mark.group_one def test_const_dict(self): T = ConstDict(int, int) @@ -442,6 +452,7 @@ def test_const_dict(self): END_COMPOUND() ) + @pytest.mark.group_one def test_dict(self): T = Dict(int, int) diff --git a/typed_python/types_serialization_test.py b/typed_python/types_serialization_test.py index c5f33c2a1..b19a66755 100644 --- a/typed_python/types_serialization_test.py +++ b/typed_python/types_serialization_test.py @@ -350,6 +350,7 @@ def check_idempotence(self, obj, ser_ctx=None): self.assert_is_copy(obj, ping_pong(obj, ser_ctx)) + @pytest.mark.group_one def test_serialize_lists_with_compression(self): def check_idempotence(x): s1 = SerializationContext().withoutCompression() @@ -373,6 +374,7 @@ def check_idempotence(x): aList.resize(0) check_idempotence((aList, aList)) + @pytest.mark.group_one def test_serialize_lists_compression_and_threads(self): someFloats = ListOf(float)(range(1000000)) for _ in range(6): @@ -404,6 +406,7 @@ def test_serialize_lists_compression_and_threads(self): print("nocompress is ", nocompressTime, int(size3 / 1024 / 1024)) print("speedup is ", normalTime / threadTime) + @pytest.mark.group_one def test_can_deserialize_pod_lists_with_any_context(self): someFloats = ListOf(float)(range(1000)) someInts = ListOf(int)(range(1000)) @@ -414,6 +417,7 @@ def test_can_deserialize_pod_lists_with_any_context(self): assert s2.deserialize(s1.serialize(someFloats)) == someFloats assert s2.deserialize(s1.serialize(someInts)) == someInts + @pytest.mark.group_one def test_serialize_core_python_objects(self): self.check_idempotence(0) self.check_idempotence(10) @@ -450,10 +454,12 @@ def test_serialize_core_python_objects(self): self.check_idempotence(TupleOf(int)) self.check_idempotence(TupleOf(int)([0x08])) + @pytest.mark.group_one def test_serialize_python_dict(self): d = {1: 2, 3: '4', '5': 6, 7.0: b'8'} self.check_idempotence(d) + @pytest.mark.group_one def test_serialize_recursive_list(self): def check_reclist(size): init = list(range(size)) @@ -469,6 +475,7 @@ def check_reclist(size): for i in range(4): check_reclist(i) + @pytest.mark.group_one def test_serialize_memoizes_tuples(self): ts = SerializationContext() @@ -477,6 +484,7 @@ def test_serialize_memoizes_tuples(self): lst = (lst, lst) self.assertTrue(len(ts.serialize(lst)) < (i+1) * 100) + @pytest.mark.group_one def test_serialize_objects(self): class AnObject: def __init__(self, o): @@ -491,6 +499,7 @@ def __init__(self, o): self.assertIsInstance(o2, AnObject) self.assertEqual(o2.o, 123) + @pytest.mark.group_one def test_serialize_stream_integers(self): for someInts in [(1, 2), TupleOf(int)((1, 2)), [1, 2]]: self.assertEqual( @@ -503,6 +512,7 @@ def test_serialize_stream_integers(self): TupleOf(int)(someInts) ) + @pytest.mark.group_one def test_serialize_stream_complex(self): T = OneOf(None, float, str, int, ListOf(int)) @@ -520,6 +530,7 @@ def test_serialize_stream_complex(self): TupleOf(T)([T(x) for x in items]) ) + @pytest.mark.group_one def test_serialize_recursive_object(self): class AnObject: def __init__(self, o): @@ -533,10 +544,12 @@ def __init__(self, o): o2 = ping_pong(o, ts) self.assertIs(o2.o, o2) + @pytest.mark.group_one def test_serialize_primitive_native_types(self): for t in [int, float, bool, type(None), str, bytes]: self.assertIs(ping_pong(t), t) + @pytest.mark.group_one def test_serialize_primitive_compound_types(self): class A: pass @@ -558,6 +571,7 @@ class A: ]: self.assertIs(ping_pong(t, ts), t) + @pytest.mark.group_one def test_serialize_functions_basic(self): def f(): return 10 @@ -565,6 +579,7 @@ def f(): ts = SerializationContext({'f': f}) self.assertIs(ping_pong(f, ts), f) + @pytest.mark.group_one def test_serialize_alternatives_as_types(self): A = Forward("A") A = A.define(Alternative("A", X={'a': int}, Y={'a': A})) @@ -573,6 +588,7 @@ def test_serialize_alternatives_as_types(self): self.assertIs(ping_pong(A, ts), A) self.assertIs(ping_pong(A.X, ts), A.X) + @pytest.mark.group_one def test_serialize_lambdas(self): def check(f, args): self.assertEqual(f(*args), ping_pong(f)(*args)) @@ -593,6 +609,7 @@ def f2(x): check(lambda x: (x, None), (10,)) check(lambda x: x+y, (10,)) + @pytest.mark.group_one def test_serialize_class_instance(self): class A: def __init__(self, x): @@ -613,6 +630,7 @@ def f(self): anA2 = deserialize(A, serialize(A, A(10), ts), ts) self.assertEqual(anA2.x, 10) + @pytest.mark.group_one def test_serialize_and_numpy(self): x = numpy.ones(10000) ts = SerializationContext() @@ -629,11 +647,13 @@ def test_serialize_and_numpy(self): self.assertTrue(sizeNotCompressed > sizeCompressed * 2, (sizeNotCompressed, sizeCompressed)) + @pytest.mark.group_one def test_serialize_and_numpy_with_dicts(self): x = numpy.ones(10000) self.assertTrue(numpy.all(ping_pong({'a': x, 'b': x})['a'] == x)) + @pytest.mark.group_one def test_serialize_and_threads(self): class A: def __init__(self, x): @@ -657,10 +677,12 @@ def thread(): self.assertEqual(len(OK), len(threads)) + @pytest.mark.group_one def test_serialize_named_tuple(self): X = NamedTuple(x=int) self.check_idempotence(X(x=20)) + @pytest.mark.group_one def test_serialize_named_tuple_subclass(self): class X(NamedTuple(x=int)): def f(self): @@ -674,6 +696,7 @@ def f(self): self.check_idempotence(X(x=20), ts) + @pytest.mark.group_one def test_serialization_context_queries(self): sc = SerializationContext({ 'X': False, @@ -684,22 +707,26 @@ def test_serialization_context_queries(self): self.assertIs(sc.objectFromName('Y'), True) self.assertIs(sc.nameForObject(True), 'Y') + @pytest.mark.group_one def test_serializing_dicts_in_loop(self): self.serializeInLoop(lambda: 1) self.serializeInLoop(lambda: {}) self.serializeInLoop(lambda: {1: 2}) self.serializeInLoop(lambda: {1: {2: 3}}) + @pytest.mark.group_one def test_serializing_tuples_in_loop(self): self.serializeInLoop(lambda: ()) self.serializeInLoop(lambda: (1, 2, 3)) self.serializeInLoop(lambda: (1, 2, (3, 4,), ((5, 6), (((6,),),)))) + @pytest.mark.group_one def test_serializing_lists_in_loop(self): self.serializeInLoop(lambda: []) self.serializeInLoop(lambda: [1, 2, 3, 4]) self.serializeInLoop(lambda: [1, 2, [3, 4, 5], [6, [[[[]]]]]]) + @pytest.mark.group_one def test_serializing_objects_in_loop(self): class X: def __init__(self, a=None, b=None, c=None): @@ -710,12 +737,14 @@ def __init__(self, a=None, b=None, c=None): self.serializeInLoop(lambda: X(a=X(), b=[1, 2, 3], c=X(a=X())), context=c) + @pytest.mark.group_one def test_serializing_numpy_arrays_in_loop(self): self.serializeInLoop(lambda: numpy.array([])) self.serializeInLoop(lambda: numpy.array([1, 2, 3])) self.serializeInLoop(lambda: numpy.array([[1, 2, 3], [2, 3, 4]])) self.serializeInLoop(lambda: numpy.ones(2000)) + @pytest.mark.group_one def test_serializing_anonymous_recursive_types(self): NT = Forward("NT") NT = NT.define(TupleOf(OneOf(int, NT))) @@ -725,6 +754,7 @@ def test_serializing_anonymous_recursive_types(self): nt2 = NT2((1, 2, 3)) NT2((nt2, 2)) + @pytest.mark.group_one def test_serializing_named_tuples_in_loop(self): NT = Forward("NT") NT = NT.define(NamedTuple(x=OneOf(int, float), y=OneOf(int, TupleOf(NT)))) @@ -733,6 +763,7 @@ def test_serializing_named_tuples_in_loop(self): self.serializeInLoop(lambda: NT(x=10, y=(NT(x=20, y=2),)), context=context) + @pytest.mark.group_one def test_serializing_tuple_of_in_loop(self): TO = TupleOf(int) @@ -740,6 +771,7 @@ def test_serializing_tuple_of_in_loop(self): self.serializeInLoop(lambda: TO((1, 2, 3, 4, 5)), context=context) + @pytest.mark.group_one def test_serializing_alternatives_in_loop(self): AT = Forward("AT") AT = AT.define(Alternative("AT", X={'x': int, 'y': float}, Y={'x': int, 'y': AT})) @@ -750,6 +782,7 @@ def test_serializing_alternatives_in_loop(self): self.serializeInLoop(lambda: AT.Y, context=context) self.serializeInLoop(lambda: AT.X(x=10, y=20), context=context) + @pytest.mark.group_one def test_inject_exception_into_context(self): NT = NamedTuple() @@ -790,11 +823,13 @@ def serializeInLoop(self, objectMaker, context=None): ########################################################################## # The Tests below are Adapted from pickletester.py in cpython/Lib/test + @pytest.mark.group_one def test_serialize_roundtrip_equality(self): expected = create_data() got = ping_pong(expected, sc) self.assert_is_copy(expected, got) + @pytest.mark.group_one def test_serialize_recursive_tuple_and_list(self): t = ([],) t[0].append(t) @@ -806,6 +841,7 @@ def test_serialize_recursive_tuple_and_list(self): self.assertEqual(len(x[0]), 1) self.assertIs(x[0][0], x) + @pytest.mark.group_one def test_serialize_recursive_dict(self): d = {} d[1] = d @@ -815,6 +851,7 @@ def test_serialize_recursive_dict(self): self.assertEqual(list(x.keys()), [1]) self.assertIs(x[1], x) + @pytest.mark.group_one def test_serialize_recursive_dict_key(self): d = {} k = K(d) @@ -826,6 +863,7 @@ def test_serialize_recursive_dict_key(self): self.assertIsInstance(list(x.keys())[0], K) self.assertIs(list(x.keys())[0].value, x) + @pytest.mark.group_one def test_serialize_recursive_set(self): y = set() k = K(y) @@ -837,6 +875,7 @@ def test_serialize_recursive_set(self): self.assertIsInstance(list(x)[0], K) self.assertIs(list(x)[0].value, x) + @pytest.mark.group_one def test_serialize_recursive_inst(self): i = C() i.attr = i @@ -846,6 +885,7 @@ def test_serialize_recursive_inst(self): self.assertEqual(dir(x), dir(i)) self.assertIs(x.attr, x) + @pytest.mark.group_one def test_serialize_recursive_multi(self): lst = [] d = {1: lst} @@ -871,21 +911,27 @@ def check_recursive_collection_and_inst(self, factory): self.assertIsInstance(list(x)[0], H) self.assertIs(list(x)[0].attr, x) + @pytest.mark.group_one def test_serialize_recursive_list_and_inst(self): self.check_recursive_collection_and_inst(list) + @pytest.mark.group_one def test_serialize_recursive_tuple_and_inst(self): self.check_recursive_collection_and_inst(tuple) + @pytest.mark.group_one def test_serialize_recursive_dict_and_inst(self): self.check_recursive_collection_and_inst(dict.fromkeys) + @pytest.mark.group_one def test_serialize_recursive_set_and_inst(self): self.check_recursive_collection_and_inst(set) + @pytest.mark.group_one def test_serialize_recursive_frozenset_and_inst(self): self.check_recursive_collection_and_inst(frozenset) + @pytest.mark.group_one def test_serialize_base_type_subclass(self): assert sc.deserialize(sc.serialize(MyInt())) == MyInt() assert sc.deserialize(sc.serialize(MyFloat())) == MyFloat() @@ -899,6 +945,7 @@ def test_serialize_base_type_subclass(self): assert sc.deserialize(sc.serialize(MySet())) == MySet() assert sc.deserialize(sc.serialize(MyFrozenSet())) == MyFrozenSet() + @pytest.mark.group_one def test_serialize_unicode_1(self): endcases = ['', '<\\u>', '<\\\u1234>', '<\n>', '<\\>', '<\\\U00012345>'] @@ -908,12 +955,14 @@ def test_serialize_unicode_1(self): u2 = ping_pong(u) self.assert_is_copy(u, u2) + @pytest.mark.group_one def test_serialize_unicode_high_plane(self): t = '\U00012345' t2 = ping_pong(t) self.assert_is_copy(t, t2) + @pytest.mark.group_one def test_serialize_bytes(self): for s in b'', b'xyz', b'xyz'*100: s2 = ping_pong(s) @@ -927,6 +976,7 @@ def test_serialize_bytes(self): s2 = ping_pong(s) self.assert_is_copy(s, s2) + @pytest.mark.group_one def test_serialize_ints(self): n = sys.maxsize while n: @@ -935,6 +985,7 @@ def test_serialize_ints(self): self.assert_is_copy(expected, n2) n = n >> 1 + @pytest.mark.group_one def test_serialize_float(self): test_values = [0.0, 4.94e-324, 1e-310, 7e-308, 6.626e-34, 0.1, 0.5, 3.14, 263.44582062374053, 6.022e23, 1e30] @@ -944,28 +995,33 @@ def test_serialize_float(self): got = ping_pong(value) self.assert_is_copy(value, got) + @pytest.mark.group_one def test_serialize_numpy_float(self): deserializedVal = ping_pong(numpy.float64(1.0)) self.assertEqual(deserializedVal, 1.0) self.assertIsInstance(deserializedVal, numpy.float64) + @pytest.mark.group_one def test_serialize_reduce(self): inst = AAA() loaded = ping_pong(inst, sc) self.assertEqual(loaded, REDUCE_A) + @pytest.mark.group_one def test_serialize_getinitargs(self): inst = initarg(1, 2) loaded = ping_pong(inst) self.assert_is_copy(inst, loaded) + @pytest.mark.group_one def test_serialize_metaclass(self): a = use_metaclass() b = ping_pong(a, sc) self.assertEqual(a.__class__, b.__class__) @pytest.mark.skip(reason="Didn't even bother") + @pytest.mark.group_one def test_serialize_dynamic_class(self): import copyreg a = create_dynamic_class("my_dynamic_class", (object,)) @@ -975,6 +1031,7 @@ def test_serialize_dynamic_class(self): self.assertEqual(a, b) self.assertIs(type(a), type(b)) + @pytest.mark.group_one def test_class_serialization_stable(self): class C: pass @@ -990,6 +1047,7 @@ class C: assert CSer == CSer2 @pytest.mark.skip(reason="Fails on 3.8 for some reason") + @pytest.mark.group_one def test_serialize_structseq(self): import time import os @@ -1006,14 +1064,17 @@ def test_serialize_structseq(self): u = ping_pong(t) self.assert_is_copy(t, u) + @pytest.mark.group_one def test_serialize_ellipsis(self): u = ping_pong(...) self.assertIs(..., u) + @pytest.mark.group_one def test_serialize_notimplemented(self): u = ping_pong(NotImplemented) self.assertIs(NotImplemented, u) + @pytest.mark.group_one def test_serialize_singleton_types(self): # Issue #6477: Test that types of built-in singletons can be pickled. singletons = [None, ..., NotImplemented] @@ -1021,6 +1082,7 @@ def test_serialize_singleton_types(self): u = ping_pong(type(singleton)) self.assertIs(type(singleton), u) + @pytest.mark.group_one def test_serialize_many_puts_and_gets(self): # Test that internal data structures correctly deal with lots of # puts/gets. @@ -1032,6 +1094,7 @@ def test_serialize_many_puts_and_gets(self): self.assert_is_copy(obj, loaded) @pytest.mark.skip(reason="Not sure that TP should insist on this") + @pytest.mark.group_one def test_serialize_attribute_name_interning(self): # Test that attribute names of pickled objects are interned when # unpickling. @@ -1045,6 +1108,7 @@ def test_serialize_attribute_name_interning(self): for x_key, y_key in zip(x_keys, y_keys): self.assertIs(x_key, y_key) + @pytest.mark.group_one def test_serialize_large_pickles(self): # Test the correctness of internal buffering routines when handling # large data. @@ -1053,6 +1117,7 @@ def test_serialize_large_pickles(self): self.assertEqual(len(loaded), len(data)) self.assertEqual(loaded, data) + @pytest.mark.group_one def test_serialize_nested_names(self): global Nested @@ -1074,6 +1139,7 @@ class C: unpickled = ping_pong(obj, sc) self.assertIs(obj, unpickled) + @pytest.mark.group_one def test_serialize_lambdas_more(self): sc = SerializationContext() @@ -1100,6 +1166,7 @@ def test_serialize_lambdas_more(self): self.assertEqual(deserialized_f_2(10), 11) + @pytest.mark.group_one def test_serialize_result_of_decorator(self): sc = SerializationContext() @@ -1117,10 +1184,12 @@ def g(x): self.assertEqual(g2(10), g(10)) + @pytest.mark.group_one def test_serialize_modules(self): sc = SerializationContext() self.assertIs(pytz, sc.deserialize(sc.serialize(pytz))) + @pytest.mark.group_one def test_serialize_submodules(self): sc = SerializationContext() @@ -1129,6 +1198,7 @@ def test_serialize_submodules(self): numpy.linalg ) + @pytest.mark.group_one def test_serialize_functions_with_references_in_list_comprehensions(self): sc = SerializationContext() @@ -1141,6 +1211,7 @@ def f(): self.assertEqual(sc.deserialize(sc.serialize(f))(), "testfunction") + @pytest.mark.group_one def test_serialize_functions_with_nested_list_comprehensions(self): sc = SerializationContext() @@ -1149,6 +1220,7 @@ def f(): self.assertEqual(sc.deserialize(sc.serialize(f))(), f()) + @pytest.mark.group_one def test_serialize_lambdas_with_nested_list_comprehensions(self): sc = SerializationContext() @@ -1156,6 +1228,7 @@ def test_serialize_lambdas_with_nested_list_comprehensions(self): self.assertEqual(sc.deserialize(sc.serialize(f))(), f()) + @pytest.mark.group_one def test_serialize_large_lists(self): x = SerializationContext() @@ -1171,6 +1244,7 @@ def test_serialize_large_lists(self): self.assertEqual(lst, l2) + @pytest.mark.group_one def test_serialize_large_numpy_arrays(self): x = SerializationContext() @@ -1179,6 +1253,7 @@ def test_serialize_large_numpy_arrays(self): self.assertTrue(numpy.all(a == a2)) + @pytest.mark.group_one def test_serialize_datetime_objects(self): x = SerializationContext() @@ -1206,6 +1281,7 @@ def test_serialize_datetime_objects(self): d2 = x.deserialize(x.serialize(d)) self.assertEqual(d, d2, (d, type(d))) + @pytest.mark.group_one def test_serialize_dict(self): x = SerializationContext() @@ -1217,6 +1293,7 @@ def test_serialize_dict(self): self.assertEqual(d, d2) + @pytest.mark.group_one def test_serialize_set(self): x = SerializationContext() @@ -1232,6 +1309,7 @@ def test_serialize_set(self): s.clear() self.assertEqual(s, x.deserialize(x.serialize(s))) + @pytest.mark.group_one def test_serialize_recursive_dict_more(self): D = Forward("D") D = D.define(Dict(str, OneOf(str, D))) @@ -1247,6 +1325,7 @@ def test_serialize_recursive_dict_more(self): self.assertEqual(d2['recurses']['recurses']['hi'], 'bye') @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_serialize_dict_doesnt_leak(self): T = Dict(int, int) d = T({i: i+1 for i in range(100)}) @@ -1261,6 +1340,7 @@ def test_serialize_dict_doesnt_leak(self): self.assertLess(currentMemUsageMb(), usage+1) @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_serialize_array_doesnt_leak(self): d = numpy.ones(1000000) x = SerializationContext() @@ -1275,6 +1355,7 @@ def test_serialize_array_doesnt_leak(self): self.assertLess(currentMemUsageMb(), usage+2) @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_deserialize_set_doesnt_leak(self): s = set(range(1000000)) x = SerializationContext() @@ -1290,6 +1371,7 @@ def test_deserialize_set_doesnt_leak(self): self.assertLess(currentMemUsageMb(), usage+1) @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_deserialize_tuple_doesnt_leak(self): s = tuple(range(1000000)) x = SerializationContext() @@ -1305,6 +1387,7 @@ def test_deserialize_tuple_doesnt_leak(self): self.assertLess(currentMemUsageMb(), usage+1) @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_deserialize_list_doesnt_leak(self): s = list(range(1000000)) x = SerializationContext() @@ -1320,6 +1403,7 @@ def test_deserialize_list_doesnt_leak(self): self.assertLess(currentMemUsageMb(), usage+1) @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_deserialize_class_doesnt_leak(self): class C(Class, Final): x = Member(int) @@ -1339,6 +1423,7 @@ def f(self, x=10): self.assertLess(currentMemUsageMb(), usage+.5) + @pytest.mark.group_one def test_serialize_named_tuples_with_extra_fields(self): T1 = NamedTuple(x=int) T2 = NamedTuple(x=int, y=float, z=str) @@ -1348,6 +1433,7 @@ def test_serialize_named_tuples_with_extra_fields(self): T2(x=10, y=0.0, z="") ) + @pytest.mark.group_one def test_serialize_listof(self): T = ListOf(int) @@ -1360,6 +1446,7 @@ def test_serialize_listof(self): self.assertEqual(aPopulatedList, deserialize(T, serialize(T, aPopulatedList))) self.assertEqual(refcount(deserialize(T, serialize(T, aPopulatedList))), 1) + @pytest.mark.group_one def test_serialize_classes(self): class AClass(Class, Final): x = Member(int) @@ -1379,6 +1466,7 @@ class AClass(Class, Final): self.assertEqual(refcount(a2), 1) + @pytest.mark.group_one def test_embedded_messages(self): T = NamedTuple(x=TupleOf(int)) T_with_message = NamedTuple(x=EmbeddedMessage) @@ -1393,6 +1481,7 @@ def test_embedded_messages(self): self.assertEqual(t2.x, t.x) self.assertEqual(t2.y, t.x) + @pytest.mark.group_one def test_serialize_untyped_classes(self): sc = SerializationContext() @@ -1412,6 +1501,7 @@ def f(self): self.assertEqual(C2(20).f(), 30) self.assertEqual(C2(20).g(), 20) + @pytest.mark.group_one def test_serialize_functions_with_return_types(self): sc = SerializationContext() @@ -1422,6 +1512,7 @@ def f(x) -> int: f2 = sc.deserialize(sc.serialize(f)) self.assertEqual(f2(10.5), 10) + @pytest.mark.group_one def test_serialize_functions_with_annotations(self): sc = SerializationContext() @@ -1440,6 +1531,7 @@ def f(x: B = C) -> B: self.assertEqual(f(), f2()) + @pytest.mark.group_one def test_serialize_typed_classes(self): sc = SerializationContext() @@ -1474,6 +1566,7 @@ def g(self): C(x=10, y=30).g() ) + @pytest.mark.group_one def test_serialize_recursive_typed_classes(self): sc = SerializationContext() @@ -1506,6 +1599,7 @@ def getSelf(self) -> B: self.assertTrue(isinstance(instance2.getSelf(), B2)) self.assertTrue(isinstance(instance2.getSelf(), B3)) + @pytest.mark.group_one def test_serialize_functions_with_cells(self): def fMaker(): @Entrypoint @@ -1526,6 +1620,7 @@ def f(x): self.assertEqual(f2(10), 11) + @pytest.mark.group_one def test_reserialize_functions(self): sc = SerializationContext({'Entrypoint': Entrypoint}) @@ -1586,6 +1681,7 @@ def h(x): self.assertEqual(f3(10), 11) self.assertEqual(h2(10), (13, 14)) + @pytest.mark.group_one def test_serialize_unnamed_classes_retains_identity(self): sc = SerializationContext() @@ -1599,6 +1695,7 @@ def f(self): assert B2().f() is B2 assert B().f() is B2 + @pytest.mark.group_one def test_serialize_unnamed_typed_classes_retains_identity(self): sc = SerializationContext() @@ -1612,6 +1709,7 @@ def f(self) -> object: assert B2().f() is B2 assert B().f() is B2 + @pytest.mark.group_one def test_serialize_lambda_preserves_identity_hash(self): sc = SerializationContext() @@ -1623,6 +1721,7 @@ def aFunction(self, x): assert identityHash(aFunction) == identityHash(aFunction2) + @pytest.mark.group_one def test_serialize_subclasses(self): sc = SerializationContext() @@ -1659,6 +1758,7 @@ class C2(B, Final): aList2[2].b.x = 100 self.assertEqual(aList2[0].x, 100) + @pytest.mark.group_one def test_serialize_subclasses_multiple_views(self): sc = SerializationContext() @@ -1683,6 +1783,7 @@ class C3(C2): for e in t: self.assertEqual(e.x4, 2) + @pytest.mark.group_one def test_serialize_classes_with_staticmethods_and_properties(self): sc = SerializationContext() @@ -1700,6 +1801,7 @@ def p(self): self.assertEqual(B2.f(10), 11) self.assertEqual(B().p, 11) + @pytest.mark.group_one def test_roundtrip_serialization_of_functions_with_annotations(self): T = int @@ -1713,6 +1815,7 @@ def f() -> T: f2Typed = Function(f2) self.assertEqual(f2Typed.overloads[0].returnType, int) + @pytest.mark.group_one def test_roundtrip_serialization_of_functions_with_defaults(self): def f(x=10, *, y=20): return x + y @@ -1721,6 +1824,7 @@ def f(x=10, *, y=20): f2 = sc.deserialize(sc.serialize(f)) self.assertEqual(f2(), 30) + @pytest.mark.group_one def test_roundtrip_serialization_of_functions_with_closures(self): F = int @@ -1739,6 +1843,7 @@ def fWrapper(): fWrapper2 = sc.deserialize(sc.serialize(fWrapper)) self.assertEqual(fWrapper2(), 1) + @pytest.mark.group_one def test_serialize_many_large_equivalent_strings(self): sc = SerializationContext() @@ -1754,6 +1859,7 @@ def f(x): 20 ) + @pytest.mark.group_one def test_serialize_class_with_classmethod(self): class ClassWithClassmethod(Class, Final): @classmethod @@ -1769,6 +1875,7 @@ def ownName(cls): ClassWithClassmethod.ownName(), ) + @pytest.mark.group_one def test_serialize_class_with_nontrivial_signatures(self): N = NamedTuple(x=int, y=float) @@ -1789,12 +1896,14 @@ def hi(x: ListOf(N)): ClassWithStaticmethod.hi(lst), ) + @pytest.mark.group_one def test_serialize_class_simple(self): sc = SerializationContext() self.assertTrue( sc.deserialize(sc.serialize(C)) is C ) + @pytest.mark.group_one def test_serialize_unnamed_alternative(self): X = Alternative("X", A={}, B={'x': int}) @@ -1804,6 +1913,7 @@ def test_serialize_unnamed_alternative(self): sc.deserialize(sc.serialize(X)).B(x=2).x == 2 ) + @pytest.mark.group_one def test_serialize_mutually_recursive_unnamed_forwards_alternatives(self): X1 = Forward("X1") X2 = Forward("X2") @@ -1814,6 +1924,7 @@ def test_serialize_mutually_recursive_unnamed_forwards_alternatives(self): sc = SerializationContext() sc.deserialize(sc.serialize(X1)) + @pytest.mark.group_one def test_compression_has_checksum(self): sc = SerializationContext().withCompression() data = ListOf(float)(range(100)) @@ -1824,6 +1935,7 @@ def test_compression_has_checksum(self): with self.assertRaisesRegex(Exception, "blockChecksum"): sc.deserialize(bytes(serDat)) + @pytest.mark.group_one def test_serialize_mutually_recursive_unnamed_forwards_tuples(self): X1 = Forward("X1") X2 = Forward("X2") @@ -1840,6 +1952,7 @@ def test_serialize_mutually_recursive_unnamed_forwards_tuples(self): sc = SerializationContext().withoutCompression() sc.deserialize(sc.serialize(X1)) + @pytest.mark.group_one def test_serialize_named_alternative(self): self.assertEqual( ModuleLevelAlternative.__module__, @@ -1853,6 +1966,7 @@ def test_serialize_named_alternative(self): ModuleLevelAlternative ) + @pytest.mark.group_one def test_serialize_unnamed_recursive_alternative(self): X = Forward("X") X = X.define( @@ -1865,6 +1979,7 @@ def test_serialize_unnamed_recursive_alternative(self): sc.deserialize(sc.serialize(X)).B(x=2).x == 2 ) + @pytest.mark.group_one def test_serialize_module_level_class(self): assert ModuleLevelClass.__module__ == 'typed_python.types_serialization_test' @@ -1877,6 +1992,7 @@ def test_serialize_module_level_class(self): sc.serialize(ModuleLevelClass), ) + @pytest.mark.group_one def test_serialize_unnamed_subclass_of_named_tuple(self): class SomeNamedTuple(NamedTuple(x=int)): def f(self): @@ -1894,6 +2010,7 @@ def f(self): 10 ) + @pytest.mark.group_one def test_serialize_named_subclass_of_named_tuple(self): sc = SerializationContext() @@ -1927,6 +2044,7 @@ def test_serialize_named_subclass_of_named_tuple(self): 10 ) + @pytest.mark.group_one def test_serialize_builtin_tp_functions(self): sc = SerializationContext() @@ -1941,6 +2059,7 @@ def test_serialize_builtin_tp_functions(self): sc.deserialize(sc.serialize(thing)), thing ) + @pytest.mark.group_one def test_serialize_methods_on_named_classes(self): sc = SerializationContext() @@ -1953,11 +2072,13 @@ def test_serialize_methods_on_named_classes(self): self.assertIs(m1, m2) + @pytest.mark.group_one def test_serialize_frozenset(self): sc = SerializationContext() assert sc.nameForObject(frozenset) is not None + @pytest.mark.group_one def test_serialize_entrypointed_modulelevel_functions(self): sc = SerializationContext() @@ -1971,6 +2092,7 @@ def test_serialize_entrypointed_modulelevel_functions(self): type(sc.deserialize(sc.serialize(moduleLevelEntrypointedFunction))) ) + @pytest.mark.group_one def test_serialize_entrypointed_modulelevel_class_functions(self): sc = SerializationContext() @@ -1984,6 +2106,7 @@ def test_serialize_entrypointed_modulelevel_class_functions(self): type(sc.deserialize(sc.serialize(ModuleLevelClass.f))) ) + @pytest.mark.group_one def test_serialize_type_function(self): sc = SerializationContext() @@ -1992,6 +2115,7 @@ def test_serialize_type_function(self): sc.deserialize(sc.serialize(FancyClass(int))) ) + @pytest.mark.group_one def test_serialize_module_level_recursive_forward(self): sc = SerializationContext() @@ -2000,6 +2124,7 @@ def test_serialize_module_level_recursive_forward(self): sc.deserialize(sc.serialize(ModuleLevelRecursiveForward)) ) + @pytest.mark.group_one def test_serialize_reference_to_module_level_constant(self): sc = SerializationContext() @@ -2007,6 +2132,7 @@ def test_serialize_reference_to_module_level_constant(self): assert getter()[0] is moduleLevelDict + @pytest.mark.group_one def test_serialize_type_with_reference_to_self_through_closure(self): @Entrypoint def f(x): @@ -2022,6 +2148,7 @@ class C: # C and 'f' are mutually recursive sc.deserialize(sc.serialize(C)) + @pytest.mark.group_one def test_serialize_cell_type(self): sc = SerializationContext() @@ -2033,6 +2160,7 @@ def getCellType(): assert callFunctionInFreshProcess(getCellType, ()) is getCellType() + @pytest.mark.group_one def test_self_visible_base_class_forward_resolved(self): Base = Forward("Base") @@ -2043,6 +2171,7 @@ def f(self, other: Base) -> Base: assert 'Forward' not in recursiveTypeGroupRepr(Base) + @pytest.mark.group_one def test_serialize_classes_with_visible_base_class(self): def getOptimizer(): Base = Forward("Base") @@ -2065,6 +2194,7 @@ def __add__(self, other: Base) -> Base: assert isinstance(Base() + Base() + Base(), Base) assert isinstance(Base() + Base() + Base(), Child) + @pytest.mark.group_one def test_serialize_self_referencing_class_basic(self): def g(x): return 10 @@ -2087,6 +2217,7 @@ def g(self): assert c.g() == 10 assert c.s() is type(c) + @pytest.mark.group_one def test_serialize_self_referencing_class_through_tuple(self): def g(x): return 10 @@ -2110,6 +2241,7 @@ def g(self): assert c.g() == 10 assert c.s() is type(c) + @pytest.mark.group_one def test_names_of_builtin_alternatives(self): sc = SerializationContext().withoutCompression() @@ -2129,11 +2261,13 @@ def test_names_of_builtin_alternatives(self): assert len(sc.serialize(native_ast.Type)) < 100 assert len(sc.serialize(TupleOf(native_ast.Type))) < 100 + @pytest.mark.group_one def test_badly_named_module_works(self): sc = SerializationContext() assert sc.objectFromName(".modules.NOT.A.REAL.MODULE") is None + @pytest.mark.group_one def test_can_serialize_nullptrs(self): x = PointerTo(int)() @@ -2142,6 +2276,7 @@ def test_can_serialize_nullptrs(self): assert sc.deserialize(sc.serialize(type(x))) == type(x) assert sc.deserialize(sc.serialize(x)) == x + @pytest.mark.group_one def test_can_serialize_subclassOf(self): class C(Class): pass @@ -2157,6 +2292,7 @@ class D(C): assert sc.deserialize(sc.serialize(T)) is T assert sc.deserialize(sc.serialize(lst)) == lst + @pytest.mark.group_one def test_can_serialize_nested_function_references(self): def lenProxy(x): return len(x) @@ -2180,6 +2316,7 @@ def makeLenProxyWeirdGlobals(): assert lenProxyDeserialized("asdf") == 4 @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_set_closure_doesnt_leak(self): def makeFunWithClosure(x): def f(): @@ -2194,6 +2331,7 @@ def f(): assert currentMemUsageMb() < mem + 1 + @pytest.mark.group_one def test_serialize_without_line_info_doesnt_have_path(self): def aFun(): return 10 @@ -2203,6 +2341,7 @@ def aFun(): assert b'types_serialization_test' not in sc.serialize(aFun.__code__) assert b'types_serialization_test' not in sc.serialize(aFun.__code__) + @pytest.mark.group_one def test_serialize_builtin_type_objects(self): s = SerializationContext() @@ -2213,6 +2352,7 @@ def check(x): check(types.FunctionType) check(types.ModuleType) + @pytest.mark.group_one def test_serialize_self_referential_class(self): def makeSeesItself(): class SeesItself: @@ -2229,6 +2369,7 @@ def seeItself(self, a, b, c, d): assert SeesItself.seeItself(1, 2, 3, 4, 5) is SeesItself + @pytest.mark.group_one def test_serialize_anonymous_module(self): with tempfile.TemporaryDirectory() as tf: c = SerializationContext().withFunctionGlobalsAsIs() @@ -2255,6 +2396,7 @@ def test_serialize_anonymous_module(self): aModule2.y = 30 assert aModule2.f(10) == 40 + @pytest.mark.group_one def test_serialize_locks(self): l = threading.Lock() x = (l, l) @@ -2265,11 +2407,13 @@ def test_serialize_locks(self): assert x2[0] is x2[1] and isinstance(x2[0], type(x[0])) + @pytest.mark.group_one def test_serialize_methods(self): sc = SerializationContext() assert sc.deserialize(sc.serialize(ModuleLevelClass().f))() == "HI!" + @pytest.mark.group_one def test_can_deserialize_anonymous_class_methods(self): class Cls: def f(self): @@ -2277,6 +2421,7 @@ def f(self): assert callFunctionInFreshProcess(Cls().f, ()) is Cls + @pytest.mark.group_one def test_serialization_preserves_forward_structure_in_classes(self): def getCls(): Cls = Forward("Cls") @@ -2295,6 +2440,7 @@ def f(self) -> Cls: Cls2 = getCls() assert Cls2.f.__annotations__['return'].__typed_python_category__ == 'Forward' + @pytest.mark.group_one def test_can_deserialize_untyped_forward_class_methods_1(self): Cls = Forward("Cls") @@ -2306,6 +2452,7 @@ def f(self) -> Cls: assert callFunctionInFreshProcess(Cls, ()).f() == "HI" + @pytest.mark.group_one def test_can_deserialize_untyped_forward_class_methods_2(self): def getCls(): Cls = Forward("Cls") @@ -2320,6 +2467,7 @@ def f(self) -> Cls: callFunctionInFreshProcess(getCls, ()) + @pytest.mark.group_one def test_can_deserialize_forward_class_methods_tp_class(self): Cls = Forward("Cls") @@ -2332,6 +2480,7 @@ def f(self) -> Cls: assert callFunctionInFreshProcess(Cls, ()).f().m == "HI" + @pytest.mark.group_one def test_can_deserialize_forward_class_methods_tp_class_no_self_reference(self): Cls = Forward("Cls") @@ -2344,6 +2493,7 @@ def f(self) -> str: assert callFunctionInFreshProcess(Cls, ()).f() == "HI" + @pytest.mark.group_one def test_deserialize_regular_class_retains_identity(self): class Cls: # recall that regular classes ignore their annotations @@ -2359,6 +2509,7 @@ def f(self): "sys.version_info.minor >= 8", reason="serialization differences on 3.8 we need to investigate" ) + @pytest.mark.group_one def test_identity_of_function_with_annotation_stable(self): def makeFunction(): @Entrypoint @@ -2375,6 +2526,7 @@ def f(x: float): "sys.version_info.minor >= 8", reason="serialization differences on 3.8 we need to investigate" ) + @pytest.mark.group_one def test_identity_of_function_with_default_value_stable(self): def makeFunction(): @Entrypoint @@ -2388,6 +2540,7 @@ def f(x=None): assert identityHash(f) == identityHashOfF @pytest.mark.skip(reason='broken') + @pytest.mark.group_one def test_deserialize_untyped_class_in_forward_retains_identity(self): # this still breaks because we have some inconsistency between how # the MRTG gets created after deserialization when we have a regular @@ -2420,6 +2573,7 @@ def pad(x): assert identityHash(Cls) == identityHash(Cls2) + @pytest.mark.group_one def test_deserialize_tp_class_retains_identity(self): Cls = Forward("Cls") @@ -2433,6 +2587,7 @@ def f(self) -> Cls: assert identityHash(Cls) == identityHash(Cls2) + @pytest.mark.group_one def test_call_method_dispatch_on_two_versions_of_same_class_with_recursion_defined_in_host(self): Base = Forward("Base") @@ -2470,6 +2625,7 @@ def callF(x): assert callFunctionInFreshProcess(deserializeAndCall, (aChildBytes,)) == "OK" + @pytest.mark.group_one def test_call_method_dispatch_on_two_versions_of_self_referential_class_produced_differently(self): def deserializeAndCall(): Base = Forward("Base") @@ -2502,6 +2658,7 @@ def f(self, x) -> int: assert callF1(child1) == callF2(child2) + @pytest.mark.group_one def test_deserialize_anonymous_recursive_base_and_subclass(self): def deserializeAndCall(): Base = Forward("Base") @@ -2539,6 +2696,7 @@ def callF(x: Child): assert callF1(child1) == callF2(child2) + @pytest.mark.group_one def test_identity_hash_of_lambda_doesnt_change_serialization(self): s = SerializationContext() @@ -2552,6 +2710,7 @@ def test_identity_hash_of_lambda_doesnt_change_serialization(self): assert ser1 == ser2 + @pytest.mark.group_one def test_call_method_dispatch_on_two_versions_of_same_class_with_recursion(self): Base = Forward("Base") @@ -2596,6 +2755,7 @@ def f(self, x) -> int: @pytest.mark.skip( reason="serialization differences on 3.8 we need to investigate" ) + @pytest.mark.group_one def test_serialization_of_entrypointed_function_stable(self): def returnSerializedForm(): s = SerializationContext().withoutCompression() @@ -2643,6 +2803,7 @@ def pad(x): assert childBytes == childBytes2 + @pytest.mark.group_one def test_serialize_abc_subclass(self): # ensure we can serialize and hash anonymous classes descended from ABC def makeClasses(): @@ -2682,6 +2843,7 @@ def f(self): assert AnotherChildClass().f() == "concrete2" + @pytest.mark.group_one def test_serialize_mutually_recursive_untyped_classes(self): # ensure we can serialize and hash anonymous classes descended from ABC def makeClasses(): @@ -2699,6 +2861,7 @@ class ChildClass(BaseClass): assert type(BaseClass.getChild()) is ChildClass + @pytest.mark.group_one def test_serialize_recursive_function(self): # ensure we can serialize and hash anonymous classes descended from ABC def makeF(): @@ -2718,6 +2881,7 @@ def makeF(): assert f(10) == 10 + @pytest.mark.group_one def test_can_serialize_classes_with_methods_and_custom_globals(self): def serializeIt(): def f(self): @@ -2742,6 +2906,7 @@ class Child(Base): assert Child2().func() == 10 + @pytest.mark.group_one def test_can_reserialize_deserialized_function_with_no_backing_file(self): # when we serialize an anonymous function on one machine, where we have # a definition for that code, we need to ensure that on another machine, @@ -2786,6 +2951,7 @@ def makeF(): assert f(10) == f2(10) + @pytest.mark.group_one def test_globals_of_entrypointed_functions_serialized_externally(self): def makeC(): with tempfile.TemporaryDirectory() as tempdir: @@ -2820,6 +2986,7 @@ def makeC(): assert C.anF() is C assert C.anF.overloads[0].methodOf.Class is C + @pytest.mark.group_one def test_held_class_serialized_externally(self): def makeC(): with tempfile.TemporaryDirectory() as tempdir: @@ -2853,6 +3020,7 @@ def makeC(): assert type(C.make()) is C + @pytest.mark.group_one def test_serialization_independent_of_whether_function_is_hashed(self): s = SerializationContext().withoutLineInfoEncoded().withoutCompression() @@ -2864,6 +3032,7 @@ def test_serialization_independent_of_whether_function_is_hashed(self): assert s1 == s2 + @pytest.mark.group_one def test_serialization_has_no_filename_reference(self): def makeF(modulename): with tempfile.TemporaryDirectory() as tempdir: @@ -2919,6 +3088,7 @@ def checkSame(f1, f2): checkSame(Entrypoint(f1), Entrypoint(f2)) checkSame(NotCompiled(f1), NotCompiled(f2)) + @pytest.mark.group_one def test_serialize_anonymous_class_with_defaults_and_nonempty(self): class C1(Class): x1 = Member(int, default_value=10, nonempty=True) @@ -2945,6 +3115,7 @@ class C1(Class): assert C2.ClassMembers['x3'].defaultValue == 2.5 assert C2.ClassMembers['x4'].defaultValue is None + @pytest.mark.group_one def test_serialize_unresolved_forward(self): F = Forward("Hi") T = NamedTuple(x=F) @@ -2955,6 +3126,7 @@ def test_serialize_unresolved_forward(self): assert T2.ElementTypes[0].__typed_python_category__ == "Forward" + @pytest.mark.group_one def test_serialization_doesnt_starve_gil(self): checkCount = [0] serializeCount = [0] @@ -3001,11 +3173,13 @@ def serializeThread(): assert .05 <= avgTimeHeld[0] <= .95 assert .05 <= avgTimeHeld[1] <= .95 + @pytest.mark.group_one def test_serialization_context_names_for_pmap_functions(self): from typed_python.lib.pmap import ensureThreads sc = SerializationContext() assert sc.nameForObject(type(ensureThreads)) is not None + @pytest.mark.group_one def test_pmap_of_notcompiled_serialized_externally(self): def makeC(): with tempfile.TemporaryDirectory() as tempdir: @@ -3046,6 +3220,7 @@ def makeC(): print("DO!") pmap(args, f, str, minGranularity=10000) + @pytest.mark.group_one def test_serialize_pyobj_in_MRTG(self): def getX(): class C: diff --git a/typed_python/types_test.py b/typed_python/types_test.py index 721c62b86..54ed06bd0 100644 --- a/typed_python/types_test.py +++ b/typed_python/types_test.py @@ -184,10 +184,12 @@ def pickRandomly(self): class TypesTests(unittest.TestCase): + @pytest.mark.group_one def test_alternative_module(self): assert AnAlternative.__module__ == 'typed_python.types_test' assert AForwardAlternative.__module__ == 'typed_python.types_test' + @pytest.mark.group_one def test_refcount_bug_with_simple_string(self): with self.assertRaisesRegex(TypeError, "first argument to refcount '111' not a permitted Type"): _types.refcount(111) @@ -205,6 +207,7 @@ def check_expected_performance(self, elapsed, expected=1.0): .format(expected=expected, elapsed=elapsed) ) + @pytest.mark.group_one def test_object_binary_compatibility(self): ibc = _types.isBinaryCompatible @@ -228,6 +231,7 @@ class Y(NamedTuple(a=int, b=int)): self.assertFalse(ibc(OneOf(int, float), OneOf(float, int))) self.assertTrue(ibc(OneOf(int, X), OneOf(int, Y))) + @pytest.mark.group_one def test_binary_compatibility_incompatible_alternatives(self): ibc = _types.isBinaryCompatible @@ -245,6 +249,7 @@ def test_binary_compatibility_incompatible_alternatives(self): self.assertFalse(ibc(A1.X, A2.X)) self.assertFalse(ibc(A1.Y, A2.Y)) + @pytest.mark.group_one def test_binary_compatibility_compatible_alternatives(self): ibc = _types.isBinaryCompatible @@ -257,12 +262,14 @@ def test_binary_compatibility_compatible_alternatives(self): self.assertFalse(ibc(A1.X, A2.Y)) self.assertFalse(ibc(A1.Y, A2.X)) + @pytest.mark.group_one def test_name_of_type_as_value_instances(self): T1 = Alternative("T1") assert Value(T1).__name__ == 'Value(' + T1.__name__ + ")" assert Value(2).__name__ == '2' + @pytest.mark.group_one def test_callable_alternatives(self): def myCall(self): if self.matches.One: @@ -289,15 +296,18 @@ def myCall(self): two = alt.Two() two() + @pytest.mark.group_one def test_object_bytecounts(self): self.assertEqual(_types.bytecount(type(None)), 0) self.assertEqual(_types.bytecount(Int8), 1) self.assertEqual(_types.bytecount(int), 8) + @pytest.mark.group_one def test_type_stringification(self): self.assertEqual(str(_types.Int8), "") self.assertEqual(str(Tuple(int)), "") + @pytest.mark.group_one def test_tuple_of(self): tupleOfInt = TupleOf(int) i = tupleOfInt(()) @@ -315,6 +325,7 @@ def test_tuple_of(self): with self.assertRaisesRegex(AttributeError, "has no attribute 'x'"): tupleOfInt((1, 2, 3)).x = 2 + @pytest.mark.group_one def test_one_of_and_types(self): # when we use types in OneOf, we need to wrap them in Value. Otherwise we can't # tell the difference between OneOf(int) and OneOf(Value(int)) @@ -342,6 +353,7 @@ def test_one_of_and_types(self): X2(int) X2(float) + @pytest.mark.group_one def test_const_dict_add_mappable(self): T = ConstDict(int, int) @@ -360,6 +372,7 @@ def test_const_dict_add_mappable(self): {1: 2, 2: 3} ) + @pytest.mark.group_one def test_const_dict_add_mappable_with_exceptions(self): T = ConstDict(int, TupleOf(int)) @@ -383,12 +396,14 @@ def test_const_dict_add_mappable_with_exceptions(self): # the refcount of 'to' should not have increased self.assertEqual(_types.refcount(to), 2) + @pytest.mark.group_one def test_one_of_alternative(self): X = Alternative("X", V={'a': int}) Ox = OneOf(None, X) self.assertEqual(Ox(X.V(a=10)), X.V(a=10)) + @pytest.mark.group_one def test_one_of_py_subclass(self): class X(NamedTuple(x=int)): def f(self): @@ -400,6 +415,7 @@ def f(self): self.assertEqual(X(x=10).f(), 10) self.assertEqual(Ox(X(x=10)).f(), 10) + @pytest.mark.group_one def test_one_of_distinguishes_py_subclasses(self): class X(NamedTuple(x=int)): def f(self): @@ -414,6 +430,7 @@ def f(self): self.assertTrue(isinstance(XorX2(X()), X)) self.assertTrue(isinstance(XorX2(X2()), X2)) + @pytest.mark.group_one def test_function_as_type_arg(self): @Function def f(x: int): @@ -427,6 +444,7 @@ def f(x: int): @flaky(max_runs=3, min_passes=1) @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_tuple_of_tuple_of_perf(self): tupleOfInt = TupleOf(int) tupleOfTupleOfInt = TupleOf(tupleOfInt) @@ -451,6 +469,7 @@ def test_tuple_of_tuple_of_perf(self): @flaky(max_runs=3, min_passes=1) @pytest.mark.skipif('sys.platform=="darwin"') + @pytest.mark.group_one def test_tuple_of_string_perf(self): t = NamedTuple(a=str, b=str) @@ -462,10 +481,12 @@ def test_tuple_of_string_perf(self): print("Took ", elapsed, " to do 1mm") self.check_expected_performance(elapsed, expected=1.5) + @pytest.mark.group_one def test_default_initializer_oneof(self): x = OneOf(None, int) self.assertTrue(x() is None, repr(x())) + @pytest.mark.group_one def test_tuple_of_various_things(self): for thing, typeOfThing in [("hi", str), (b"somebytes", bytes), (1.0, float), (2, int), @@ -476,12 +497,14 @@ def test_tuple_of_various_things(self): self.assertTrue(type(t[0]) is typeOfThing) self.assertEqual(t[0], thing) + @pytest.mark.group_one def test_tuple_assign_fails(self): with self.assertRaisesRegex(TypeError, "does not support item assignment"): (1, 2, 3)[10] = 20 with self.assertRaisesRegex(TypeError, "does not support item assignment"): TupleOf(int)((1, 2, 3))[10] = 20 + @pytest.mark.group_one def test_list_of(self): L = ListOf(int) self.assertEqual(L.__qualname__, "ListOf(int)") @@ -514,6 +537,7 @@ def test_list_of(self): l3.append(23) self.assertEqual(l3, [10, 2, 3, 11, 10, 2, 3, 11, 23]) + @pytest.mark.group_one def test_list_resize(self): l1 = ListOf(TupleOf(int))() @@ -554,6 +578,7 @@ def test_list_resize(self): l1.clear() self.assertEqual(len(l1), 0) + @pytest.mark.group_one def test_one_of(self): o = OneOf(None, str) @@ -580,6 +605,7 @@ def test_one_of(self): with self.assertRaises(TypeError): o(False) + @pytest.mark.group_one def test_use_of_None(self): o1 = OneOf(None, str) o2 = OneOf(type(None), str) @@ -593,21 +619,26 @@ def test_use_of_None(self): s2 = Set(type(None)) assert s1.ElementType == s2.ElementType == type(None) # noqa + @pytest.mark.group_one def test_dict_equality_with_python(self): assert Dict(int, int)({1: 2}) == {1: 2} + @pytest.mark.group_one def test_ordering(self): # TODO: investigate and correct: with the ordering 1, True, the assertion o(True) is True fails o = OneOf(None, "hi", 1.5, True, 1, b"hi2") self.assertIs(o(True), True) + @pytest.mark.group_one def test_one_of_flattening(self): self.assertEqual(OneOf(OneOf(None, 1.0), OneOf(2.0, 3.0)), OneOf(None, 1.0, 2.0, 3.0)) + @pytest.mark.group_one def test_one_of_order_matters(self): self.assertNotEqual(OneOf(1.0, 2.0), OneOf(2.0, 1.0)) + @pytest.mark.group_one def test_type_filter(self): EvenInt = TypeFilter(int, lambda i: i % 2 == 0) @@ -626,6 +657,7 @@ def test_type_filter(self): with self.assertRaises(TypeError): e2 + (1,) + @pytest.mark.group_one def test_tuple_of_one_of_fixed_size(self): t = TupleOf(OneOf(0, 1, 2, 3, 4)) @@ -636,6 +668,7 @@ def test_tuple_of_one_of_fixed_size(self): self.assertEqual(len(serialize(t, typedInts)), len(ints) * 2 + 6) # 3 bytes for extra flags self.assertEqual(tuple(typedInts), ints) + @pytest.mark.group_one def test_tuple_of_one_of_multi(self): t = TupleOf(OneOf(int, bool)) @@ -653,6 +686,7 @@ def test_tuple_of_one_of_multi(self): self.assertEqual(tuple(typedThings), someThings) + @pytest.mark.group_one def test_compound_oneof(self): producer = RandomValueProducer() producer.addEvenly(1000, 2) @@ -671,12 +705,14 @@ def test_compound_oneof(self): for i in range(len(vals)): self.assertEqual(tupInst[i], vals[i], vals) + @pytest.mark.group_one def test_one_of_conversion_failure(self): o = OneOf(None, str) with self.assertRaises(TypeError): o(b"bytes") + @pytest.mark.group_one def test_one_of_in_tuple(self): t = Tuple(OneOf(None, str), str) @@ -689,6 +725,7 @@ def test_one_of_in_tuple(self): with self.assertRaises(IndexError): t((None, "hi2"))[2] + @pytest.mark.group_one def test_one_of_composite(self): t = OneOf(TupleOf(str), TupleOf(float)) @@ -698,6 +735,7 @@ def test_one_of_composite(self): with self.assertRaises(TypeError): t((1.0, "2.0")) + @pytest.mark.group_one def test_comparisons_in_one_of(self): t = OneOf(None, float) @@ -722,6 +760,7 @@ def map(x): for t2 in ts: self.assertTrue(f(t1, t2) is f(t(t1), t(t2))) + @pytest.mark.group_one def test_comparisons_equivalence(self): t = TupleOf(OneOf(None, str, bytes, float, int, TupleOf(int), bool),) @@ -767,6 +806,7 @@ def ge(a, b): (f, t1, t2, t((t1,)), t((t2,)), f(t1, t2), f(t((t1,)), t((t2,)))) ) + @pytest.mark.group_one def test_const_dict(self): t = ConstDict(str, str) @@ -784,6 +824,7 @@ def test_const_dict(self): self.assertTrue("c" in deserialize(t, serialize(t, t({'a': 'b', 'b': 'c', 'c': 'd', 'def': 'e'})))) self.assertTrue("def" in deserialize(t, serialize(t, t({'a': 'b', 'b': 'c', 'c': 'd', 'def': 'e'})))) + @pytest.mark.group_one def test_const_dict_get(self): a = ConstDict(str, str)({'a': 'b', 'c': 'd'}) @@ -791,6 +832,7 @@ def test_const_dict_get(self): self.assertEqual(a.get('asdf'), None) self.assertEqual(a.get('asdf', 20), 20) + @pytest.mark.group_one def test_const_dict_items_keys_and_values(self): a = ConstDict(str, str)({'a': 'b', 'c': 'd'}) @@ -798,11 +840,13 @@ def test_const_dict_items_keys_and_values(self): self.assertEqual(sorted(a.keys()), ['a', 'c']) self.assertEqual(sorted(a.values()), ['b', 'd']) + @pytest.mark.group_one def test_empty_string(self): a = ConstDict(str, str)({'a': ''}) print(a['a']) + @pytest.mark.group_one def test_dict_to_oneof(self): t = ConstDict(str, OneOf("A", "B", "ABCDEF")) a = t({'a': 'A', 'b': 'ABCDEF'}) @@ -812,6 +856,7 @@ def test_dict_to_oneof(self): self.assertEqual(a, deserialize(t, serialize(t, a))) + @pytest.mark.group_one def test_dict_assign_coercion(self): T = Dict(str, int) @@ -820,6 +865,7 @@ def test_dict_assign_coercion(self): self.assertEqual(t, {"hi": 1}) + @pytest.mark.group_one def test_dict_update(self): T = Dict(str, int) t = T() @@ -836,6 +882,7 @@ def test_dict_update(self): t.update(T({"hi": 2})) self.assertEqual(t, {"hi": 2}) + @pytest.mark.group_one def test_dict_clear(self): T = Dict(str, TupleOf(int)) @@ -857,6 +904,7 @@ def test_dict_clear(self): self.assertEqual(len(a), 0) + @pytest.mark.group_one def test_dict_clear_large(self): T = Dict(str, str) @@ -882,10 +930,12 @@ def test_dict_clear_large(self): d["1"] = "1" self.assertTrue("1" in d) + @pytest.mark.group_one def test_deserialize_primitive(self): x = deserialize(str, serialize(str, "a")) self.assertTrue(isinstance(x, str)) + @pytest.mark.group_one def test_dict_containment(self): for _ in range(100): producer = RandomValueProducer() @@ -899,6 +949,7 @@ def test_dict_containment(self): for k in v: self.assertTrue(k in v) + @pytest.mark.group_one def test_dict_keys_values_and_items(self): # check that 'Dict().keys' behaves correctly. T = Dict(str, int) @@ -953,6 +1004,7 @@ def test_dict_keys_values_and_items(self): with self.assertRaises(Exception): aDict.keys().keys() + @pytest.mark.group_one def test_const_dict_keys_values_and_items(self): # check that 'ConstDict().keys' behaves correctly. T = ConstDict(str, int) @@ -1010,6 +1062,7 @@ def test_const_dict_keys_values_and_items(self): with self.assertRaises(Exception): aDict.keys().keys() + @pytest.mark.group_one def test_const_dict_mixed(self): t = ConstDict(str, int) self.assertTrue(t({"a": 10})["a"] == 10) @@ -1017,12 +1070,14 @@ def test_const_dict_mixed(self): t = ConstDict(int, str) self.assertTrue(t({10: "a"})[10] == "a") + @pytest.mark.group_one def test_const_dict_comparison(self): t = ConstDict(str, str) self.assertEqual(t({'a': 'b'}), t({'a': 'b'})) self.assertLess(t({}), t({'a': 'b'})) + @pytest.mark.group_one def test_const_dict_lookup(self): for type_to_use, vals in [(int, list(range(20))), (bytes, [b'1', b'2', b'3', b'4', b'5'])]: @@ -1049,6 +1104,7 @@ def test_const_dict_lookup(self): assert last_k is None or k > last_k, (k, last_k) last_k = k + @pytest.mark.group_one def test_const_dict_lookup_time(self): int_dict = ConstDict(int, int) @@ -1058,6 +1114,7 @@ def test_const_dict_lookup_time(self): self.assertTrue(k in d) self.assertTrue(d[k] == k) + @pytest.mark.group_one def test_const_dict_of_dict(self): int_dict = ConstDict(int, int) int_dict_2 = ConstDict(int_dict, int_dict) @@ -1072,6 +1129,7 @@ def test_const_dict_of_dict(self): self.assertTrue(big[d] == d2) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_dict_hash_perf(self): str_dict = ConstDict(str, str) @@ -1085,11 +1143,13 @@ def test_dict_hash_perf(self): print(elapsed, " to do 1mm") self.check_expected_performance(elapsed) + @pytest.mark.group_one def test_mutable_dict_not_hashable(self): with self.assertRaisesRegex(Exception, "not hashable"): hash(Dict(int, int)()) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_const_dict_str_perf(self): t = ConstDict(str, str) @@ -1102,6 +1162,7 @@ def test_const_dict_str_perf(self): self.check_expected_performance(elapsed) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_const_dict_int_perf(self): t = ConstDict(int, int) @@ -1113,6 +1174,7 @@ def test_const_dict_int_perf(self): print("Took ", elapsed, " to do 1mm") self.check_expected_performance(elapsed) + @pytest.mark.group_one def test_const_dict_iter_int(self): t = ConstDict(int, int) @@ -1120,6 +1182,7 @@ def test_const_dict_iter_int(self): for k in aDict: self.assertEqual(aDict[k], k+1) + @pytest.mark.group_one def test_const_dict_iter_str(self): t = ConstDict(str, str) @@ -1127,6 +1190,7 @@ def test_const_dict_iter_str(self): for k in aDict: self.assertEqual(aDict[str(k)], str(int(k)+1)) + @pytest.mark.group_one def test_alternative_matcher_type(self): A = Alternative("A", X=dict(x=int)) @@ -1136,6 +1200,7 @@ def test_alternative_matcher_type(self): assert A.X().matches.X assert not A.X().matches.NotX + @pytest.mark.group_one def test_alternative_bytecounts(self): alt = Alternative( "Empty", @@ -1147,6 +1212,7 @@ def test_alternative_bytecounts(self): self.assertEqual(_types.bytecount(alt.X), 1) self.assertEqual(_types.bytecount(alt.Y), 1) + @pytest.mark.group_one def test_alternatives_with_Bytes(self): alt = Alternative( "Alt", @@ -1154,6 +1220,7 @@ def test_alternatives_with_Bytes(self): ) self.assertEqual(alt.x_0(a=b''), alt.x_0(a=b'')) + @pytest.mark.group_one def test_alternatives_with_str_func(self): alt = Alternative( "Alt", @@ -1165,6 +1232,7 @@ def test_alternatives_with_str_func(self): self.assertEqual(alt.x_0().f(), 1) self.assertEqual(str(alt.x_0()), "not_your_usual_str") + @pytest.mark.group_one def test_alternatives_with_str_and_repr(self): A = Alternative( "A", @@ -1178,6 +1246,7 @@ def test_alternatives_with_str_and_repr(self): self.assertEqual(repr(ListOf(A)([A.X()])), "[alt_repr]") self.assertEqual(str(ListOf(A)([A.X()])), "[alt_repr]") + @pytest.mark.group_one def test_alternative_magic_methods(self): A_attrs = {"q": "value-q", "z": "value-z"} @@ -1341,6 +1410,7 @@ def A2_setitem(self, i, v): A2.b()[123] = 7 self.assertEqual(A2.b()[123], 7) + @pytest.mark.group_one def test_alternative_iter(self): class A_iter(): @@ -1376,6 +1446,7 @@ def __next__(self): self.assertEqual([x for x in A.a()], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) self.assertEqual([x for x in reversed(A.a())], [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]) + @pytest.mark.group_one def test_alternative_as_iterator(self): class B_iter(): @@ -1403,6 +1474,7 @@ def __next__(self): self.assertEqual([x for x in A.a()], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) self.assertEqual([x for x in A.a()], []) + @pytest.mark.group_one def test_alternative_with(self): depth = 0 @@ -1428,6 +1500,7 @@ def A_exit(s, t, v, b): self.assertEqual(depth, 2) self.assertEqual(depth, 0) + @pytest.mark.group_one def test_empty_alternatives(self): a = Alternative( "Alt", @@ -1443,6 +1516,7 @@ def test_empty_alternatives(self): self.assertNotEqual(a.A(), a.B()) self.assertNotEqual(a.B(), a.A()) + @pytest.mark.group_one def test_extracted_alternatives_have_correct_type(self): Alt = Alternative( "Alt", @@ -1457,6 +1531,7 @@ def test_extracted_alternatives_have_correct_type(self): self.assertEqual(a, aTup[0]) self.assertTrue(type(a) is type(aTup[0])) # noqa + @pytest.mark.group_one def test_alternatives(self): alt = Alternative( "Alt", @@ -1483,6 +1558,7 @@ def test_alternatives(self): with self.assertRaisesRegex(AttributeError, "immutable"): a.x = 20 + @pytest.mark.group_one def test_alternatives_comparison(self): empty = Alternative("X", A={}, B={}) @@ -1505,6 +1581,7 @@ def test_alternatives_comparison(self): self.assertFalse(a.C(c="") == a.C(c="hi")) self.assertNotEqual(a.D(d=b""), a.D(d=b"hi")) + @pytest.mark.group_one def test_alternatives_add_operator(self): alt = Alternative( "Alt", @@ -1517,6 +1594,7 @@ def test_alternatives_add_operator(self): self.assertEqual(a+a, (a, a)) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_alternatives_radd_operator(self): alt = Alternative( "Alt", @@ -1534,6 +1612,7 @@ def test_alternatives_radd_operator(self): print(a + v) @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_alternatives_perf(self): alt = Alternative( "Alt", @@ -1552,6 +1631,7 @@ def test_alternatives_perf(self): print("Took ", elapsed, " to do 1mm") self.check_expected_performance(elapsed, expected=2.0) + @pytest.mark.group_one def test_object_hashing_and_equality(self): for _ in range(100): producer = RandomValueProducer() @@ -1571,6 +1651,7 @@ def test_object_hashing_and_equality(self): if type(v1) is type(v2): self.assertEqual(repr(v1), repr(v2), (v1, v2, type(v1), type(v2))) + @pytest.mark.group_one def test_bytes_repr(self): # macos has some weird behavior where it can't convert the numpy array # to bytes because of a unicode error. @@ -1584,6 +1665,7 @@ def test_bytes_repr(self): someBytes = b'"' + numpy.random.uniform(size=2).tobytes() self.assertEqual(repr(makeTuple(someBytes)), repr((someBytes,))) + @pytest.mark.group_one def test_equality_with_native_python_objects(self): tups = [(1, 2, 3), (), ("2",), (b"2",), (1, 2, 3, "b"), (2,), (None,)] @@ -1601,6 +1683,7 @@ def test_equality_with_native_python_objects(self): if tup1 != tup2: self.assertNotEqual( makeTupleOf(*tup1), tup2 ) + @pytest.mark.group_one def test_add_tuple_of(self): tupleOfInt = TupleOf(int) @@ -1611,11 +1694,13 @@ def test_add_tuple_of(self): self.assertEqual(tupleOfInt(tup1) + tupleOfInt(tup2), tupleOfInt(tup1+tup2)) self.assertEqual(tupleOfInt(tup1) + tup2, tupleOfInt(tup1+tup2)) + @pytest.mark.group_one def test_stringification_of_none(self): T = TupleOf(OneOf(None, str)) self.assertEqual(str(T([None, 'hi'])), '(None, "hi")') + @pytest.mark.group_one def test_slice_tuple_of(self): tupleOfInt = TupleOf(int) @@ -1635,6 +1720,7 @@ def test_slice_tuple_of(self): with self.assertRaises(IndexError): aTuple[i] + @pytest.mark.group_one def test_dictionary_subtraction_basic(self): intDict = ConstDict(int, int) @@ -1642,6 +1728,7 @@ def test_dictionary_subtraction_basic(self): self.assertEqual(intDict({1: 2, 3: 4}) - (1,), intDict({3: 4})) self.assertEqual(intDict({1: 2, 3: 4}) - (3,), intDict({1: 2})) + @pytest.mark.group_one def test_dictionary_addition_and_subtraction(self): someDicts = [{i: choice([1, 2, 3, 4, 5]) for i in range(choice([4, 6, 10, 20]))} for _ in range(20)] intDict = ConstDict(int, int) @@ -1667,6 +1754,7 @@ def test_dictionary_addition_and_subtraction(self): self.assertEqual(res, intDict(addResult)) + @pytest.mark.group_one def test_serialization_primitives(self): def checkCanSerialize(x): self.assertEqual(x, deserialize(type(x), serialize(type(x), x)), x) @@ -1690,6 +1778,7 @@ def checkCanSerialize(x): checkCanSerialize(True) checkCanSerialize(False) + @pytest.mark.group_one def test_serialization_bytecounts(self): ints = TupleOf(int)((1, 2, 3, 4)) @@ -1714,6 +1803,7 @@ def varintBytecount(value): print(time.time() - t0, " for ", len(ints)) + @pytest.mark.group_one def test_serialization_roundtrip(self): for _ in range(100): producer = RandomValueProducer() @@ -1732,10 +1822,12 @@ def test_serialization_roundtrip(self): self.assertEqual(str(v), str(v2)) self.assertEqual(v, v2, (v, v2, type(v), type(v2), type(v) is type(v2))) + @pytest.mark.group_one def test_create_invalid_tuple(self): with self.assertRaises(TypeError): Tuple((int, int)) + @pytest.mark.group_one def test_roundtrip_tuple(self): T = Tuple(str, bool, str) v = T(('1', False, '')) @@ -1744,6 +1836,7 @@ def test_roundtrip_tuple(self): self.assertEqual(v, v2) + @pytest.mark.group_one def test_roundtrip_alternative(self): A = Alternative("A", a0=dict(x_0=None)) T = NamedTuple(x0=A, x1=bool) @@ -1754,6 +1847,7 @@ def test_roundtrip_alternative(self): self.assertEqual(v, v2) + @pytest.mark.group_one def test_serialize_doesnt_leak(self): T = TupleOf(int) @@ -1769,6 +1863,7 @@ def getMem(): self.assertTrue(getMem() < m0 + 100) + @pytest.mark.group_one def test_const_dict_of_tuple(self): K = NamedTuple(a=OneOf(float, int), b=OneOf(float, int)) someKs = [K(a=0, b=0), K(a=1), K(a=10), K(b=10), K()] @@ -1798,6 +1893,7 @@ def test_const_dict_of_tuple(self): self.assertTrue(k in x) x[k] + @pytest.mark.group_one def test_conversion_of_binary_compatible(self): class T1(NamedTuple(a=int)): pass @@ -1814,6 +1910,7 @@ class T2Comp(NamedTuple(d=ConstDict(str, T1))): self.assertTrue(_types.isBinaryCompatible(T1Comp, T2Comp)) self.assertTrue(_types.isBinaryCompatible(T1, T2)) + @pytest.mark.group_one def test_binary_compatible_nested(self): def make(): class Interior(NamedTuple(a=int)): @@ -1829,6 +1926,7 @@ class Exterior(NamedTuple(a=Interior)): self.assertTrue(_types.isBinaryCompatible(E1, E2)) + @pytest.mark.group_one def test_python_objects_in_tuples(self): class NormalPyClass: pass @@ -1842,6 +1940,7 @@ class NormalPySubclass(NormalPyClass): self.assertIsInstance(nt.x, NormalPyClass) self.assertIsInstance(nt.y, NormalPySubclass) + @pytest.mark.group_one def test_construct_alternatives_with_positional_arguments(self): a = Alternative("A", HasOne={'a': str}, HasTwo={'a': str, 'b': str}) @@ -1856,6 +1955,7 @@ def test_construct_alternatives_with_positional_arguments(self): with self.assertRaises(TypeError): a.HasOne(a.HasTwo(a='1', b='b')) + @pytest.mark.group_one def test_unsafe_pointers_to_list_internals(self): x = ListOf(int)() x.resize(100) @@ -1882,6 +1982,7 @@ def test_unsafe_pointers_to_list_internals(self): aPointer.initialize(30) self.assertEqual(x[10], 30) + @pytest.mark.group_one def test_pointer_to_has_no_len_and_is_not_iterable(self): x = ListOf(int)([1, 2]) @@ -1892,6 +1993,7 @@ def test_pointer_to_has_no_len_and_is_not_iterable(self): for i in x.pointerUnsafe(0): break + @pytest.mark.group_one def test_unsafe_pointers_to_uninitialized_list_items(self): # because this is testing unsafe operations, the test is # really just that we don't segfault! @@ -1913,6 +2015,7 @@ def test_unsafe_pointers_to_uninitialized_list_items(self): self.assertEqual(_types.refcount(aLeakedTuple), 2) + @pytest.mark.group_one def test_list_extend(self): LI = ListOf(int) LF = ListOf(float) @@ -1934,6 +2037,7 @@ def test_list_extend(self): self.assertEqual(li, list(range(10))) + @pytest.mark.group_one def test_list_copy_operation_duplicates_list(self): T = ListOf(int) @@ -1944,6 +2048,7 @@ def test_list_copy_operation_duplicates_list(self): self.assertNotEqual(y[0], 100) + @pytest.mark.group_one def test_list_and_tuple_conversion_to_numpy(self): for T in [ListOf(bool), TupleOf(bool)]: for arr in [ @@ -1988,6 +2093,7 @@ def test_list_and_tuple_conversion_to_numpy(self): self.assertEqual(str(ListOf(float)([1, 2, 3, 4]).toArray().dtype), 'float64') self.assertEqual(str(ListOf(Float32)([1, 2, 3, 4]).toArray().dtype), 'float32') + @pytest.mark.group_one def test_list_of_equality(self): x = ListOf(int)([1, 2, 3, 4]) y = ListOf(int)([1, 2, 3, 5]) @@ -1995,6 +2101,7 @@ def test_list_of_equality(self): self.assertEqual(x, x) self.assertNotEqual(x, y) + @pytest.mark.group_one def test_tuple_r_add(self): self.assertEqual( (1, 2, 4, 5, 6) + TupleOf(int)([1, 2]), @@ -2009,15 +2116,18 @@ def test_tuple_r_add(self): with self.assertRaises(TypeError): [1, 2, "hi", 5, 6] + TupleOf(int)([1, 2]) + @pytest.mark.group_one def test_tuple_r_cmp(self): self.assertEqual( (1, 2, 3), TupleOf(int)([1, 2, 3]) ) + @pytest.mark.group_one def test_can_convert_numpy_scalars(self): self.assertEqual(OneOf(int, float)(numpy.int64(10)), 10) self.assertEqual(OneOf(int, float)(numpy.float64(10.5)), 10.5) + @pytest.mark.group_one def test_other_bitness_types(self): # verify we can cast around non-64-bit values in a way that matches numpy typeAndNumpyType = [ @@ -2061,6 +2171,7 @@ def test_other_bitness_types(self): # numpy.int16(numpy.float64(10000000000)) pass + @pytest.mark.group_one def test_other_bitness_types_operators(self): def add(x, y): return x + y @@ -2178,6 +2289,7 @@ def promotedType(i: int): if bitness(T1) > 1 and bitness(T2) > 1: self.assertEqual(res, op(10, 10)) + @pytest.mark.group_one def test_comparing_arbitrary_objects(self): x = TupleOf(object)(["a"]) y = TupleOf(object)([1]) @@ -2189,10 +2301,12 @@ def test_comparing_arbitrary_objects(self): self.assertEqual(y, y) self.assertNotEqual(x, y) + @pytest.mark.group_one def test_list_of_indexing_with_numpy_ints(self): x = ListOf(ListOf(int))([[1, 2, 3], [4, 5, 6]]) self.assertEqual(x[numpy.int64(0)][numpy.int64(0)], 1) + @pytest.mark.group_one def test_error_message_on_bad_dispatch(self): @Function def f(x: int): @@ -2204,6 +2318,7 @@ def f(x: int): with self.assertRaisesRegex(TypeError, "argname="): f(argname=1) + @pytest.mark.group_one def test_const_dict_comparison_more(self): N = NamedTuple(x=OneOf(None, int), y=OneOf(None, int)) D = ConstDict(str, N) @@ -2214,6 +2329,7 @@ def test_const_dict_comparison_more(self): self.assertEqual(D({'a': n1}), D({'a': n1})) self.assertNotEqual(D({'a': n1}), D({'a': n2})) + @pytest.mark.group_one def test_mutable_dict(self): T = Dict(int, int) @@ -2258,6 +2374,7 @@ def test_mutable_dict(self): del d[0] self.assertLess(currentMemUsageMb(), usage+1) + @pytest.mark.group_one def test_mutable_dict_fuzz(self): native_d = Dict(int, int)() py_d = {} @@ -2279,6 +2396,7 @@ def test_mutable_dict_fuzz(self): for i in range(dictSize): self.assertEqual(z in py_d, z in native_d) + @pytest.mark.group_one def test_mutable_dict_refcounts(self): native_d = Dict(str, ListOf(int))() i = ListOf(int)() @@ -2307,12 +2425,14 @@ def test_mutable_dict_refcounts(self): self.assertEqual(_types.refcount(i), 1) + @pytest.mark.group_one def test_mutable_dict_create_many(self): for ct in range(100): d = Dict(int, int)() for i in range(ct): d[i] = i + 1 + @pytest.mark.group_one def test_mutable_dict_methods(self): d = Dict(int, int)({i: i+1 for i in range(10)}) @@ -2330,12 +2450,14 @@ def test_mutable_dict_methods(self): with self.assertRaises(TypeError): self.assertEqual(d.get("1000"), None) + @pytest.mark.group_one def test_mutable_dict_setdefault_bad_arguments(self): d = Dict(int, str)() with self.assertRaises(TypeError): d.setdefault(1, 2, 3) + @pytest.mark.group_one def test_mutable_dict_setdefault(self): d = Dict(int, str)() d[1] = "a" @@ -2360,6 +2482,7 @@ def test_mutable_dict_setdefault(self): self.assertEqual(d.setdefault(3), "") + @pytest.mark.group_one def test_mutable_dict_pop(self): d = Dict(int, str)() d[1] = 'a' @@ -2376,6 +2499,7 @@ def test_mutable_dict_pop(self): ): d.pop("hihi") + @pytest.mark.group_one def test_mutable_dict_pop_with_conversion(self): d = Dict(Tuple(int, str), Tuple(int, str))() d[(1, "hi")] = (1, "bye") @@ -2385,6 +2509,7 @@ def test_mutable_dict_pop_with_conversion(self): self.assertEqual(d.pop(d.KeyType((2, "hi"))), (2, "bye")) self.assertTrue(len(d) == 0) + @pytest.mark.group_one def test_mutable_dict_setdefault_refcount(self): d = Dict(int, ListOf(int))() aList = ListOf(int)([1, 2, 3]) @@ -2404,6 +2529,7 @@ def test_mutable_dict_setdefault_refcount(self): d.setdefault(3, aList) self.assertEqual(_types.refcount(aList), 3) + @pytest.mark.group_one def test_mutable_dict_iteration_order(self): d = Dict(int, int)() @@ -2415,6 +2541,7 @@ def test_mutable_dict_iteration_order(self): del d[1] self.assertEqual(list(d), [10, 2]) + @pytest.mark.group_one def test_simplicity(self): isSimple = _types.isSimple @@ -2466,6 +2593,7 @@ class C(Class): self.assertFalse(isSimple(OneOf(int, X))) self.assertTrue(isSimple(OneOf(int, float))) + @pytest.mark.group_one def test_oneof_picks_best_choice(self): T = OneOf(float, int, bool) @@ -2473,6 +2601,7 @@ def test_oneof_picks_best_choice(self): self.assertIsInstance(T(1), int) self.assertIsInstance(T(True), bool) + @pytest.mark.group_one def test_dict_equality(self): for d in [{1: 2}, {1: 2, 3: 4}]: self.assertEqual(Dict(int, int)(d), d) @@ -2486,11 +2615,13 @@ def test_dict_equality(self): T = Dict(OneOf(int, float), OneOf(int, float)) self.assertEqual(T({1: 2.5}), {1: 2.5}) + @pytest.mark.group_one def test_dict_equality_with_python_and_object(self): self.assertTrue(Dict(int, object)({1: 2}) == {1: 2}) self.assertTrue(Dict(int, object)({1: (7, 8, 9)}) == {1: (7, 8, 9)}) self.assertTrue(Dict(int, object)({1: 'two'}) == {1: 'two'}) + @pytest.mark.group_one def test_const_dict_with_noncomparable_things(self): DictType = ConstDict(OneOf(int, str), int) @@ -2499,6 +2630,7 @@ def test_const_dict_with_noncomparable_things(self): self.assertEqual(aDict[1], 100) self.assertEqual(aDict['hi'], 200) + @pytest.mark.group_one def test_const_dict_with_noncomparable_things_as_object(self): DictType = ConstDict(object, int) @@ -2507,6 +2639,7 @@ def test_const_dict_with_noncomparable_things_as_object(self): self.assertEqual(aDict[1], 100) self.assertEqual(aDict['hi'], 200) + @pytest.mark.group_one def test_oneof_conversion(self): BrokenOutBool = OneOf(False, True, int) @@ -2518,6 +2651,7 @@ def test_oneof_conversion(self): self.assertIs(type(BrokenOutBoolReordered(0)), int) self.assertIs(type(BrokenOutBoolReordered(False)), bool) + @pytest.mark.group_one def test_set_constructor_identity(self): s = Set(int) self.assertEqual(s.__qualname__, "Set(int)") @@ -2530,6 +2664,7 @@ def test_set_constructor_identity(self): s2 = Set(int)([1]) self.assertNotEqual(id(s2), id(s1)) + @pytest.mark.group_one def test_set_update(self): s1 = Set(int)([1, 2, 3]) @@ -2541,11 +2676,13 @@ def test_set_update(self): self.assertEqual(s1, Set(int)(range(1, 10))) + @pytest.mark.group_one def test_set_len(self): s1 = Set(int)([1, 2, 3]) s2 = Set(int)([1, 2, 3]) self.assertEqual(len(s1), len(s2)) + @pytest.mark.group_one def test_set_discard(self): s = Set(int)([1, 2, 3]) s.discard(2) @@ -2561,12 +2698,14 @@ def test_set_discard(self): s = Set(int)() s.discard(1) + @pytest.mark.group_one def test_set_clear(self): s = Set(int)([1, 2, 3]) s.clear() self.assertEqual(set(s), set()) self.assertEqual(len(s), 0) + @pytest.mark.group_one def test_set_contains(self): letters = ['a', 'b', 'c'] s1 = Set(str)() @@ -2578,6 +2717,7 @@ def test_set_contains(self): self.assertEqual(c in s1, c in s2) self.assertRaises(TypeError, s1.__contains__, [[]]) + @pytest.mark.group_one def test_set_remove(self): s = Set(str)() s.add("a") @@ -2587,6 +2727,7 @@ def test_set_remove(self): self.assertRaises(KeyError, s.remove, "Q") self.assertRaises(TypeError, s.remove, []) + @pytest.mark.group_one def test_set_add(self): s = Set(int)() self.assertEqual(len(s), 0) @@ -2605,6 +2746,7 @@ def test_set_add(self): s = Set(int)(i) self.assertEqual(len(s), 3) + @pytest.mark.group_one def test_set_pop(self): s = Set(int)([1, 2, 3]) @@ -2613,6 +2755,7 @@ def test_set_pop(self): with self.assertRaises(KeyError): s.pop() + @pytest.mark.group_one def test_set_refcounts(self): native_d = Dict(str, Set(int))() i = Set(int)() @@ -2691,6 +2834,7 @@ def test_set_refcounts(self): self.assertEqual(_types.refcount(i2), 1) self.assertEqual(_types.refcount(i3), 1) + @pytest.mark.group_one def test_set_equality(self): s = Set(str)() s.add('hello') @@ -2706,15 +2850,18 @@ def test_set_equality(self): self.assertEqual(s != other_s, True) self.assertEqual(s == another_s, True) + @pytest.mark.group_one def test_set_self_equality(self): s = Set(int)() self.assertEqual(s, s) + @pytest.mark.group_one def test_set_repr(self): repr_s = '{1, 2, 3}' s = Set(int)([1, 2, 3]) self.assertEqual(repr(s), repr_s) + @pytest.mark.group_one def test_set_literal(self): s = Set(int)([1, 2, 3]) t = {1, 2, 3} @@ -2724,6 +2871,7 @@ def test_set_literal(self): t = {"a", "b", "c"} self.assertEqual(t, set(s)) + @pytest.mark.group_one def test_set_iterating(self): s = Set(int)() it = iter(s) @@ -2740,6 +2888,7 @@ def test_set_iterating(self): break self.assertEqual(count, len(s)) + @pytest.mark.group_one def test_set_assign_from_existing_dict_key_nothrow(self): d = Dict(str, Set(int))() i = Set(int)() @@ -2747,6 +2896,7 @@ def test_set_assign_from_existing_dict_key_nothrow(self): d['a'] = i d['a'] = Set(int)() + @pytest.mark.group_one def test_set_uniquification(self): word = 'simsalabim' s = Set(str)() @@ -2756,6 +2906,7 @@ def test_set_uniquification(self): ds = sorted(dict.fromkeys(word)) self.assertEqual(ss, ds) + @pytest.mark.group_one def test_set_copy(self): s = Set(int)([1]) dup = s.copy() @@ -2774,6 +2925,7 @@ def test_set_copy(self): self.assertRaises(TypeError, s.copy, s) self.assertRaises(TypeError, s.copy, []) + @pytest.mark.group_one def test_set_construct_from_str(self): word = 'symbolic' s = Set(str)(word) @@ -2785,6 +2937,7 @@ def test_set_construct_from_str(self): for c in word: self.assertIn(c, s) + @pytest.mark.group_one def test_set_ops_throws_diff_type(self): s = Set(int)([1]) self.assertRaises(TypeError, s.union, 1.0) @@ -2798,6 +2951,7 @@ def test_set_ops_throws_diff_type(self): self.assertRaises(TypeError, s.difference, [[]]) + @pytest.mark.group_one def test_set_union_deleted(self): x = Set(int)() y = Set(int)() @@ -2814,6 +2968,7 @@ def test_set_union_deleted(self): assert len(x | y) == 10 + @pytest.mark.group_one def test_set_union_refcounts(self): s = Set(int)([1]) s2 = Set(int)([2]) @@ -2826,6 +2981,7 @@ def test_set_union_refcounts(self): self.assertIn(2, k) self.assertNotEqual(id(s), id(s2), id(k)) + @pytest.mark.group_one def test_set_union(self): word = 'symbolic' word2 = 'word' @@ -2865,6 +3021,7 @@ def _check(u, s, chars): s = Set(int)() self.assertEqual(s.union(Set(int)([1]), s, Set(int)([2])), Set(int)([1, 2])) + @pytest.mark.group_one def test_set_ops_with_other_containers(self): S = Set(str) # operators require type matching; but methods accept iterables @@ -2973,6 +3130,7 @@ def test_set_ops_with_other_containers(self): self.assertFalse(S('abcba').isdisjoint(C('abcdecad')), C) self.assertFalse(S('abcba').isdisjoint(C('ccb')), C) + @pytest.mark.group_one def test_set_intersection(self): word1 = 'symbolic' word2 = 'words' @@ -2994,6 +3152,7 @@ def test_set_intersection(self): self.assertEqual(z, s1) self.assertEqual(_types.refcount(s1), 1) + @pytest.mark.group_one def test_set_difference(self): word1 = 'symbolic' word2 = 'symbolism' @@ -3009,6 +3168,7 @@ def test_set_difference(self): self.assertEqual(s1, Set(str)(word1)) self.assertEqual(type(i), Set(str)) + @pytest.mark.group_one def test_set_symmetric_difference(self): word1 = 'symbolic' word2 = 'symbolism' @@ -3024,6 +3184,7 @@ def test_set_symmetric_difference(self): self.assertEqual(s1, Set(str)(word1)) self.assertEqual(type(i), Set(str)) + @pytest.mark.group_one def test_set_listof_tupleof_constructors(self): s1 = Set(int)(ListOf(int)([1, 1])) self.assertEqual(len(s1), 1) @@ -3031,6 +3192,7 @@ def test_set_listof_tupleof_constructors(self): s2 = Set(int)(TupleOf(int)((1, 1))) self.assertEqual(len(s2), 1) + @pytest.mark.group_one def test_list_of_tuples_transpose(self): listOfTuples = ListOf(NamedTuple(x=int, y=str, z=bool))() listOfTuples.append(dict(x=1, y="hi", z=False)) @@ -3042,6 +3204,7 @@ def test_list_of_tuples_transpose(self): self.assertEqual(tupleOfLists.y, ['hi', 'hihi']) self.assertEqual(tupleOfLists.z, [False, True]) + @pytest.mark.group_one def test_const_dict_equality_with_python(self): CD = ConstDict(OneOf(int, str), OneOf(int, str)) @@ -3053,6 +3216,7 @@ def test_const_dict_equality_with_python(self): self.assertEqual(CD(d1) == d2, d1 == d2) self.assertEqual(d1 == CD(d2), d1 == d2) + @pytest.mark.group_one def test_alternative_reverse_operators(self): A = Alternative("A", a={'a': int}, b={'b': str}, __radd__=lambda lhs, rhs: "radd", @@ -3114,6 +3278,7 @@ def test_alternative_reverse_operators(self): with self.assertRaises(Exception): A.a() | v + @pytest.mark.group_one def test_alternative_missing_inplace_operators_fallback(self): A = Alternative("A", a={'a': int}, b={'b': str}, __add__=lambda self, other: "worked", @@ -3171,6 +3336,7 @@ def test_alternative_missing_inplace_operators_fallback(self): v ^= 10 self.assertEqual(v, "worked") + @pytest.mark.group_one def test_list_and_tuple_of_compare(self): things = [ ListOf(int)([1, 2]), @@ -3240,6 +3406,7 @@ def test_list_and_tuple_of_compare(self): self.assertEqual(t1 != t2, t1Untyped != t2Untyped) self.assertEqual(t1 == t2, t1Untyped == t2Untyped) + @pytest.mark.group_one def test_docstrings_all_types(self): # TODO: actually test all types types = [ @@ -3300,6 +3467,7 @@ def test_docstrings_all_types(self): self.assertTrue(good) # see output for specific problems @flaky(max_runs=3, min_passes=1) + @pytest.mark.group_one def test_list_of_uint8_from_bytes_perf(self): someBytes = b"asdf" * 1024 * 1024 @@ -3312,6 +3480,7 @@ def test_list_of_uint8_from_bytes_perf(self): # I get .001, but if we use the normal interpreter loop, .2 assert elapsed < .02 + @pytest.mark.group_one def test_iterate_dict_and_change_size_throws(self): x = Dict(int, int)({1: 2}) @@ -3319,6 +3488,7 @@ def test_iterate_dict_and_change_size_throws(self): for k in x: x[k + 1] = 2 + @pytest.mark.group_one def test_iterate_set_and_change_size_throws(self): x = Set(int)([1]) @@ -3326,6 +3496,7 @@ def test_iterate_set_and_change_size_throws(self): for k in x: x.add(k + 1) + @pytest.mark.group_one def test_construct_named_tuple_with_other_named_tuple(self): # we should be matching the names up correctly T1 = NamedTuple(x=int, y=str) @@ -3341,6 +3512,7 @@ def test_construct_named_tuple_with_other_named_tuple(self): with self.assertRaises(TypeError): T2(T3(x=10, y='hello')) + @pytest.mark.group_one def test_dict_update_refcounts(self): d = Dict(TupleOf(int), TupleOf(int))() k = TupleOf(int)([1]) @@ -3389,6 +3561,7 @@ def test_dict_update_refcounts(self): assert _types.refcount(k) == 1 assert _types.refcount(v) == 1 + @pytest.mark.group_one def test_dict_from_const_dict_refcounts(self): D = Dict(TupleOf(int), TupleOf(int)) CD = ConstDict(TupleOf(int), TupleOf(int)) @@ -3415,6 +3588,7 @@ def test_dict_from_const_dict_refcounts(self): assert _types.refcount(k1) == 1 assert _types.refcount(k2) == 1 + @pytest.mark.group_one def test_set_refcounts_tupleof_int(self): s = Set(TupleOf(int))() @@ -3432,6 +3606,7 @@ def test_set_refcounts_tupleof_int(self): assert _types.refcount(k1) == 1 + @pytest.mark.group_one def test_const_dict_from_dict_refcounts(self): CD = ConstDict(TupleOf(int), TupleOf(int)) @@ -3460,6 +3635,7 @@ def test_const_dict_from_dict_refcounts(self): assert _types.refcount(k1) == 1 assert _types.refcount(k2) == 1 + @pytest.mark.group_one def test_list_of_constructor_from_numpy(self): array = numpy.array([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0]]) @@ -3469,6 +3645,7 @@ def test_list_of_constructor_from_numpy(self): assert ListOf(float)(array.transpose()[2]) == ListOf(float)([2.0, 5.0]) + @pytest.mark.group_one def test_subclass_of(self): class C(Class): pass @@ -3514,6 +3691,7 @@ class F(D, Final): lst.append(F) assert lst[0] == F + @pytest.mark.group_one def test_call_iter(self): def manualIter(x): iterator = x.__iter__()