-
Notifications
You must be signed in to change notification settings - Fork 215
Fix Optional failing when default is some builtins
#276
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 Optional failing when default is some builtins
#276
Conversation
Optional failing when default is some builtins, and fix incompatibility with Python 2.7Optional failing when default is some builtins, and fix incompatibility with Python < 3.3
|
Thanks for this! Yeah, 3.3 is ancient and wasn't very widely used, so I'd be in favor of dropping support for it. Would that make your PR easier/more elegant? |
schema.py
Outdated
| try: | ||
| return f(**kwargs) | ||
| except TypeError as e: | ||
| if ( | ||
| e.args[0].startswith("{}() got an unexpected keyword argument".format(f.__name__)) # Python 2/3. | ||
| or e.args[0].startswith("{}() takes no arguments".format(f.__name__)) # Python 2 only. | ||
| ): | ||
| return f() |
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.
Is there a realistic scenario wherein someone should be passing **kwargs if the function does not support keyword-arguments in the first place?
Why not just skip the whole try/except block and unconditionally return f(**kwargs)?
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.
E.g. see test_optional_callable_default_ignore_inherited_schema_validate_kwargs:
Lines 758 to 770 in 09c00ed
| def test_optional_callable_default_ignore_inherited_schema_validate_kwargs(): | |
| def convert(data, increment): | |
| if isinstance(data, int): | |
| return data + increment | |
| return data | |
| s = {"k": int, "d": {Optional("k", default=lambda: 42): int, "l": [{"l": [int]}]}} | |
| v = {"k": 1, "d": {"l": [{"l": [3, 4, 5]}]}} | |
| d = Schema(s).validate(v, increment=1) | |
| assert d["k"] == 1 and d["d"]["k"] == 42 and d["d"]["l"][0]["l"] == [3, 4, 5] | |
| d = Schema(s).validate(v, increment=10) | |
| assert d["k"] == 1 and d["d"]["k"] == 42 and d["d"]["l"][0]["l"] == [3, 4, 5] |
That approach would work if lambda: 42 was instead lambda **_: 42. This would be a backwards-incompatible change (warranting a major version bump), though.
|
Sorry for the delayed response! Following @BvB93's comment above, I think the underlying problem here is how #268 passes around kwargs. Schema is trying to pass Given this, though, This approach is fundamentally flawed for other reasons, though. For example, suppose Now, if #268 is to be kept and not rolled back, I think that the best way to deal with this is to (a) drop Python < 3.3 so that This would be a backwards-incompatible change that would necessitate a major version bump, but AFAIK it elegantly handles all of the relevant issues here: I've implemented this below and adjusted the tests relevant tests that were added in #268 accordingly. |
|
On second thought: a major version bump is technically not necessary under SemVer even if this is merged, since Schema is still in major version 0. Schema still being v0.x.x means that if the major version is bumped, the reason for that bump should be to indicate public API stability, not to indicate backwards-incompatible changes. I am under the impression that the public API has already been stable for some time, though, so perhaps the major version should still be bumped if this is merged. |
Optional failing when default is some builtins, and fix incompatibility with Python < 3.3Optional failing when default is some builtins
Closes #272.
Note that
inspect.signature(which is used in the current_invoke_with_optional_kwargs!) is not available in Python < 3.3, which (I believe?) schema hasn't officially dropped support for yet. I know that I am just an outsider to this project, but I'd really suggest adopting #273.Also, I think that my implementation below is not the most elegant way to deal with this issue. It might be better to instead have
Optionalaccept apass_kwargsparameter rather than choosing whether or not to passkwargsbased on a heuristic.pass_argscould beTrueby default (to pass all kwargs), but could also beFalseor a set of strings (representing parameter names to pass). Let me know what you think!