From 37cd5036fe5d0497b3f5b7aa0017a7f4433a1b81 Mon Sep 17 00:00:00 2001 From: JHM Darbyshire <24256554+attack68@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:19:22 +0100 Subject: [PATCH] TYP: make /calendars mypy compliant --strict (#525) --- python/rateslib/calendars/rs.py | 77 +++++++++++++++----------------- python/rateslib/curves/curves.py | 4 +- python/rateslib/default.py | 4 +- 3 files changed, 39 insertions(+), 46 deletions(-) diff --git a/python/rateslib/calendars/rs.py b/python/rateslib/calendars/rs.py index fad7cab1..979ee77c 100644 --- a/python/rateslib/calendars/rs.py +++ b/python/rateslib/calendars/rs.py @@ -125,15 +125,14 @@ def get_calendar( tgt_and_nyc_cal.holidays[300:312] """ - _: CalTypes = _get_calendar(calendar=calendar, kind=False, named=named) + _: CalTypes = _get_calendar_with_kind(calendar=calendar, named=named)[0] return _ -def _get_calendar( +def _get_calendar_with_kind( calendar: CalInput, - kind: bool = False, named: bool = True, -) -> Union[CalTypes, tuple[CalTypes, str]]: +) -> tuple[CalTypes, str]: """ Returns a calendar object either from an available set or a user defined input. @@ -142,9 +141,6 @@ def _get_calendar( calendar : str, Cal, UnionCal, NamedCal If `str`, then the calendar is returned from pre-calculated values. If a specific user defined calendar this is returned without modification. - kind : bool - If `True` will also return the kind of calculation from `"null", "named", - "custom"`. named : bool If `True` will return a :class:`~rateslib.calendars.NamedCal` object, which is more compactly serialized, otherwise will parse an input string and return a @@ -152,44 +148,41 @@ def _get_calendar( Returns ------- - NamedCal, Cal, UnionCal or tuple + tuple[NamedCal | Cal | UnionCal, str] """ # TODO: rename calendars or make a more generalist statement about their names. - if isinstance(calendar, str) and named: - try: - return _get_calendar_labelled(NamedCal(calendar), "object", kind) - except ValueError: - named = False # try parsing with Python only - - if calendar is NoInput.blank: - return _get_calendar_labelled(defaults.calendars["all"], "null", kind) - elif isinstance(calendar, str) and not named: - # parse the string in Python and return Rust objects directly - vectors = calendar.split("|") - if len(vectors) == 1: - calendars = vectors[0].lower().split(",") - if len(calendars) == 1: # only one named calendar is found - return _get_calendar_labelled(defaults.calendars[calendars[0]], "named", kind) - else: - cals = [defaults.calendars[_] for _ in calendars] - return _get_calendar_labelled(UnionCal(cals, None), "named", kind) - elif len(vectors) == 2: - calendars = vectors[0].lower().split(",") - cals = [defaults.calendars[_] for _ in calendars] - settlement_calendars = vectors[1].lower().split(",") - sets = [defaults.calendars[_] for _ in settlement_calendars] - return _get_calendar_labelled(UnionCal(cals, sets), "named", kind) - else: - raise ValueError("Cannot use more than one pipe ('|') operator in `calendar`.") + # these object categorisations do not seem to make sense. + if isinstance(calendar, str): + if named: + try: + return NamedCal(calendar), "object" + except ValueError: + # try parsing with Python only + pass + # parse the string in Python and return Rust Cal/UnionCal objects directly + return _parse_str_calendar(calendar), "named" + elif isinstance(calendar, NoInput): + return defaults.calendars["all"], "null" else: # calendar is a Calendar object type - return _get_calendar_labelled(calendar, "custom", kind) + return calendar, "custom" -def _get_calendar_labelled( - output: CalTypes, label: str, kind: bool -) -> Union[CalTypes, tuple[CalTypes, str]]: - """Package the return for the get_calendar function""" - if kind: - return output, label - return output +def _parse_str_calendar(calendar: str) -> CalTypes: + """Parse the calendar string using Python and construct calendar objects.""" + vectors = calendar.split("|") + if len(vectors) == 1: + calendars = vectors[0].lower().split(",") + if len(calendars) == 1: # only one named calendar is found + return defaults.calendars[calendars[0]] + else: + cals = [defaults.calendars[_] for _ in calendars] + return UnionCal(cals, None) + elif len(vectors) == 2: + calendars = vectors[0].lower().split(",") + cals = [defaults.calendars[_] for _ in calendars] + settlement_calendars = vectors[1].lower().split(",") + sets = [defaults.calendars[_] for _ in settlement_calendars] + return UnionCal(cals, sets) + else: + raise ValueError("Cannot use more than one pipe ('|') operator in `calendar`.") diff --git a/python/rateslib/curves/curves.py b/python/rateslib/curves/curves.py index 72a32f86..32c5a35c 100644 --- a/python/rateslib/curves/curves.py +++ b/python/rateslib/curves/curves.py @@ -21,7 +21,7 @@ from rateslib import defaults from rateslib.calendars import CalInput, add_tenor, create_calendar, dcf from rateslib.calendars.dcfs import _DCF1d -from rateslib.calendars.rs import Modifier, _get_calendar +from rateslib.calendars.rs import Modifier, _get_calendar_with_kind from rateslib.default import NoInput, _drb, plot from rateslib.dual import Dual, Dual2, DualTypes, dual_exp, dual_log, set_order_convert from rateslib.rs import index_left_f64 @@ -324,7 +324,7 @@ def __init__( # Parameters for the rate derivation self.convention = defaults.convention if convention is NoInput.blank else convention self.modifier = defaults.modifier if modifier is NoInput.blank else modifier.upper() - self.calendar, self.calendar_type = _get_calendar(calendar, kind=True) + self.calendar, self.calendar_type = _get_calendar_with_kind(calendar) if self.calendar_type == "named": self.calendar_type = f"named: {calendar.lower()}" diff --git a/python/rateslib/default.py b/python/rateslib/default.py index 96da2b3f..b954c485 100644 --- a/python/rateslib/default.py +++ b/python/rateslib/default.py @@ -11,7 +11,7 @@ from pandas import read_csv from rateslib._spec_loader import INSTRUMENT_SPECS -from rateslib.rs import get_named_calendar +from rateslib.rs import Cal, NamedCal, UnionCal, get_named_calendar # Licence: Creative Commons - Attribution-NonCommercial-NoDerivatives 4.0 International # Commercial use of this code, and/or copying and redistribution is prohibited. @@ -103,7 +103,7 @@ def __init__(self): self.stub_length = "SHORT" self.eval_mode = "swaps_align" self.modifier = "MF" - self.calendars = { + self.calendars: dict[str, NamedCal | UnionCal | Cal] = { "all": get_named_calendar("all"), "bus": get_named_calendar("bus"), "tgt": get_named_calendar("tgt"),