From 06a4ce90fc9bb047cef4e70d8a429b69a6cfd181 Mon Sep 17 00:00:00 2001 From: Peter Schutt Date: Wed, 31 Jan 2024 11:04:46 +1000 Subject: [PATCH] BREAKING: kw onlyh args and overloads for `calculate_implied_probabilities` Makes all arguments other than `odds` kw only, this drastically reduces the number of required overloads to type the signature properly. ```py # still works calculate_implied_probabilities([2.0, 2.0]) calculate_implied_probabilities(odds=[2.0, 2.0]) calculate_implied_probabilities([2.0, 2.0], full_output=True) ## also any other combination of passing arguments as keyword args remains the same # patterns of passing any arg other than `odds` as positional breaks calculate_implied_probabilibies([2.0, 2.0], 1000) calculate_impolied_probabilities([2.0, 2.0], 1000, 1e-12, True) ``` This encourages clarity at the callsite and also helps from a library perspective as it is easier to add new kw only args to an api without breaking downstream. Adds overloads and tests for combination of input types and value of `full_output` flag. --- python/shin/__init__.py | 42 +++++++++++++++++++++++++++++++++++++++- typesafety/test_shin.yml | 32 ++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/python/shin/__init__.py b/python/shin/__init__.py index be5a11b..eb48318 100644 --- a/python/shin/__init__.py +++ b/python/shin/__init__.py @@ -2,7 +2,7 @@ from collections.abc import Mapping, Sequence from math import sqrt -from typing import Any +from typing import Any, Literal, overload from .shin import optimise as _optimise_rust @@ -31,8 +31,48 @@ def _optimise( return z, delta, iterations +# sequence input, full output False +@overload +def calculate_implied_probabilities( + odds: Sequence[float], + *, + max_iterations: int = ..., + convergence_threshold: float = ..., + full_output: Literal[False] = False, + force_python_optimiser: bool = ..., +) -> list[float]: + ... + + +# mapping, full output False +@overload +def calculate_implied_probabilities( + odds: Mapping[Any, float], + *, + max_iterations: int = ..., + convergence_threshold: float = ..., + full_output: Literal[False] = False, + force_python_optimiser: bool = ..., +) -> dict[Any, float]: + ... + + +# full output True +@overload +def calculate_implied_probabilities( + odds: Sequence[float] | Mapping[Any, float], + *, + max_iterations: int = ..., + convergence_threshold: float = ..., + full_output: Literal[True], + force_python_optimiser: bool = ..., +) -> dict[str, Any]: + ... + + def calculate_implied_probabilities( odds: Sequence[float] | Mapping[Any, float], + *, max_iterations: int = 1000, convergence_threshold: float = 1e-12, full_output: bool = False, diff --git a/typesafety/test_shin.yml b/typesafety/test_shin.yml index 00a3567..c993d2e 100644 --- a/typesafety/test_shin.yml +++ b/typesafety/test_shin.yml @@ -5,3 +5,35 @@ reveal_type(shin.optimise) out: | main:3: note: Revealed type is "def (inverse_odds: builtins.list[builtins.float], sum_inverse_odds: builtins.float, n: builtins.int, max_iterations: builtins.int =, convergence_threshold: builtins.float =) -> tuple[builtins.float, builtins.float, builtins.float]" + +- case: test_sequence_input_overload + main: | + import shin + + reveal_type(shin.calculate_implied_probabilities([3.0, 3.0, 3.0])) + out: | + main:3: note: Revealed type is "builtins.list[builtins.float]" + +- case: test_mapping_input_overload + main: | + import shin + + reveal_type(shin.calculate_implied_probabilities({1: 3.0, 2: 3.0, 3: 3.0})) + out: | + main:3: note: Revealed type is "builtins.dict[Any, builtins.float]" + +- case: test_sequence_input_full_output_overload + main: | + import shin + + reveal_type(shin.calculate_implied_probabilities([3.0, 3.0, 3.0], full_output=True)) + out: | + main:3: note: Revealed type is "builtins.dict[builtins.str, Any]" + +- case: test_mapping_input_full_output_overload + main: | + import shin + + reveal_type(shin.calculate_implied_probabilities({1: 3.0, 2: 3.0, 3: 3.0}, full_output=True)) + out: | + main:3: note: Revealed type is "builtins.dict[builtins.str, Any]"