GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Run mypy on `Lib/test/libregrtest` in CI by AlexWaygood · Pull Request #109382 · python/cpython

Conversation

@AlexWaygood

@AlexWaygood AlexWaygood commented Sep 13, 2023

Copy link
Copy Markdown
Member

@vstinner: this is essentially the minimum set of changes that are required to get mypy to pass when run on libregrtest. Let me know what you think!

I think it might be good to post on Discourse and check that everybody's okay with this idea, before we go through with it. This would be the first time we'd be running mypy on a project inside the Lib/ directory; all existing mypy-checked projects live inside Tools/.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@AlexWaygood
Run mypy on Lib/test/libregrtest in CI
24db8b9
@AlexWaygood
AlexWaygood requested a review from vstinner September 13, 2023 16:41
@AlexWaygood AlexWaygood added the skip news label Sep 13, 2023
vstinner
vstinner reviewed Sep 13, 2023
View reviewed changes

@vstinner vstinner left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Most libregrtest/ changes LGTM, but I'm not sure about coding style changes. Can you please create a PR just for this change, and then update this PR to just add the infra to run mypy?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/test_audit.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

AlexWaygood added 4 commits September 13, 2023 17:52
@AlexWaygood
fixes
c217d64
@AlexWaygood
improve workflow file
73ac976
@AlexWaygood
nit
ad42b09
@AlexWaygood
minimize diff
a637bce
@AlexWaygood

AlexWaygood commented Sep 13, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

Most libregrtest/ changes LGTM, but I'm not sure about coding style changes.

Which coding style changes do you dislike? I tried hard not to make any changes in this PR unless they were strictly required to make the mypy check pass (which is why I think it's good to introduce mypy to CI in the same PR: it validates that the changes in this PR are correct, at least from mypy's perspective). If you highlight the changes you're not sure about, hopefully I can explain why they were necessary to make mypy happy ;-)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

AlexWaygood added 2 commits September 13, 2023 18:21
@AlexWaygood
Add instructions to the mypy.ini file on how to run mypy
e1b0e4a
@AlexWaygood
Improve workflow file
267bc83
@vstinner

vstinner commented Sep 13, 2023

Copy link
Copy Markdown
Member

I don't get how replacing self.workers with workers is needed by mypy for example.

AlexWaygood reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@AlexWaygood
Revert some unnecessary changes
d24bcf9
@AlexWaygood

AlexWaygood commented Sep 13, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

I don't get how replacing self.workers with workers is needed by mypy for example.

Good point, those changes aren't needed anymore. I think I needed them in an earlier version of this PR, but mypy now seems happy without them :-)

I've reverted those, thanks!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

vstinner
vstinner reviewed Sep 14, 2023
View reviewed changes

@vstinner vstinner left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Sorry, this change is too big to be reviewed. Please extract non-controversial changes: remove .github/workflows/mypy.yml changes and the lines where I added comments :-) I mean, please create a new PR with the most obvious non-controversial type hint changes.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/libregrtest/results.py Outdated
@@ -1,4 +1,5 @@
import sys
import xml.etree.ElementTree as ET

@vstinner vstinner Sep 14, 2023

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Please don't do that. I want to minimize imports at startup, to minimize how many modules are imported when a test is run. Maybe even add a comment to explain why the import is not done at top level, that it's a deliberate choice.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@AlexWaygood AlexWaygood Sep 14, 2023

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Okay. The reason why I did this was to accurately add type hints for the TestResults.testsuite_xml attribute on line 35. The current type hints for that attribute are incorrect, and caused several mypy errors.

A possible workaround is to do the top-level import inside an if TYPE_CHECKING block.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@AlexWaygood AlexWaygood Sep 14, 2023

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

A possible workaround is to do the top-level import inside an if TYPE_CHECKING block.

I made that change in 581ef0d; let me know what you think!

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/libregrtest/setup.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/test/libregrtest/single.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/test/libregrtest/single.py Outdated

class PrintWarningsType(Protocol):
orig_stderr: io.TextIOWrapper
def __call__(self, msg: str) -> None: ...

@vstinner vstinner Sep 14, 2023

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

If possible, I would prefer avoiding to have to add glue on top of code just to please mypy. If print_warning() API is too weird for mypy, maybe rewrite it with such class directly in test.support, no?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@AlexWaygood AlexWaygood Sep 14, 2023

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

If print_warning() API is too weird for mypy, maybe rewrite it with such class directly in test.support, no?

Unfortunately not. Mypy doesn't know that the test.support module exists: when it comes to the stdlib, it only knows about the modules we include stubs for in typeshed. Historically, we haven't included stubs for any modules in the Lib/test/ directory, as these aren't available on all builds of Python, and are generally only meant to be used by CPython core devs like us. As a result, everything that is imported from test.support is inferred by mypy as being of type Any.

However, that also means that we don't need this protocol here: I only added it to give mypy a little more information, and make the code slightly more type safe. Since you don't like it, I'll remove it!

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@vstinner vstinner Sep 14, 2023

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Mypy doesn't know that the test.support module exists

Can't we make mypy aware of test.support, instead of having to put ducktape to workaround these limitations?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@AlexWaygood AlexWaygood Sep 14, 2023

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Can't we make mypy aware of test.support

This is somewhat tricky due to the fact that regrtest is in the Lib/test/ directory. Mypy hates being run on stuff inside the Lib/ directory, as it thinks that everything inside the Lib/ directory is "shadowing the stdlib". The only way we're managing to get mypy happy with being run on libregrtest is by cd-ing into Lib/test/, and then running mypy with very specific options so that it doesn't look anywhere else in the Lib/ directory, it only looks in Lib/test/libregrtest.

There would be some ways of making mypy aware of test.support, but I'm not sure I like any of them:

  1. We could write a custom script that copies libregrtest and test.support into a temporary directory, then runs mypy on them together. Why I don't like this: it's easier for users if they can run mypy just by invoking mypy on the command line. Having to run mypy via a wrapper script is a bad user experience, and it's more code for us to maintain as well.
  2. We could add stubs for test.support in typeshed, so that mypy sees test.support as "just another part of the stdlib". Why I don't like this: lots of Python users can't access test.support on their installed versions of Python, but if we add stubs for test.support in typeshed, mypy will never complain if users import test.support in their own code. Also, it will be a lot of work for us typeshed maintainers to maintain stubs for test.support, since the test.support module tends to change its API a lot more frequently than other things in the Lib/ directory.
  3. We could add stubs for test.support inside the libregrtest directory itself. Why I don't like this: this just feels like it would be really ugly, and really hard to maintain. The stubs would go out of date really quickly, if we weren't careful.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@vstinner vstinner Sep 14, 2023

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

We could write a custom script that copies libregrtest and test.support into a temporary directory

That sounds like a good idea to me.

I would prefer that mypy users need workaround, than libregrtest have to write complicated workarounds in the working code just to please mypy.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/libregrtest/single.py
)
if use_timeout:
faulthandler.dump_traceback_later(timeout, exit=True)
faulthandler.dump_traceback_later(cast(float, timeout), exit=True)

@vstinner vstinner Sep 14, 2023

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I don't understand this cast. timeout is a float is use_timeout is True. Why is a cast needed?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@AlexWaygood AlexWaygood Sep 14, 2023

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Yes, this code is type-safe. The issue is that mypy only understands a limited set of type narrowing operations, and the way timeout has been narrowed to be a float here isn't one of them.

Mypy understands this kind of logic:

x: float | None
if x is not None:
    # OK, mypy understands `f` has to be a float here

But this kind of thing is too complex for mypy:

x: float | None
x_is_None = x is None
if not x_is_None:
    # mypy will not understand that x has been safely narrowed to `None` here

Another way we could make mypy happy would be to add an assert, like this -- but it feels redundant to me, since the type of timeout has already been narrowed to be a float in the lines immediately preceding this:

Suggested change
faulthandler.dump_traceback_later(cast(float, timeout), exit=True)
assert timeout is not None
faulthandler.dump_traceback_later(timeout, exit=True)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/libregrtest/worker.py
match_tests: FilterTuple | None = runtests.match_tests
json_file: JsonFile = runtests.json_file
json_file = runtests.json_file
assert isinstance(json_file, JsonFile)

@vstinner vstinner Sep 14, 2023

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I dislike assert, it's removed by python -O. Why is this assertion needed? The attribute is declared as json_file: JsonFile | None. Is it to remove the None case?

If mypy doesn't understand the logic, maybe a developer can have the same doubt. Maybe add a regular if json_file is None: raise ....

Or maybe, RunTests can have a sub-type which adds the json_file attribute: the class used by create_worker_process() / worker_process(). Would it please mypy?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@AlexWaygood AlexWaygood Sep 14, 2023

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Why is this assertion needed? The attribute is declared as json_file: JsonFile | None. Is it to remove the None case?

Yes, it's to remove the None case.

If mypy doesn't understand the logic, maybe a developer can have the same doubt. Maybe add a regular if json_file is None: raise ....

Sure. Should I do the same for all asserts being proposed in this PR?

Or maybe, RunTests can have a sub-type which adds the json_file attribute: the class used by create_worker_process() / worker_process(). Would it please mypy?

Yes, that might also make mypy happier. Hard to tell without seeing a PR and running mypy on it, though :-)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
AlexWaygood added 5 commits September 14, 2023 13:25
@AlexWaygood
PEP 585
87c3e8e
@AlexWaygood
Add comment to type: ignore comment on case TestResults()
800d080
@AlexWaygood
Remove PrintWarningsType
98d3000
@AlexWaygood
results.py: Don't import xml.etree.ElementTree in the global scope
581ef0d
@AlexWaygood
minimize diff
89e4a77
@AlexWaygood AlexWaygood mentioned this pull request Sep 14, 2023
gh-109413: libregrtest: Add and improve type annotations #109405
Merged
@AlexWaygood

AlexWaygood commented Sep 14, 2023

Copy link
Copy Markdown
Member Author

please create a new PR with the most obvious non-controversial type hint changes.

Okay, I've had a go at doing that in #109405

vstinner reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Sep 15, 2023

Copy link
Copy Markdown
Member

Can you rebase your PR on the main branch?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@AlexWaygood

AlexWaygood commented Sep 15, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

I'll close this for now, and continue to break it up into smaller PRs so that it's obvious what I'm doing at each stage 👍

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@AlexWaygood AlexWaygood closed this Sep 15, 2023
@AlexWaygood
AlexWaygood deleted the regrtest-mypy-2 branch September 15, 2023 13:27
@AlexWaygood
AlexWaygood restored the regrtest-mypy-2 branch September 15, 2023 13:27
@vstinner

vstinner commented Sep 15, 2023

Copy link
Copy Markdown
Member

Nice! I like this idea :-)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@AlexWaygood AlexWaygood mentioned this pull request Sep 15, 2023
gh-109413: Add a custom script for running mypy on libregrtest #109464
Closed
@AlexWaygood
AlexWaygood deleted the regrtest-mypy-2 branch March 7, 2024 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@vstinner vstinner vstinner left review comments
@ezio-melotti ezio-melotti Awaiting requested review from ezio-melotti ezio-melotti will be requested when the pull request is marked ready for review ezio-melotti is a code owner
@hugovk hugovk Awaiting requested review from hugovk hugovk will be requested when the pull request is marked ready for review hugovk is a code owner
@AA-Turner AA-Turner Awaiting requested review from AA-Turner AA-Turner will be requested when the pull request is marked ready for review AA-Turner is a code owner
@webknjaz webknjaz Awaiting requested review from webknjaz webknjaz will be requested when the pull request is marked ready for review webknjaz is a code owner
@itamaro itamaro Awaiting requested review from itamaro itamaro will be requested when the pull request is marked ready for review itamaro is a code owner
@JacobCoffee JacobCoffee Awaiting requested review from JacobCoffee JacobCoffee will be requested when the pull request is marked ready for review JacobCoffee is a code owner
@StanFromIreland StanFromIreland Awaiting requested review from StanFromIreland StanFromIreland will be requested when the pull request is marked ready for review StanFromIreland is a code owner

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

skip news

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@AlexWaygood @vstinner
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.