`Field.number(kind=...)` supports any function that returns a number
For example, in our internal codebase, we have a function:
def decimal_from_str(value: str, parens_negate: bool = False) -> Decimal:
...
amount = Field.number(kind=decimal_from_str)
Hmm, I didn't notice mypy isn't happy with this. We might need our own protocol with __float__ and the comparison operators. @glyph does that sound reasonable?
Hmm, I didn't notice mypy isn't happy with this. We might need our own protocol with
__float__and the comparison operators. @glyph does that sound reasonable?
Is __float__ really even necessary here? It feels like just the comparison would do it?
Hmm, I didn't notice mypy isn't happy with this. We might need our own protocol with
__float__and the comparison operators. @glyph does that sound reasonable?Is
__float__really even necessary here? It feels like just the comparison would do it?
That's a good point. The other mypy issue is str vs AnyStr, which I opened https://github.com/twisted/klein/pull/708 for
Codecov Report
All modified and coverable lines are covered by tests :white_check_mark:
Project coverage is 99.07%. Comparing base (
0f3597e) to head (030e604).
Additional details and impacted files
@@ Coverage Diff @@
## trunk #709 +/- ##
=======================================
Coverage 99.07% 99.07%
=======================================
Files 46 46
Lines 3986 4002 +16
Branches 531 540 +9
=======================================
+ Hits 3949 3965 +16
Misses 23 23
Partials 14 14
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
@glyph updated with a _Numeric protocol! I tried setting it as a bound on a TypeVar and using that for minimum, maximum, and kind, but mypy complains and I couldn't figure out how to make it happy:
diff --git a/src/klein/_form.py b/src/klein/_form.py
index da93a33..04de050 100644
--- a/src/klein/_form.py
+++ b/src/klein/_form.py
@@ -56,6 +56,9 @@ class _Numeric(Protocol[_T]):
...
+_N = TypeVar("_N", bound=_Numeric)
+
+
class CrossSiteRequestForgery(Resource):
"""
Cross site request forgery detected. Request aborted.
@@ -273,9 +276,9 @@ class Field:
@classmethod
def number(
cls,
- minimum: Optional[_Numeric] = None,
- maximum: Optional[_Numeric] = None,
- kind: Callable[[str], _Numeric] = float,
+ minimum: Optional[_N] = None,
+ maximum: Optional[_N] = None,
+ kind: Callable[[str], _N] = float,
**kw: Any,
) -> "Field":
"""
src/klein/_form.py:281:37: error: Incompatible default for argument "kind" (default has type "type[float]", argument has type
"Callable[[str], _N]") [assignment]
kind: Callable[[str], _N] = float,
^~~~~
Found 1 error in 1 file (checked 50 source files)
@rouge8 to try to better explain the structure I was looking for, I opened a PR against your PR: https://github.com/rouge8/klein/pull/1 . Numerics aren't generic, because a numeric has to work with itself and (in this context, at least) only itself.
The goofy verbose @overload is just due to the fact that mypy can't understand the influence of default parameters on type signatures, i.e. https://github.com/python/mypy/issues/3737 .
Re: the coverage failure, I don't really have time to look at it now, but there should be a coverage ignore pattern you can grab for ... in protocols somewhere, in some twisted project, that should be applied to this so it's not getting dinged for not covering protocol implementations :)
Ohhh, thanks for the fix! I'll add the coverage ignore tomorrow during the workday.