diff --git a/pyproject.toml b/pyproject.toml index 53dc692..04b0538 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "res-wind-up" -version = "0.4.5" +version = "0.4.6" authors = [ { name = "Alex Clerc", email = "alex.clerc@res-group.com" } ] diff --git a/tests/test_models.py b/tests/test_models.py index 4c84739..2f2ce06 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -170,3 +170,47 @@ def test_saves_as_expected( with fp.open() as f: data = json.load(f) WindUpConfig.model_validate(data) + + +class TestMatchingMonthsOverride: + """Tests date ranges of pre-upgrade period based on `WindUpConfig.from_yaml` config file loading.""" + + def test_without_pre_last_dt_utc_start(self) -> None: + """Checks default matching-months logic. + + Tests constructed pre-upgrade period when `pre_last_dt_utc_start` is not specified in the config file. + """ + cfg = WindUpConfig.from_yaml(TEST_CONFIG_DIR / "test_LSA_T13.yaml") + assert cfg.prepost.pre_first_dt_utc_start == pd.Timestamp("2020-09-30 00:00:00+0000", tz="UTC") + assert cfg.prepost.pre_last_dt_utc_start == pd.Timestamp("2021-07-20 23:50:00+0000", tz="UTC") + assert cfg.upgrade_first_dt_utc_start == pd.Timestamp("2021-09-30 00:00:00+0000", tz="UTC") + assert cfg.prepost.post_first_dt_utc_start == pd.Timestamp("2021-09-30 00:00:00+0000", tz="UTC") + assert cfg.prepost.post_last_dt_utc_start == pd.Timestamp("2022-07-20 23:50:00+0000", tz="UTC") + + def test_with_pre_last_dt_utc_start(self) -> None: + """Check that a pre-upgrade period (start and end date) may be specified explicitly in the config file. + + If a config file contains an entry for `pre_last_dt_utc_start`, this should override the default matching-months + logic. + """ + # Modify yaml file and then load it to ensure the override works as expected + yaml_path = TEST_CONFIG_DIR / "test_LSA_T13.yaml" + with yaml_path.open() as f: + yaml_str = f.read() + # Add a new line with "pre_last_dt_utc_start" value + new_line = "\npre_last_dt_utc_start: 2021-09-29 23:50:00+0000\n" + yaml_str += new_line + modified_yaml_path = TEST_CONFIG_DIR / "modified_test_LSA_T13.yaml" + with modified_yaml_path.open("w") as mf: + mf.write(yaml_str) + + cfg = WindUpConfig.from_yaml(modified_yaml_path) + + # delete the modified yaml file after loading the config + modified_yaml_path.unlink() + + assert cfg.prepost.pre_first_dt_utc_start == pd.Timestamp("2020-09-30 00:00:00+0000", tz="UTC") + assert cfg.prepost.pre_last_dt_utc_start == pd.Timestamp("2021-09-29 23:50:00+0000", tz="UTC") + assert cfg.upgrade_first_dt_utc_start == pd.Timestamp("2021-09-30 00:00:00+0000", tz="UTC") + assert cfg.prepost.post_first_dt_utc_start == pd.Timestamp("2021-09-30 00:00:00+0000", tz="UTC") + assert cfg.prepost.post_last_dt_utc_start == pd.Timestamp("2022-07-20 23:50:00+0000", tz="UTC") diff --git a/uv.lock b/uv.lock index 3c56752..3558166 100644 --- a/uv.lock +++ b/uv.lock @@ -1,4 +1,5 @@ version = 1 +revision = 1 requires-python = ">=3.9, <4.0" resolution-markers = [ "python_full_version >= '3.14'", @@ -3208,6 +3209,14 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/64/4a/36d8c966a0b086362ac10a7ee75978ed15c5f2dfdfc02a1578d19d3802fb/pydantic_core-2.41.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:170ee6835f6c71081d031ef1c3b4dc4a12b9efa6a9540f93f95b82f3c7571ae8", size = 2321830 }, { url = "https://files.pythonhosted.org/packages/a2/6e/d80cc4909dde5f6842861288aa1a7181e7afbfc50940c862ed2848df15bd/pydantic_core-2.41.4-cp39-cp39-win32.whl", hash = "sha256:3adf61415efa6ce977041ba9745183c0e1f637ca849773afa93833e04b163feb", size = 1976706 }, { url = "https://files.pythonhosted.org/packages/29/ee/5bda8d960d4a8b24a7eeb8a856efa9c865a7a6cab714ed387b29507dc278/pydantic_core-2.41.4-cp39-cp39-win_amd64.whl", hash = "sha256:a238dd3feee263eeaeb7dc44aea4ba1364682c4f9f9467e6af5596ba322c2332", size = 2027640 }, + { url = "https://files.pythonhosted.org/packages/b0/12/5ba58daa7f453454464f92b3ca7b9d7c657d8641c48e370c3ebc9a82dd78/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:a1b2cfec3879afb742a7b0bcfa53e4f22ba96571c9e54d6a3afe1052d17d843b", size = 2122139 }, + { url = "https://files.pythonhosted.org/packages/21/fb/6860126a77725c3108baecd10fd3d75fec25191d6381b6eb2ac660228eac/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:d175600d975b7c244af6eb9c9041f10059f20b8bbffec9e33fdd5ee3f67cdc42", size = 1936674 }, + { url = "https://files.pythonhosted.org/packages/de/be/57dcaa3ed595d81f8757e2b44a38240ac5d37628bce25fb20d02c7018776/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f184d657fa4947ae5ec9c47bd7e917730fa1cbb78195037e32dcbab50aca5ee", size = 1956398 }, + { url = "https://files.pythonhosted.org/packages/2f/1d/679a344fadb9695f1a6a294d739fbd21d71fa023286daeea8c0ed49e7c2b/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed810568aeffed3edc78910af32af911c835cc39ebbfacd1f0ab5dd53028e5c", size = 2138674 }, + { url = "https://files.pythonhosted.org/packages/c4/48/ae937e5a831b7c0dc646b2ef788c27cd003894882415300ed21927c21efa/pydantic_core-2.41.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:4f5d640aeebb438517150fdeec097739614421900e4a08db4a3ef38898798537", size = 2112087 }, + { url = "https://files.pythonhosted.org/packages/5e/db/6db8073e3d32dae017da7e0d16a9ecb897d0a4d92e00634916e486097961/pydantic_core-2.41.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:4a9ab037b71927babc6d9e7fc01aea9e66dc2a4a34dff06ef0724a4049629f94", size = 1920387 }, + { url = "https://files.pythonhosted.org/packages/0d/c1/dd3542d072fcc336030d66834872f0328727e3b8de289c662faa04aa270e/pydantic_core-2.41.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4dab9484ec605c3016df9ad4fd4f9a390bc5d816a3b10c6550f8424bb80b18c", size = 1951495 }, + { url = "https://files.pythonhosted.org/packages/2b/c6/db8d13a1f8ab3f1eb08c88bd00fd62d44311e3456d1e85c0e59e0a0376e7/pydantic_core-2.41.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8a5028425820731d8c6c098ab642d7b8b999758e24acae03ed38a66eca8335", size = 2139008 }, { url = "https://files.pythonhosted.org/packages/5d/d4/912e976a2dd0b49f31c98a060ca90b353f3b73ee3ea2fd0030412f6ac5ec/pydantic_core-2.41.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1e5ab4fc177dd41536b3c32b2ea11380dd3d4619a385860621478ac2d25ceb00", size = 2106739 }, { url = "https://files.pythonhosted.org/packages/71/f0/66ec5a626c81eba326072d6ee2b127f8c139543f1bf609b4842978d37833/pydantic_core-2.41.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:3d88d0054d3fa11ce936184896bed3c1c5441d6fa483b498fac6a5d0dd6f64a9", size = 1932549 }, { url = "https://files.pythonhosted.org/packages/c4/af/625626278ca801ea0a658c2dcf290dc9f21bb383098e99e7c6a029fccfc0/pydantic_core-2.41.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b2a054a8725f05b4b6503357e0ac1c4e8234ad3b0c2ac130d6ffc66f0e170e2", size = 2135093 }, @@ -3596,7 +3605,7 @@ wheels = [ [[package]] name = "res-wind-up" -version = "0.4.5" +version = "0.4.6" source = { editable = "." } dependencies = [ { name = "eval-type-backport" }, @@ -3681,6 +3690,7 @@ requires-dist = [ { name = "types-tqdm", marker = "extra == 'dev'" }, { name = "utm" }, ] +provides-extras = ["dev", "examples"] [[package]] name = "rfc3339-validator" diff --git a/wind_up/models.py b/wind_up/models.py index b408170..e630eb3 100644 --- a/wind_up/models.py +++ b/wind_up/models.py @@ -404,13 +404,20 @@ def from_yaml(cls, file_path: Path) -> "WindUpConfig": # noqa ANN102 if test_is_toggle: cfg_dct["analysis_first_dt_utc_start"] = cfg_dct["upgrade_first_dt_utc_start"] else: + if cfg_dct.get("pre_last_dt_utc_start") is not None: + pre_last_dt_utc_start = pd.to_datetime(cfg_dct.get("pre_last_dt_utc_start")) + else: + pre_last_dt_utc_start = pd.to_datetime( + cfg_dct["analysis_last_dt_utc_start"] - pd.DateOffset(years=cfg_dct["years_offset_for_pre_period"]) + ) + if pre_last_dt_utc_start.tzinfo is None: + pre_last_dt_utc_start = pre_last_dt_utc_start.tz_localize("UTC") pre_post_dict = { "post_first_dt_utc_start": cfg_dct["upgrade_first_dt_utc_start"], "post_last_dt_utc_start": cfg_dct["analysis_last_dt_utc_start"], "pre_first_dt_utc_start": cfg_dct["upgrade_first_dt_utc_start"] - pd.DateOffset(years=cfg_dct["years_offset_for_pre_period"]), - "pre_last_dt_utc_start": cfg_dct["analysis_last_dt_utc_start"] - - pd.DateOffset(years=cfg_dct["years_offset_for_pre_period"]), + "pre_last_dt_utc_start": pre_last_dt_utc_start, } cfg_dct["prepost"] = PrePost.model_validate(pre_post_dict) cfg_dct["analysis_first_dt_utc_start"] = cfg_dct["prepost"].pre_first_dt_utc_start