Skip to content
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

🐛 Fix Mypy plugin crash on variadic arguments #525

Conversation

connorbrinton
Copy link
Contributor

These changes fix a crash that would occur in the Thinc Mypy plugin whenever a Thinc API function was called with variadic arguments.

Previously the Thinc Mypy plugin would treat any argument with a generic type as a Model instance and attempt to infer a more specific type for the return type of the function call. However, the Thinc Mypy plugin was intended to only be used on functions that exclusively accept and return Model instances. Since the plugin accepted overly broad input, it would sometimes end up trying to access the second generic type argument for a generic type instance with only a single argument. This resulted in the plugin crashing.

This specifically manifested itself whenever variadic arguments were passed to a Thinc API function. Mypy passes the type of variadic arguments as List[Model[InT, OutT]]. The Thinc Mypy plugin would look at this type and attempt to treat it as an unwrapped Model type since the plugin would allow any generic type as an argument type annotation. Later on the plugin would attempt to retrieve the output type of the "Model". Since List accepts only a single generic argument, attempting to access type.args[1] would cause the crash.

These changes fix this by restricting the input on which the Thinc Mypy plugin operates. Specifically each argument and the return type must:

  • Be a generic type Instance,
  • Refer to the thinc.model.Model type and
  • Have two generic type arguments

Notably these restrictions prevent the Thinc Mypy plugin from working on subclasses of thinc.model.Model. While this plugin previously had some support for Model subclasses, this behavior was not documented and unintentional. Model subclasses were only properly handled if their first two generic type arguments had the same meaning as Model's generic type arguments.

Support for Model subclasses may be restored in the future through the use of Mypy's map_instance_to_supertype function. I just haven't figured out how to use it yet 😅

Fixes #519

These changes add comments to the `get_reducers_type` function
annotating the purpose and meaning of various sections of the function.
This will help future newcomers understand the logic used to compute
more specific types for model-combining functions.
These changes add a regression test checking whether or not
type-checking succeeds when applied to a file with variadic arguments
passed to a Thinc API function.
These changes fix a crash that would occur in the Thinc Mypy plugin
whenever a Thinc API function was called with variadic arguments.

Previously the Thinc Mypy plugin would treat any argument with a generic
type as a `Model` instance and attempt to infer a more specific type for
the return type of the function call. However, the Thinc Mypy plugin was
intended to only be used on functions that exclusively accept and return
`Model` instances. Since the plugin accepted overly broad input, it
would sometimes end up trying to access the second generic type argument
for a generic type instance with only a single argument. This resulted
in the plugin crashing.

This specifically manifested itself whenever variadic arguments were
passed to a Thinc API function. Mypy passes the type of variadic
arguments as `List[Model[InT, OutT]]`. The Thinc Mypy plugin would look
at this type and attempt to treat it as an unwrapped `Model` type since
the plugin would allow any generic type as an argument type annotation.
Later on the plugin would attempt to retrieve the output type of the
"Model". Since `List` accepts only a single generic argument, attempting
to access `type.args[1]` would cause the crash.

These changes fix this by restricting the input on which the Thinc Mypy
plugin operates. Specifically each argument and the return type must:
* Be a generic type `Instance`,
* Refer to the `thinc.model.Model` type and
* Have two generic type arguments

Notably these restrictions prevent the Thinc Mypy plugin from working on
subclasses of `thinc.model.Model`. While this plugin previously had some
support for `Model` subclasses, this behavior was not documented and
unintentional. `Model` subclasses were only properly handled if their
first two generic type arguments had the same meaning as `Model`'s
generic type arguments.

Support for `Model` subclasses may be restored in the future through the
use of Mypy's `map_instance_to_supertype` function. I just haven't
figured out how to use it yet 😅

Fixes explosion#519
@adrianeboyd
Copy link
Contributor

Thanks for the PR! I'll go ahead and try to fix the python version compat issues from our end.

@svlandeg svlandeg added feat / types Type hints and type checking bug Bugs and behaviour differing from documentation labels Aug 30, 2021
Copy link
Member

@svlandeg svlandeg left a comment

Choose a reason for hiding this comment

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

Hi @connorbrinton,

This all looks pretty good, I particularly appreciate the detailed explanations, code comments and additional unit test :-) I made a few small nitpicking suggestions for some of the comments, as it makes sense to avoid statements with "I/my" in the code base, as you don't know later on who wrote what (and it shouldn't really matter either).

thinc/mypy.py Outdated Show resolved Hide resolved
thinc/tests/regression/issue519/test_issue519.py Outdated Show resolved Hide resolved
Co-authored-by: Sofie Van Landeghem <svlandeg@users.noreply.github.com>
@connorbrinton
Copy link
Contributor Author

@svlandeg Thanks for those suggestions, they've been committed 🙂

@svlandeg
Copy link
Member

svlandeg commented Aug 30, 2021

We'll get this released as part of 8.0.9 so we can continue with explosion/spaCy#8773!

@svlandeg svlandeg merged commit c028bd9 into explosion:master Aug 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Bugs and behaviour differing from documentation feat / types Type hints and type checking
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Mypy plugin crash analyzing concatenate called with *args
3 participants