Skip to content

Type annotation infrastructure and initial typing for qtbot.py #605

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

Open
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

herobank110
Copy link

@herobank110 herobank110 commented May 22, 2025

Initial version of adding type annotations to the library.

  • infrastructure of mypy in precommit (ci and local type checking)

  • Typing focused around qtboy.py to start with

  • Note: qt objects are typed with aliases refering to Any - this may be upgraded in future to use correct types.

@herobank110 herobank110 marked this pull request as draft May 22, 2025 22:39
@herobank110 herobank110 mentioned this pull request May 22, 2025
@herobank110 herobank110 changed the title Type annotation test Type annotation infrastructure and initial typing for qtbot.py Jun 8, 2025
@@ -617,9 +668,9 @@ def captureExceptions(self):
with capture_exceptions() as exceptions:
yield exceptions

capture_exceptions = captureExceptions
Copy link
Author

Choose a reason for hiding this comment

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

Note: removed this line becausemypy gave a warning about this also being assigned in the constructor here: https://github.com/pytest-dev/pytest-qt/blob/master/src/pytestqt/qtbot.py#L153

@herobank110 herobank110 marked this pull request as ready for review June 8, 2025 20:14
Copy link
Member

@nicoddemus nicoddemus left a comment

Choose a reason for hiding this comment

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

Thanks a lot @herobank110!

Left some comments, please take a look!

@@ -174,7 +174,7 @@
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
# 'preamble': '',
}
} # type: dict[str, str]
Copy link
Member

@nicoddemus nicoddemus Jun 10, 2025

Choose a reason for hiding this comment

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

I think we should add a mypy.ini file and add some options:

[mypy]
files = src,tests
no_implicit_optional = True
pretty = True
show_error_codes = True
strict_equality = True
warn_redundant_casts = True
warn_unused_configs = True
warn_unused_ignores = True

This way we can remove this type annotation:

Suggested change
} # type: dict[str, str]
}


__version__ = version
__version__ = cast("str", version)
Copy link
Member

Choose a reason for hiding this comment

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

Does this work?

Suggested change
__version__ = cast("str", version)
__version__: str = version

Comment on lines +36 to +39
QWidget = Any
SignalInstance = Any
QRect = Any
QKeySequence = Any
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
QWidget = Any
SignalInstance = Any
QRect = Any
QKeySequence = Any
QWidget: TypeAlias = Any
SignalInstance: TypeAlias = Any
QRect: TypeAlias = Any
QKeySequence: TypeAlias = Any

if value in (True, False):
return value
return cast("bool", value)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return cast("bool", value)
return cast(bool, value)

try:
return {"true": True, "false": False}[value.lower()]
return {"true": True, "false": False}[cast("str", value).lower()]
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return {"true": True, "false": False}[cast("str", value).lower()]
return {"true": True, "false": False}[cast(str, value).lower()]

Or:

Suggested change
return {"true": True, "false": False}[cast("str", value).lower()]
return {"true": True, "false": False}[str(value).lower()]

@@ -593,7 +644,7 @@ def waitCallback(self, *, timeout=5000, raising=None):
return blocker

@contextlib.contextmanager
def captureExceptions(self):
def captureExceptions(self) -> Generator["CapturedExceptions", None, None]:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
def captureExceptions(self) -> Generator["CapturedExceptions", None, None]:
def captureExceptions(self) -> Iterator["CapturedExceptions"]:



def _add_widget(item, widget, *, before_close_func=None):
QtBot.SignalEmittedError = SignalEmittedError # type: ignore[attr-defined]
Copy link
Member

Choose a reason for hiding this comment

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

Does using ignore[attr-defined] here means that the type checker does not know about QtBot.SignalEmittedError?

If so, we should move this to the class declaration:

class QtBot:
    ...
    SignalEmittedError: ClassVar[Type[SignalEmittedError]] = SignalEmittedError

(Same for the other exceptions of course)

@@ -46,3 +46,7 @@ repos:
files: ^(HOWTORELEASE.rst|README.rst)$
language: python
additional_dependencies: [pygments, restructuredtext_lint]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v1.15.0'
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
rev: 'v1.15.0'
rev: 'v1.16.0'

@nicoddemus nicoddemus requested a review from The-Compiler June 10, 2025 13:19
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.

2 participants