-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Allow use of entry-points like strings in mypy.ini to register plugins #5358
Conversation
For example mypkg.mymod:register
I think it's fine to add this. Yes, the plugin API will still change rapidly (basically each time someone writes a new plugin they have to spend some time changing the existing API), but since we already have plugin configuration in mypy.ini I don't see how this makes it worse. (Haven't had time to review the code yet, sorry.) |
I agree. I think having a way to point mypy to a plugin has gotten significantly more important as several projects (such as attrs and numpy-stubs) will likely need this. With PEP 561 support, I only expect the number of projects wanting this to increase. I will take a look at reviewing shortly. |
Great! I'll go over this a bit more thoroughly (I haven't actually tested it yet) and get all tests passing. |
I actually wanted to do something similar myself. Using a qualified name of plugin seems much simpler and sustainable than the full path. Didn't look at the code yet, but a quick question now: why such special syntax (I mean the colon)? I would expect just a qualified name, i.e. |
This is used in entry points for packaging, so I think the idea is to mimic that. |
What I would care is whether this is a common syntax for plugins in other Python projects. If not, I would stick to something simpler. Also there is a certain asymmetry with the current syntax, for the full path we always look for a function called |
Btw, I support omitting the function name, as in the third example: [mypy]
plugins = path/plugin1.py, plugin2:register, plugin3 In the last case, the registration function defaults to |
OK, then I am fine with this. As I understand the module name can be qualified, like Btw, maybe we can also add the possibility to override the function name with a colon syntax for the case of full path (for consistency)? |
I just realized that we cannot currently tell whether a plugin registered as
I will defer to you all on this. |
Personal opinion: choice 2 would have the advantage of being explicit as to the file's location. It's immediately obvious that this is looking in the current directory, not a special lookup path of some sort or similar. |
It's not backward incompatible, though. If we're willing to make a breaking change, then why not option 3? In that case, if someone is currently using |
Who would call their module "foo.py"? That would mean they have a filename
"foo/py.py". That's just silly. So if it ends in ".py" (exactly) it should
be treated as a file.
|
So option 5 then ;) |
I am with Guido here. |
I added some tests. For certain key cases related to the loading mechanism, I test both the file and module style loading, but what do you think about converting the remainder to use the module-style by default? |
@chadrik Thanks for adding tests! I like the PR in general, but it looks like I will not have time to review this in detail before my vacation. I hope someone else can review and merge this. I have only one comment, I would prefer to see "sandboxed" tests for installed plugins, e.g. like @ethanhs did this for PEP 561 packages testing instead of modifying |
Enjoy your well earned vacation! I am happy to take this over, unless anyone else would prefer to take it (go ahead and unassign me if so). |
Thanks -- please go ahead, Ethan! |
The existing plugin tests use testcheck.py which runs in the current process. Pushing this into a subprocess will necessitate a specialized runner for plugins, which substantially increases the scope |
I think ideally the plugin tests should have their own suite which is run out of process. The check suite is supposed to test the core type checking features of mypy, a plugin seems like a different unit to test. That being said, if you feel like it would be easier, I think there will plenty of time to refactor the testing in a separate PR. |
I completely agree with your logic, I’m just time poor and I don’t want
this PR to get hung up on that issue. Let’s put it in a separate PR.
…On Sat, Jul 28, 2018 at 4:17 PM Ethan Smith ***@***.***> wrote:
I think ideally the plugin tests should have their own suite which is run
out of process. The check suite is supposed to test the core type checking
features of mypy, a plugin seems like a different unit to test. That being
said, if you feel like it would be easier, I think there will plenty of
time to refactor the testing in a separate PR.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#5358 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAD3E_o0HBcU1q8wI318Y2P1BlU5nGjSks5uLPD_gaJpZM4VQD5z>
.
|
I usually prefer having non-trivial refactorings as separate PRs. PRs with both refactorings and new features are slower to review. They are also more likely to get merge conflicts, resulting in further delays. Sometimes it's best to do the refactoring as the first PR, but this is up to the author. |
It sounds like we are in agreement about creating a separate ticket for
sandboxing the plugin tests. What’s left to do on this one?
…On Mon, Jul 30, 2018 at 4:13 AM Jukka Lehtosalo ***@***.***> wrote:
I usually prefer having non-trivial refactorings as separate PRs. PRs with
both refactorings and new features are slower to review. They are also more
likely to get merge conflicts, resulting in further delays. Sometimes it's
best to do the refactoring as the first PR, but this is up to the author.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#5358 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAD3E4WBgNh-IRFMRQWf9yMM2AL2EeOUks5uLupbgaJpZM4VQD5z>
.
|
I will do a final review later today and hopefully merge. |
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.
Just two minor things. Thank you for working on this!
mypy/build.py
Outdated
@@ -580,33 +581,43 @@ def plugin_error(message: str) -> None: | |||
errors.set_file(options.config_file, None) | |||
for plugin_path in options.plugins: | |||
# Plugin paths are relative to the config file location. |
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.
This comment seems out of date.
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.
true. will get this addressed once I get your answer on the second issue.
mypy/build.py
Outdated
fnam = os.path.basename(plugin_path) | ||
module_name = fnam[:-3] | ||
sys.path.insert(0, plugin_dir) | ||
elif re.search(r'\/', plugin_path): |
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.
This won't work correctly on Windows if someone gives a path with e.g C:\\Foo\\bar
. I'd recommend os.sep in plugin_path
instead.
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.
Thanks for catching that. What I intended to do was this:
re.search(r'[\\/]', plugin_path)
I considered os.sep
, but decided against it because it's bound to the current OS. I think it's more correct to detect anything that looks like a file path, but I'll let you make the call.
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.
That is a good point. I think your proposed solution is good.
Notes addressed |
@chadrik thank you! |
This addresses issue #3916. Unlike my last attempt this does not use
pkg_resources
.It is currently possible for third-parties to author plugins and load them via mypy.ini, using a path to a plugin file. e.g.
This PR extends the syntax to allow plugins to be specified using entry-points-like strings:
Reservations have been expressed about the still-experimental nature of the plugin API. In rebuttal, I would say:
Perhaps a compromise is to simply not advertise this feature extensively yet. It will enable projects like attrs, which are at the bleeding edge of static type checking and well aware of the unsupported risks involved, to push the tooling forward, while shouldering the responsibility of making adjustments to our plugin if the API changes.