diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c4176dbf..3b9df3347 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `LocalWorkspace` now creates a symlink to the outputs of the latest run. - Tango is now better at guessing when a step has died and should be re-run. - Tango is now more lenient about registering the same class under the same name twice. +- When you use `dict` instead of `Dict` in your type annotations, you now get a legible error message. Same for `List`, `Tuple`, and `Set`. ### Fixed @@ -38,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Made `FromParams` more efficient by only trying to parse the params as a `Step` when it looks like it actually could be a step. - Fixed bug where `Executor` would crash if `git` command could not be found. - Fixed bug where validation settings were not interpreted the right way by the torch trainer. +- When you register the same name twice using `Registrable`, you get an error message. That error message now contains the correct class name. ## [v0.4.0](https://github.com/allenai/tango/releases/tag/v0.4.0) - 2022-01-27 diff --git a/tango/common/from_params.py b/tango/common/from_params.py index f1327386b..da9848c90 100644 --- a/tango/common/from_params.py +++ b/tango/common/from_params.py @@ -141,7 +141,38 @@ def infer_method_params( # `from __future__ import annotation`, the annotation will be a str, # so we need to resolve it using `get_type_hints` from the typing module. # See https://www.python.org/dev/peps/pep-0563/ for more info. - parameters[param_name] = param.replace(annotation=get_type_hints(method)[param_name]) + try: + parameters[param_name] = param.replace( + annotation=get_type_hints(method)[param_name] + ) + except TypeError as e: + if "'type' object is not subscriptable" in str(e): + # This can happen when someone uses a type hint like `dict[str, str]` + # instead of `Dict[str, str]`. + err_msg = ( + f"Failed to parse the type annotation `{param.annotation}` " + f"from `{cls.__qualname__}.{method.__name__}()`." + ) + + if "[" in param.annotation: + # Check if there is an equivalent generic in the `typing` module. + import typing + + type_, *_ = param.annotation.split("[", 1) + for possible_typing_equivalent in {type_, type_.title()}: + if hasattr(typing, possible_typing_equivalent): + err_msg += ( + f" Try using `{possible_typing_equivalent}` " + "from the `typing` module instead." + ) + break + + new_e = TypeError(err_msg) + new_e.__cause__ = e + new_e.__cause__ = e + raise new_e + else: + raise if var_positional_key: del parameters[var_positional_key]