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
argparse types (and actions) must be hashable #60720
Comments
The argparse documentation states that "type= can take any callable that takes a single string argument and returns the converted value". The following is an exception: >>> import argparse
>>> ap = argparse.ArgumentParser()
>>> ap.add_argument('foo', type={}.get)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3/argparse.py", line 1294, in add_argument
type_func = self._registry_get('type', action.type, action.type)
File "/usr/lib/python3/argparse.py", line 1236, in _registry_get
return self._registries[registry_name].get(value, default)
TypeError: unhashable type: 'dict' Sadly, a method bound to an unhashable type is unhashable! (Of course, is trivial to use partial or lambda to make any function hashable.) The offending line in _registry_get is intended to look up named types (or actions), so it perhaps only relevant for string type= and action= values, which could be handled explicitly instead of using dict.get(x, x) to handle both cases. Alternatively, the TypeError could be caught and default returned. |
@paul can you take a look at this please. |
This is a straight forward patch, modifying '_registry_get' to return 'default' if it gets this 'TypeError'. 'test_argparse.py' has a testcase based on jnothman's example. Temporarily it includes a skipped test that would pass the original code. The alternative would be to add a note to the documentation to the effect that the 'type' must also be hashable. But for an edge condition like this, that may be more confusing than enlightening. While 'dict(one=1, two=20).get' now works as a 'type' callable, it is not ideal. If there is no match it returns None. The alternative '.__getitem__' raises a KeyError. But '_get_values' handles TypeError and ValueErrors, the kinds returned by 'int' and 'float'. It also handles an ArgumentTypeError, giving a custom type more control over the error message. Is it worth noting something about the type errors in the documentation? I've seen users make a different error with the type parameter - 'type=boolean', thinking this means the input should be converted to boolean. They are thinking of 'type' as a datatype, rather than a function that converts a string into something else. I don't know of a solution other than explaining that 'boolean()' does not act like 'int()'. This patch also handles the 'action' case. However I can't think of a way write a Action subclass that would be unhashable. It would have to inherit from both Action and dict. |
Clearly this is not in high demand |
I've got confused with the "TypeError: unhashable type: 'dict'" error creating a choose-from-dictionary argument in Python 3.6. I used lambda as a workaround, but IMO it would be great to have this patch merged. |
Hi bradengroom, Thank you! |
Luna and I talked a bit about this offline and we decided not to merge the PR (nor the original patch, which is the same). Instead Luna will add a note to the docs explaining the caveat. |
Luna discovered that has actually been fixed in 3.8 (i.e. the master branch), by making {}.get hashable. So I'm closing this as fixed. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: