Skip to content

Conversation

kurtmckee
Copy link
Contributor

This PR introduces the following changes:

  • Add mypy as a test environment for tox and CI.
  • Make watchdog PEP 561 compatible (signaling that it has type annotations).
  • Remove the emitter_class parameter from BaseObserver.__init__(). This aligns the call signature of the base class with its subclasses and allows the code sample in README.rst to pass mypy checks.

Closes #840

@BoboTiG
Copy link
Collaborator

BoboTiG commented Jul 9, 2022

There is a breaking change, could you add a line in the changelog for that?

@kurtmckee
Copy link
Contributor Author

Done. Please let me know if this is acceptable, or if other changes are desired. Thanks!

@BoboTiG
Copy link
Collaborator

BoboTiG commented Jul 31, 2022

Sorry for the delay.

After a second thought, I am not comfortable with the breaking change: it's a historic API, and may be overridden a lot in the nature.
Could you try using another approach that doesn't break the current API?

@kurtmckee
Copy link
Contributor Author

Yep, I'll try to do that. I'll rewrite the history so the commits are clean.

@kurtmckee kurtmckee force-pushed the add-mypy-type-checking branch from c590714 to f535a8c Compare August 2, 2022 13:14
@kurtmckee
Copy link
Contributor Author

I think this is addressed now. I've rebased to keep the commit history clean. Please let me know if additional changes are needed! 👍

@kurtmckee kurtmckee force-pushed the add-mypy-type-checking branch 2 times, most recently from ef1fdeb to d03274d Compare August 4, 2022 13:18
@altendky
Copy link
Contributor

altendky commented Mar 6, 2023

Is this, or something like it, going to happen? If help is wanted, I'll do what I can. Having a py.typed for a library that isn't well hinted is problematic.

@BoboTiG
Copy link
Collaborator

BoboTiG commented Mar 6, 2023

@kurtmckee could you fix conflicts 🙏🏻 ?

@altendky I'll review again the PR tomorrow. I would prefer to not remove is_<plateform>() calls in observer/__init__.py. If you know a better way I would love to consider it. Also, it would be great to have another review, if you have some time for that :)

@kurtmckee
Copy link
Contributor Author

Sure thing! It won't be immediate due to work requirements but I can jump back to this soon!

@altendky
Copy link
Contributor

altendky commented Mar 7, 2023

I'm skeptical about finding a good solution to avoid platform checks that mypy is aware of. I guess a mypy plugin might be able to use it, but... ick. Could you provide some explanation of what about that code makes it important to keep around? I'm not questioning it yet, but i don't have any of the history to know what makes not changing it important. mypy platform checks have even annoying corner cases as it is.

Thanks to you both for your interest in this both before, and now. :]

@altendky
Copy link
Contributor

altendky commented Mar 7, 2023

Hmm, now that I said that...

if (not typing.TYPE_CHECKING and platform.is_linux()) or (typing.TYPE_CHECKING and sys.platform == "linux"):

Maybe? Point being to retain runtime behavior at runtime and preferred type checking behavior when type checking. Still ick, but something.

@BoboTiG
Copy link
Collaborator

BoboTiG commented Mar 7, 2023

Lets go with the cleanest way that works for mypy. Changes seem good then 👍🏻

@altendky
Copy link
Contributor

altendky commented Mar 7, 2023

As a first pass, it looks like all our mypy checks pass with this PR. https://github.com/Chia-Network/chia-blockchain/actions/runs/4355725081 I'll take a quick pass over the changes now and maybe more detailed after ci is green.

@kurtmckee
Copy link
Contributor Author

Thanks, @altendky, that's a confidence boost for the direction of this work! I should be able to return to this soon but have to get through some work requirements first. 😀

Copy link
Contributor

@altendky altendky left a comment

Choose a reason for hiding this comment

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

There are some high level things I would encourage doing beyond just this PR. I'm happy to put in my own time towards them and handling them in a separate following PR seems ok.

  1. Run the mypy checks at least across multiple platforms if not also across supported Python versions. Dependencies can vary across each of those. The watchdog code itself certainly varies a lot depending on the platform.

  2. I tend to work with quite strict mypy settings. Applications sort of get a choice but libraries need to live up to whatever standards they want to enable their users to achieve. The default mypy setting mostly only checks stuff that is actively hinted. Requiring that everything is hinted and that Any is banned as much as possible is valuable, along with misc other settings. For the record, I look to https://github.com/altendky/qtrio/blob/459492f5f3d1fe6b6bb8b4e93d9a1bd1cdb4dc32/mypy.ini and https://github.com/Chia-Network/chia-blockchain/blob/8430b072e262cb7a80e688fdc3ad8f1fd2b50d0e/mypy.ini as my personal references for where I've ended up with mypy config.

  3. I try to always ignore the specific error message as opposed to general # type: ignore comments. I see that some ignores here do, many don't. When following this, it is useful to add show_error_codes = True to mypy.ini so they error output includes the error code to ignore.

  4. I certainly don't follow it in all my own cases... but I do like having comments for type ignores. This makes it easier to read and conclude they are appropriate. If possible, a link to a PR or issue that when resolved should result in a reconsideration of the ignore. Sometimes either some or all of the actual mypy complaint is good.

Again, thanks to all for the work here. Based on my mypy checks failing with v2.3.1 but passing with this PR, this is an improvement. Even if you like my suggestions, they can certainly be considered as followups for me to invest my own time in. :]

Comment on lines 18 to 23
# The `select` module varies between platforms.
# mypy may complain about missing module attributes
# depending on which platform it's running on.
# The comment below disables mypy's attribute check.
#
# type: ignore[attr-defined]
#

Copy link
Contributor

Choose a reason for hiding this comment

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

Big Picture: I think this is a macOS/BSD only option? If so we can encase the whole thing in a platform check instead of ignoring. I guess perhaps a not-windows-not-linux check would be the applicable one here?


Small Picture: Locally, with the just-released mypy 1.1.1 anyways, I get src/watchdog/observers/kqueue.py:23: error: type ignore with error code is not supported for modules; use # mypy: disable-error-code=... [syntax]

@@ -119,11 +119,11 @@ def _errcheck_dword(value, func, args):
return args


kernel32 = ctypes.WinDLL("kernel32")
kernel32 = ctypes.WinDLL("kernel32") # type: ignore[attr-defined]
Copy link
Contributor

Choose a reason for hiding this comment

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

With this being Windows only we could again encapsulate the whole file with a platform check. I mean yeah, it's ugly. I take a layer of indentation over lack of good hint checking though, personally.

@@ -49,7 +52,7 @@
WindowsApiEmitter as Emitter
)
elif platform.is_bsd():
from watchdog.observers.kqueue import (
from watchdog.observers.kqueue import ( # type: ignore[attr-defined,no-redef]
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to keep around the mypy-incompatible platform checks? Or can we apply the compatible ones everywhere? I think the result in terms of ignoring this code is the same unless we have BSD systems in the test matrix, but just as a general thing I wonder about fully dropping the incompatible check mechanism. Even if there is agreement on that, I understand that that could well end up as a breaking change to save for a major version bump. Though, it does appear to be not documented which makes it at least a little less clearly public API. :] https://watchdog.readthedocs.io/en/latest/api.html#module-watchdog.utils

@kurtmckee kurtmckee force-pushed the add-mypy-type-checking branch from d03274d to 81d49b2 Compare March 10, 2023 14:00
@kurtmckee
Copy link
Contributor Author

kurtmckee commented Mar 10, 2023

✔️ Step 1: Rebased on master branch.
✔️ Step 2: Fix new errors that occur with the latest versions of mypy.

I'm going to take a step back from this effort and work on CI, which needs an overhaul. @BoboTiG, expect separate PR's to address some issues in CI.

@kurtmckee
Copy link
Contributor Author

@altendky I'm under the impression that you have a deeper knowledge of type annotations, and how they can be applied in platform-specific ways. Would you be open to @BoboTiG reviewing this PR as-is and then working in parallel toward tightening the type annotations and getting the test suite to pass reliably on all platforms?

@altendky
Copy link
Contributor

Yep, works for me. As is this is useful for both of us.

@BoboTiG
Copy link
Collaborator

BoboTiG commented Mar 10, 2023

Thanks both of you. It will be useful to a lot more people at the end :)

@BoboTiG BoboTiG merged commit 4d1510d into gorakhargosh:master Mar 10, 2023
@kurtmckee kurtmckee deleted the add-mypy-type-checking branch March 10, 2023 16:18
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.

mypy failure against sample code from watchdog homepage
3 participants