diff --git a/pyrightconfig.json b/pyrightconfig.json index 54d18ad0de17..d4fd646c7920 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -7,7 +7,7 @@ ], "exclude": [ // test cases use a custom config file - "stubs/**/@tests/test_cases" + "**/@tests/test_cases", ], "typeCheckingMode": "strict", // Allowed in base settings for incomplete stubs, checked in stricter settings diff --git a/pyrightconfig.stricter.json b/pyrightconfig.stricter.json index 23e57a5218a1..cac67e2349d2 100644 --- a/pyrightconfig.stricter.json +++ b/pyrightconfig.stricter.json @@ -7,7 +7,7 @@ ], "exclude": [ // test cases use a custom pyrightconfig file - "stubs/**/@tests/test_cases", + "**/@tests/test_cases", "stdlib/distutils/command", "stdlib/distutils/dist.pyi", "stdlib/importlib/readers.pyi", diff --git a/pyrightconfig.testcases.json b/pyrightconfig.testcases.json index e2898dd56268..a957cc694f18 100644 --- a/pyrightconfig.testcases.json +++ b/pyrightconfig.testcases.json @@ -2,8 +2,7 @@ "$schema": "https://raw.githubusercontent.com/microsoft/pyright/main/packages/vscode-pyright/schemas/pyrightconfig.schema.json", "typeshedPath": ".", "include": [ - "test_cases", - "stubs/**/@tests/test_cases" + "**/@tests/test_cases", ], "typeCheckingMode": "strict", // Extra strict settings diff --git a/test_cases/stdlib/asyncio/check_coroutines.py b/stdlib/@tests/test_cases/asyncio/check_coroutines.py similarity index 100% rename from test_cases/stdlib/asyncio/check_coroutines.py rename to stdlib/@tests/test_cases/asyncio/check_coroutines.py diff --git a/test_cases/stdlib/asyncio/check_gather.py b/stdlib/@tests/test_cases/asyncio/check_gather.py similarity index 100% rename from test_cases/stdlib/asyncio/check_gather.py rename to stdlib/@tests/test_cases/asyncio/check_gather.py diff --git a/test_cases/stdlib/asyncio/check_task.py b/stdlib/@tests/test_cases/asyncio/check_task.py similarity index 100% rename from test_cases/stdlib/asyncio/check_task.py rename to stdlib/@tests/test_cases/asyncio/check_task.py diff --git a/test_cases/stdlib/builtins/check_dict-py39.py b/stdlib/@tests/test_cases/builtins/check_dict-py39.py similarity index 100% rename from test_cases/stdlib/builtins/check_dict-py39.py rename to stdlib/@tests/test_cases/builtins/check_dict-py39.py diff --git a/test_cases/stdlib/builtins/check_dict.py b/stdlib/@tests/test_cases/builtins/check_dict.py similarity index 100% rename from test_cases/stdlib/builtins/check_dict.py rename to stdlib/@tests/test_cases/builtins/check_dict.py diff --git a/test_cases/stdlib/builtins/check_exception_group-py311.py b/stdlib/@tests/test_cases/builtins/check_exception_group-py311.py similarity index 100% rename from test_cases/stdlib/builtins/check_exception_group-py311.py rename to stdlib/@tests/test_cases/builtins/check_exception_group-py311.py diff --git a/test_cases/stdlib/builtins/check_iteration.py b/stdlib/@tests/test_cases/builtins/check_iteration.py similarity index 100% rename from test_cases/stdlib/builtins/check_iteration.py rename to stdlib/@tests/test_cases/builtins/check_iteration.py diff --git a/test_cases/stdlib/builtins/check_list.py b/stdlib/@tests/test_cases/builtins/check_list.py similarity index 100% rename from test_cases/stdlib/builtins/check_list.py rename to stdlib/@tests/test_cases/builtins/check_list.py diff --git a/test_cases/stdlib/builtins/check_object.py b/stdlib/@tests/test_cases/builtins/check_object.py similarity index 100% rename from test_cases/stdlib/builtins/check_object.py rename to stdlib/@tests/test_cases/builtins/check_object.py diff --git a/test_cases/stdlib/builtins/check_pow.py b/stdlib/@tests/test_cases/builtins/check_pow.py similarity index 100% rename from test_cases/stdlib/builtins/check_pow.py rename to stdlib/@tests/test_cases/builtins/check_pow.py diff --git a/test_cases/stdlib/builtins/check_reversed.py b/stdlib/@tests/test_cases/builtins/check_reversed.py similarity index 100% rename from test_cases/stdlib/builtins/check_reversed.py rename to stdlib/@tests/test_cases/builtins/check_reversed.py diff --git a/test_cases/stdlib/builtins/check_round.py b/stdlib/@tests/test_cases/builtins/check_round.py similarity index 100% rename from test_cases/stdlib/builtins/check_round.py rename to stdlib/@tests/test_cases/builtins/check_round.py diff --git a/test_cases/stdlib/builtins/check_sum.py b/stdlib/@tests/test_cases/builtins/check_sum.py similarity index 100% rename from test_cases/stdlib/builtins/check_sum.py rename to stdlib/@tests/test_cases/builtins/check_sum.py diff --git a/test_cases/stdlib/builtins/check_tuple.py b/stdlib/@tests/test_cases/builtins/check_tuple.py similarity index 100% rename from test_cases/stdlib/builtins/check_tuple.py rename to stdlib/@tests/test_cases/builtins/check_tuple.py diff --git a/test_cases/stdlib/check_codecs.py b/stdlib/@tests/test_cases/check_codecs.py similarity index 100% rename from test_cases/stdlib/check_codecs.py rename to stdlib/@tests/test_cases/check_codecs.py diff --git a/test_cases/stdlib/check_concurrent_futures.py b/stdlib/@tests/test_cases/check_concurrent_futures.py similarity index 100% rename from test_cases/stdlib/check_concurrent_futures.py rename to stdlib/@tests/test_cases/check_concurrent_futures.py diff --git a/test_cases/stdlib/check_contextlib.py b/stdlib/@tests/test_cases/check_contextlib.py similarity index 100% rename from test_cases/stdlib/check_contextlib.py rename to stdlib/@tests/test_cases/check_contextlib.py diff --git a/test_cases/stdlib/check_dataclasses.py b/stdlib/@tests/test_cases/check_dataclasses.py similarity index 100% rename from test_cases/stdlib/check_dataclasses.py rename to stdlib/@tests/test_cases/check_dataclasses.py diff --git a/test_cases/stdlib/check_enum.py b/stdlib/@tests/test_cases/check_enum.py similarity index 100% rename from test_cases/stdlib/check_enum.py rename to stdlib/@tests/test_cases/check_enum.py diff --git a/test_cases/stdlib/check_functools.py b/stdlib/@tests/test_cases/check_functools.py similarity index 100% rename from test_cases/stdlib/check_functools.py rename to stdlib/@tests/test_cases/check_functools.py diff --git a/test_cases/stdlib/check_importlib.py b/stdlib/@tests/test_cases/check_importlib.py similarity index 100% rename from test_cases/stdlib/check_importlib.py rename to stdlib/@tests/test_cases/check_importlib.py diff --git a/test_cases/stdlib/check_importlib_metadata.py b/stdlib/@tests/test_cases/check_importlib_metadata.py similarity index 100% rename from test_cases/stdlib/check_importlib_metadata.py rename to stdlib/@tests/test_cases/check_importlib_metadata.py diff --git a/test_cases/stdlib/check_io.py b/stdlib/@tests/test_cases/check_io.py similarity index 100% rename from test_cases/stdlib/check_io.py rename to stdlib/@tests/test_cases/check_io.py diff --git a/test_cases/stdlib/check_logging.py b/stdlib/@tests/test_cases/check_logging.py similarity index 100% rename from test_cases/stdlib/check_logging.py rename to stdlib/@tests/test_cases/check_logging.py diff --git a/test_cases/stdlib/check_multiprocessing.py b/stdlib/@tests/test_cases/check_multiprocessing.py similarity index 100% rename from test_cases/stdlib/check_multiprocessing.py rename to stdlib/@tests/test_cases/check_multiprocessing.py diff --git a/test_cases/stdlib/check_pathlib.py b/stdlib/@tests/test_cases/check_pathlib.py similarity index 100% rename from test_cases/stdlib/check_pathlib.py rename to stdlib/@tests/test_cases/check_pathlib.py diff --git a/test_cases/stdlib/check_re.py b/stdlib/@tests/test_cases/check_re.py similarity index 100% rename from test_cases/stdlib/check_re.py rename to stdlib/@tests/test_cases/check_re.py diff --git a/test_cases/stdlib/check_sqlite3.py b/stdlib/@tests/test_cases/check_sqlite3.py similarity index 100% rename from test_cases/stdlib/check_sqlite3.py rename to stdlib/@tests/test_cases/check_sqlite3.py diff --git a/test_cases/stdlib/check_tarfile.py b/stdlib/@tests/test_cases/check_tarfile.py similarity index 100% rename from test_cases/stdlib/check_tarfile.py rename to stdlib/@tests/test_cases/check_tarfile.py diff --git a/test_cases/stdlib/check_tempfile.py b/stdlib/@tests/test_cases/check_tempfile.py similarity index 100% rename from test_cases/stdlib/check_tempfile.py rename to stdlib/@tests/test_cases/check_tempfile.py diff --git a/test_cases/stdlib/check_threading.py b/stdlib/@tests/test_cases/check_threading.py similarity index 100% rename from test_cases/stdlib/check_threading.py rename to stdlib/@tests/test_cases/check_threading.py diff --git a/test_cases/stdlib/check_tkinter.py b/stdlib/@tests/test_cases/check_tkinter.py similarity index 100% rename from test_cases/stdlib/check_tkinter.py rename to stdlib/@tests/test_cases/check_tkinter.py diff --git a/test_cases/stdlib/check_unittest.py b/stdlib/@tests/test_cases/check_unittest.py similarity index 100% rename from test_cases/stdlib/check_unittest.py rename to stdlib/@tests/test_cases/check_unittest.py diff --git a/test_cases/stdlib/check_xml.py b/stdlib/@tests/test_cases/check_xml.py similarity index 100% rename from test_cases/stdlib/check_xml.py rename to stdlib/@tests/test_cases/check_xml.py diff --git a/test_cases/stdlib/collections/check_defaultdict-py39.py b/stdlib/@tests/test_cases/collections/check_defaultdict-py39.py similarity index 100% rename from test_cases/stdlib/collections/check_defaultdict-py39.py rename to stdlib/@tests/test_cases/collections/check_defaultdict-py39.py diff --git a/test_cases/stdlib/email/check_message.py b/stdlib/@tests/test_cases/email/check_message.py similarity index 100% rename from test_cases/stdlib/email/check_message.py rename to stdlib/@tests/test_cases/email/check_message.py diff --git a/test_cases/stdlib/itertools/check_itertools_recipes.py b/stdlib/@tests/test_cases/itertools/check_itertools_recipes.py similarity index 100% rename from test_cases/stdlib/itertools/check_itertools_recipes.py rename to stdlib/@tests/test_cases/itertools/check_itertools_recipes.py diff --git a/test_cases/stdlib/typing/check_MutableMapping.py b/stdlib/@tests/test_cases/typing/check_MutableMapping.py similarity index 100% rename from test_cases/stdlib/typing/check_MutableMapping.py rename to stdlib/@tests/test_cases/typing/check_MutableMapping.py diff --git a/test_cases/stdlib/typing/check_all.py b/stdlib/@tests/test_cases/typing/check_all.py similarity index 100% rename from test_cases/stdlib/typing/check_all.py rename to stdlib/@tests/test_cases/typing/check_all.py diff --git a/test_cases/stdlib/typing/check_regression_issue_9296.py b/stdlib/@tests/test_cases/typing/check_regression_issue_9296.py similarity index 100% rename from test_cases/stdlib/typing/check_regression_issue_9296.py rename to stdlib/@tests/test_cases/typing/check_regression_issue_9296.py diff --git a/test_cases/stdlib/typing/check_typing_io.py b/stdlib/@tests/test_cases/typing/check_typing_io.py similarity index 100% rename from test_cases/stdlib/typing/check_typing_io.py rename to stdlib/@tests/test_cases/typing/check_typing_io.py diff --git a/tests/README.md b/tests/README.md index 2e4e261d9aba..8a8cf8083bab 100644 --- a/tests/README.md +++ b/tests/README.md @@ -102,7 +102,8 @@ the stubs in typeshed (including the standard library). ## regr\_test.py This test runs mypy against the test cases for typeshed's stdlib and third-party -stubs. See [the README in the `test_cases` directory](../test_cases/README.md) +stubs. See [the REGRESSION.md document](./REGRESSION.md) +in this directory for more information about what these test cases are for and how they work. Run `python tests/regr_test.py --help` for information on the various configuration options. diff --git a/test_cases/README.md b/tests/REGRESSION.md similarity index 82% rename from test_cases/README.md rename to tests/REGRESSION.md index 437ae4552bcb..d0694f8e2762 100644 --- a/test_cases/README.md +++ b/tests/REGRESSION.md @@ -1,32 +1,27 @@ ## Regression tests for typeshed -This directory contains code samples that act as a regression test for -typeshed's stdlib stubs. +Regression tests for the standard library stubs can be found in the +`stdlib/@tests/test_cases` directory. Stubs for third-party libraries that do +have test cases can be found in `@tests/test_cases` subdirectories for each +stubs package. For example, the test cases for `requests` can be found in the +`stubs/requests/@tests/test_cases` directory. -**This directory should *only* contain test cases for functions and classes which +**Regression test cases should only be written for functions and classes which are known to have caused problems in the past, where the stubs are difficult to get right.** 100% test coverage for typeshed is neither necessary nor desirable, as it would lead to code duplication. Moreover, typeshed has multiple other mechanisms for spotting errors in the stubs. -### Where are the third-party test cases? - -Not all third-party stubs packages in typeshed have test cases, and not all of -them need test cases. For those that do have test cases, however, the samples -can be found in `@tests/test_cases` subdirectories for each stubs package. For -example, the test cases for `requests` can be found in the -`stubs/requests/@tests/test_cases` directory. - ### The purpose of these tests Different test cases in this directory serve different purposes. For some stubs in typeshed, the type annotations are complex enough that it's useful to have sanity checks that test whether a type checker understands the intent of the annotations correctly. Examples of tests like these are -`stdlib/builtins/check_pow.py` and `stdlib/asyncio/check_gather.py`. +`builtins/check_pow.py` and `asyncio/check_gather.py`. -Other test cases, such as the samples for `ExitStack` in `stdlib/check_contextlib.py` -and the samples for `LogRecord` in `stdlib/check_logging.py`, do not relate to +Other test cases, such as the samples for `ExitStack` in `check_contextlib.py` +and the samples for `LogRecord` in `check_logging.py`, do not relate to stubs where the annotations are particularly complex, but they *do* relate to stubs where decisions have been taken that might be slightly unusual. These test cases serve a different purpose: to check that type checkers do not emit @@ -74,10 +69,10 @@ Use the same top-level name for the module / package you would like to test. Use the `check_${thing}.py` naming pattern for individual test files. By default, test cases go into a file with the same name as the stub file, prefixed with `check_`. -For example: `stdlib/check_contextlib.py`. +For example: `check_contextlib.py`. If that file becomes too big, we instead create a directory with files named after individual objects being tested. -For example: `stdlib/builtins/check_dict.py`. +For example: `builtins/check_dict.py`. ### Differences to the rest of typeshed @@ -114,7 +109,7 @@ with a specific Python version passed on the command line to the `tests/regr_tes To mark a test-case file as being skippable on lower versions of Python, append `-py3*` to the filename. For example, if `foo` is a stdlib feature that's new in Python 3.11, -test cases for `foo` should be put in a file named `test_cases/stdlib/check_foo-py311.py`. +test cases for `foo` should be put in a file named `check_foo-py311.py`. This means that mypy will only run the test case if `--python-version 3.11`, `--python-version 3.12`, etc. is passed on the command line to `tests/regr_test.py`, @@ -123,4 +118,4 @@ is passed on the command line. However, `if sys.version_info >= (3, target):` is still required for `pyright` in the test file itself. -Example: [`check_exception_group-py311.py`](https://github.com/python/typeshed/blob/main/test_cases/stdlib/builtins/check_exception_group-py311.py) +Example: [`check_exception_group-py311.py`](../stdlib/@tests/test_cases/builtins/check_exception_group-py311.py) diff --git a/tests/check_typeshed_structure.py b/tests/check_typeshed_structure.py index 20b329878199..3e4d6ed8dc93 100755 --- a/tests/check_typeshed_structure.py +++ b/tests/check_typeshed_structure.py @@ -15,6 +15,7 @@ from parse_metadata import read_metadata from utils import ( REQS_FILE, + STDLIB_PATH, TEST_CASES_DIR, TESTS_DIR, VERSIONS_RE, @@ -59,7 +60,8 @@ def assert_consistent_filetypes( def check_stdlib() -> None: """Check that the stdlib directory contains only the correct files.""" - assert_consistent_filetypes(Path("stdlib"), kind=".pyi", allowed={"_typeshed/README.md", "VERSIONS"}) + assert_consistent_filetypes(STDLIB_PATH, kind=".pyi", allowed={"_typeshed/README.md", "VERSIONS", TESTS_DIR}) + check_tests_dir(tests_path("stdlib")) def check_stubs() -> None: @@ -81,11 +83,13 @@ def check_stubs() -> None: tests_dir = tests_path(dist.name) if tests_dir.exists() and tests_dir.is_dir(): - py_files_present = any(file.suffix == ".py" for file in tests_dir.iterdir()) - error_message = ( - f"Test-case files must be in an `{TESTS_DIR}/{TEST_CASES_DIR}` directory, not in the `{TESTS_DIR}` directory" - ) - assert not py_files_present, error_message + check_tests_dir(tests_dir) + + +def check_tests_dir(tests_dir: Path) -> None: + py_files_present = any(file.suffix == ".py" for file in tests_dir.iterdir()) + error_message = f"Test-case files must be in an `{TESTS_DIR}/{TEST_CASES_DIR}` directory, not in the `{TESTS_DIR}` directory" + assert not py_files_present, error_message def check_distutils() -> None: @@ -146,7 +150,7 @@ def check_versions_file() -> None: def _find_stdlib_modules() -> set[str]: modules = set[str]() - for path, _, files in os.walk("stdlib"): + for path, _, files in os.walk(STDLIB_PATH): for filename in files: base_module = ".".join(os.path.normpath(path).split(os.sep)[1:]) if filename == "__init__.pyi": diff --git a/tests/mypy_test.py b/tests/mypy_test.py index 6b12667df072..a432dd41a3a0 100755 --- a/tests/mypy_test.py +++ b/tests/mypy_test.py @@ -29,6 +29,7 @@ from parse_metadata import PackageDependencies, get_recursive_requirements, read_metadata from utils import ( PYTHON_VERSION, + TESTS_DIR, VERSIONS_RE as VERSION_LINE_RE, colored, get_gitignore_spec, @@ -366,7 +367,7 @@ def test_stdlib(args: TestConfig) -> TestResult: stdlib = Path("stdlib") supported_versions = parse_versions(stdlib / "VERSIONS") for name in os.listdir(stdlib): - if name == "VERSIONS" or name.startswith("."): + if name in ("VERSIONS", TESTS_DIR) or name.startswith("."): continue module = Path(name).stem module_min_version, module_max_version = supported_versions[module] diff --git a/tests/utils.py b/tests/utils.py index 6fd21d34c113..b875d8b01d59 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -22,6 +22,7 @@ def colored(text: str, color: str | None = None, **kwargs: Any) -> str: # type: PYTHON_VERSION: Final = f"{sys.version_info.major}.{sys.version_info.minor}" +STDLIB_PATH = Path("stdlib") STUBS_PATH = Path("stubs") @@ -139,15 +140,14 @@ def distribution_info(distribution_name: str) -> DistributionTests: def tests_path(distribution_name: str) -> Path: - assert distribution_name != "stdlib" - return STUBS_PATH / distribution_name / TESTS_DIR + if distribution_name == "stdlib": + return STDLIB_PATH / TESTS_DIR + else: + return STUBS_PATH / distribution_name / TESTS_DIR def test_cases_path(distribution_name: str) -> Path: - if distribution_name == "stdlib": - return Path(TEST_CASES_DIR) - else: - return tests_path(distribution_name) / TEST_CASES_DIR + return tests_path(distribution_name) / TEST_CASES_DIR def get_all_testcase_directories() -> list[DistributionTests]: