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 plugin #722
Mypy plugin #722
Conversation
In principle this looks great, but as you say let's defer it until 1.1 - it shouldn't cause any backwards incompatibility issues I assume? |
You can always just turn the plugin off (by not incluiding it in |
For what it's worth, if anyone wants this in the interim, you can just copy/paste the contents of the pydantic/mypy.py file into your own project and add it to the mypy plugins in your It would be nice to be able to distribute it with the library though. |
Codecov Report
@@ Coverage Diff @@
## master #722 +/- ##
======================================
Coverage 100% 100%
======================================
Files 16 17 +1
Lines 2800 3142 +342
Branches 543 615 +72
======================================
+ Hits 2800 3142 +342
Continue to review full report at Codecov.
|
After some painful edge case exploration and mypy debugging, I've gotten the test coverage of the plugin itself up to 100% (modulo two minor no-covers related to import edge cases, where I've just copied the logic from the official dataclasses plugin). Still needs:
I think it might make sense to (eventually) support other config settings and/or finer-grained strictness controls, but I'm more inclined to just release this and see what features people actually request. Edit: Actually, I'm going to hold off on adding support for construct until I have a chance to work on python/mypy#7301; otherwise we'd have to copy a lot of code right out of mypy. Edit 2: It turned out to be easier than I expected to get this working. PR opened for the mypy issue, but I was able to drop a single function into place that we can remove once the PR is merged. |
@samuelcolvin I think this is basically done! I added docs and updated the description at the top with some more detail. I think the docs pretty clearly cover everything the plugin adds. The tests are a little haphazard organized, basically just dumped into the big Special note: these changes should make running the mypy tests and mypy check faster on subsequent runs due to better caching (even though there are now more tests). |
Also, @koxudaxi if you have a chance to review I think you might find it interesting and/or have some inputs. |
I'm away from my computer but will look on Tuesday if not before. Are we caching the mypy cache directory (sorry can't see on my phone)? |
@samuelcolvin Sounds good, no rush. I’m not sure what you mean by “are we caching the mypy cache directory” — could you clarify? I put the test caches inside the default one (used during checks). The structure of the caching directories is such that this doesn’t cause any conflicts. |
Sorry, I mean there's a |
Yeah, the directory is |
Well, might make things faster. Don't worry if it's a pain. |
In general this all looks great. Must have been a massive effort!
More of my comments are questions or trivial corrections.
|
||
cases = [ | ||
('mypy-plugin.ini', 'plugin_success.py', None), | ||
('mypy-plugin.ini', 'plugin_fail.py', 'plugin-fail.txt'), |
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.
are you sure these are really easier as separate files? Surely easier to have the expected output right here with the test even if some are very verbose?
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.
It's extremely annoying to iterate on it without a mechanism for generating the expected output. By putting it in a file, I can set GENERATE=True
above and it will write the file with the actual output, and I can look at the git diffs to see if things are as desired.
I initially tried having the results in-line here, but the problem is that a one line changes all the line numbers. And the line numbers actually do matter, so I think we shouldn't just strip them from the expected output. But then every time I tweak a line I had to manually compare all the output lines and fix the line numbers. Then I'd make another minor change and have to do it all again.
I think there might be better ways to manage mypy plugin tests (might be good to look at how the sqlalchemy or django plugins do this). But I thought they might ultimately rely on calling mypy on a separate file for each test, and I was specifically trying to minimize the amount of time spent executing mypy tests during normal test runs, and I think there is a substantial amount of overhead for each file analyzed. I tried to get all the tests into as few files as possible to keep the tests running fast.
@samuelcolvin I think I've incorporated all your feedback on the non-docs files, or at least responded above where I had concerns. I renamed the plugin config settings so they could all be I'm going to wait until we reach consensus on the non-docs stuff before updating the docs. |
It looks like this is what django-stubs uses. Here's a blog article discussing: https://sobolevn.me/2019/08/testing-mypy-types It looks like a massive improvement over what is used in this PR, but 1) I'm not sure how fast it would run, and 2) I'm not sure how maintained it is. We could also just run the mypy plugin tests separately, the only downside would be the added complexity of checking for 100% coverage. |
Looking good. Apart from the docs and a few pretty trivial potential fixes, I think this is more or less ready. |
I tried using dataclasses but it caused the cythonized builds to fail due to the Maybe there's a workaround, but since it's not really giving much benefit here I figured hand-writing the init function was fine. |
Also, I believe I have now addressed all your concerns with regard to the docs. Maybe give it another once over, but I think it's good to go now. |
this is awesome. Thank you very much! |
* Add mypy plugin * Make all arguments optional for BaseSettings * Get test coverage up * Add changes * Add type-checking for BaseModel.construct, and checking for from_orm * Fix formatting and linting * Fix the build * Heavy refactor of plugin and mypy tests * Make linting pass * Handle dynamic aliases * Better organize plugin code * Add docs * Add support for error codes * Fix minor docs typo * Rename config settings, add docstrings, and incorporate other feedback * Incorporate feedback * Update docs, remove dataclasses for cython * fix mypy example
Change Summary
Add a mypy plugin with a number of features; see the added docs for more details.
Other notable improvements for pydantic developers:
this seemed like the most practical solution for now
.mypy_cache
folder..mypy_cache
, the samemake clean
works to clean up all of the cache directoriesRelated issue number
Closes #460
Checklist
changes/
,see changes/README.md for details
on the format