Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mypy_test.py: Allow non-types dependencies #9408

Merged
merged 19 commits into from
Jan 7, 2023

Conversation

AlexWaygood
Copy link
Member

Work towards #5768 (cc. @Avasam)

@github-actions

This comment was marked as off-topic.

@AlexWaygood AlexWaygood marked this pull request as ready for review December 26, 2022 17:00
@AlexWaygood
Copy link
Member Author

AlexWaygood commented Dec 26, 2022

Okay, I think this is ready for review.

The approach is pretty similar to the approach I took in #9382 for regr_test.py: dynamically create virtual environments for testing stubs packages in isolation. However, since mypy_test.py tests all of typeshed's stubs in succession (and since lots of typeshed's stubs packages depend on other typeshed stubs packages), the performance issues with creating a virtual environment for testing each stubs package are even more severe than with regr_test.py.

I mitigate the performance issues associated with dynamically creating virtual environments in two ways:

  • Dynamically creating venvs is mostly slow due to I/O bottlenecks. Creating the virtual environments can be sped up dramatically by creating them concurrently in a threadpool. The same goes for pip installing the requirements into the venvs -- though unfortunately, we have to use pip with --no-cache-dir, as the pip cache gets easily corrupted if you try to do concurrent reads and writes to the pip cache.
  • If types-pycocotools requires numpy>=1 and types-D3DShot also requires numpy>=1 (for example), there's no need to create 2 virtual environments. The same requirements have been specified, so they can share a virtual environment between them. This means we don't have to create nearly so many virtual environments.

The CI run on db260f2 shows what happens if we add non-types requirements to several packages in typeshed. I added --verbose to the invocation of mypy_test.py in the same commit, so that you can see exactly when venvs are being created, and exactly what packages are being pip installed into those venvs.

I've also confirmed that the mypy tests all pass on #9459 locally if this PR is applied.

requirements-tests.txt Outdated Show resolved Hide resolved
Comment on lines -241 to -266
def get_mypy_flags(args: TestConfig, temp_name: str, *, testing_stdlib: bool) -> list[str]:
flags = [
"--python-version",
args.version,
"--show-traceback",
"--warn-incomplete-stub",
"--show-error-codes",
"--no-error-summary",
"--platform",
args.platform,
"--no-site-packages",
"--custom-typeshed-dir",
str(Path(__file__).parent.parent),
"--strict",
# Stub completion is checked by pyright (--allow-*-defs)
"--allow-untyped-defs",
"--allow-incomplete-defs",
"--allow-subclassing-any", # Needed until we can use non-types dependencies #5768
"--enable-error-code",
"ignore-without-code",
"--config-file",
temp_name,
]
if not testing_stdlib:
flags.append("--explicit-package-bases")
return flags
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved these inline as it honestly didn't make much sense for this to be a separate function any more. The precise set of flags that's being passed now depends on whether it's the stdlib being tested, and (if it's a third-party package) whether the stubs package depends (either directly or indirectly) on a non-types package.

tests/utils.py Outdated Show resolved Hide resolved
@@ -142,7 +145,7 @@ def make_venv(venv_dir: Path) -> VenvInfo:
try:
venv.create(venv_dir, with_pip=True, clear=True)
except subprocess.CalledProcessError as e:
if "ensurepip" in e.cmd:
if "ensurepip" in e.cmd and b"KeyboardInterrupt" not in e.stdout.splitlines():
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "if you're on Linux, you might need to install the python3-venv package" message was showing up every time I interrupted the script with a KeyboardInterrupt during the "concurrently create many venvs" step, and it was kinda annoying.

tests/mypy_test.py Outdated Show resolved Hide resolved
tests/mypy_test.py Outdated Show resolved Hide resolved


def install_requirements_for_venv(venv_info: VenvInfo, args: TestConfig, external_requirements: frozenset[str]) -> None:
# Use --no-cache-dir to avoid issues with concurrent read/writes to the cache
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't GitHub Actions provide a way to cache pip installs across runs? If that's available, it would be a pretty promising way to optimize this check.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does, yeah. But it's nice to be able to run this script locally as well, and for that we need a solution that's performant even if it doesn't have access to the GitHub Actions cache. I'm also not entirely sure if the GitHub Actions cache is accessible from within Python scripts or not. (I have no idea how it works tbh.)

Anyway, I'll merge this for now, and if anybody can think of further optimisations, they can be applied in future PRs :)

Thanks for the review!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JelleZijlstra If you mean the setup-python action. It only caches the download, not the install. See actions/setup-python#330

It's still possible to do it manually using actions/cache .

@AlexWaygood AlexWaygood merged commit 4d6fda9 into python:main Jan 7, 2023
@AlexWaygood AlexWaygood deleted the mypy-test-non-types branch January 7, 2023 23:57
AlexWaygood added a commit that referenced this pull request Jan 8, 2023
Some fairly subtle logic was added in #9408, and I'm immediately regretting not having documented it slightly better. This PR adds some more comments to make maintaining this code easier in the future.
JelleZijlstra pushed a commit that referenced this pull request Jan 8, 2023
Some fairly subtle logic was added in #9408, and I'm immediately regretting not having documented it slightly better. This PR adds some more comments to make maintaining this code easier in the future.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants