From 32b4f0a1fcd5c564fa97ca335739b1a10ea9132a Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 20 May 2022 19:31:29 -0400 Subject: [PATCH 1/4] validate cache CI step --- .github/workflows/pytest.yml | 2 ++ Makefile | 3 +++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 7f0d35bb..da2abe25 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -31,6 +31,8 @@ jobs: - name: Timing test timeout-minutes: 2 run: python -m scripts.statcast_timing + - name: Cache test + run: make validate-cache - name: Run MyPy run: make mypy ONLY_MODIFIED=0 continue-on-error: true diff --git a/Makefile b/Makefile index 4a03a8b5..de479f68 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,9 @@ mypy: test: pytest $(TEST_RUN_AGAINST) $(TEST_FLAGS) --doctest-modules --cov=pybaseball --cov-report term-missing +validate-cache: install + python ./scripts/validate_cache.py + # The test-github-actions is here to allow any local developer to test the GitHub actions on their code # before pushing and creating a PR. Just install act from https://github.com/nektos/act and run # make test-github-actions From e22971c4e2a3e94c2194c9611183f8417d60bfa2 Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 20 May 2022 19:33:53 -0400 Subject: [PATCH 2/4] adds script --- scripts/validate_cache.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 scripts/validate_cache.py diff --git a/scripts/validate_cache.py b/scripts/validate_cache.py new file mode 100644 index 00000000..bde74f03 --- /dev/null +++ b/scripts/validate_cache.py @@ -0,0 +1,13 @@ + +import sys +import pybaseball + +if __name__ == "__main__": + season = 2020 + pybaseball.cache.enable() + batting = pybaseball.batting_stats(season) + pitching = pybaseball.pitching_stats(season) + columns_same = list(batting.columns) == list(pitching.columns) + shape_same = batting.shape == pitching.shape + cache_failed = columns_same and shape_same + sys.exit(int(cache_failed)) From 979cde08d04628410e012edfc2dd8dc545a117ad Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 20 May 2022 22:08:54 -0400 Subject: [PATCH 3/4] move cache dectorator to concrete class - this lets the class name be part of the function signature --- pybaseball/cache/func_utils.py | 5 ++++- pybaseball/datasources/fangraphs.py | 13 ++++++++++++- scripts/validate_cache.py | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/pybaseball/cache/func_utils.py b/pybaseball/cache/func_utils.py index 2f122790..10500a34 100644 --- a/pybaseball/cache/func_utils.py +++ b/pybaseball/cache/func_utils.py @@ -9,5 +9,8 @@ def get_func_name(func: Callable) -> str: if '__self__' in dir(func): # This is a class method return f"{func.__getattribute__('__self__').__class__.__name__}.{func.__name__}" + # it's a method of an instantiated object + elif "__qualname__" in dir(func): + return func.__qualname__ - return f"{func.__name__}" + return func.__name__ diff --git a/pybaseball/datasources/fangraphs.py b/pybaseball/datasources/fangraphs.py index 69d0e6fb..8a318023 100644 --- a/pybaseball/datasources/fangraphs.py +++ b/pybaseball/datasources/fangraphs.py @@ -73,7 +73,6 @@ def _sort(self, data: pd.DataFrame, columns: List[str], ascending: bool = True) def _validate(self, data: pd.DataFrame) -> pd.DataFrame: return data - @cache.df_cache() def fetch(self, start_season: int, end_season: Optional[int] = None, league: str = 'ALL', ind: int = 1, stat_columns: Union[str, List[str]] = 'ALL', qual: Optional[int] = None, split_seasons: bool = True, month: str = 'ALL', on_active_roster: bool = False, minimum_age: int = MIN_AGE, @@ -172,6 +171,10 @@ class FangraphsBattingStatsTable(FangraphsDataTable): ROW_ID_FUNC: RowIdFunction = player_row_id_func ROW_ID_NAME = 'IDfg' + @cache.df_cache() + def fetch(self, *args, **kwargs): + return super().fetch(*args, **kwargs) + def _postprocess(self, data: pd.DataFrame) -> pd.DataFrame: return self._sort(data, ["WAR", "OPS"], ascending=False) @@ -182,6 +185,10 @@ class FangraphsFieldingStatsTable(FangraphsDataTable): ROW_ID_FUNC: RowIdFunction = player_row_id_func ROW_ID_NAME = 'IDfg' + @cache.df_cache() + def fetch(self, *args, **kwargs): + return super().fetch(*args, **kwargs) + def _postprocess(self, data: pd.DataFrame) -> pd.DataFrame: return self._sort(data, ["DEF"], ascending=False) @@ -191,6 +198,10 @@ class FangraphsPitchingStatsTable(FangraphsDataTable): ROW_ID_FUNC: RowIdFunction = player_row_id_func ROW_ID_NAME = 'IDfg' + @cache.df_cache() + def fetch(self, *args, **kwargs): + return super().fetch(*args, **kwargs) + def _postprocess(self, data: pd.DataFrame) -> pd.DataFrame: if "WAR" in data.columns: new_position = min(7, len(data.columns) - 1) diff --git a/scripts/validate_cache.py b/scripts/validate_cache.py index bde74f03..3e8d45d5 100644 --- a/scripts/validate_cache.py +++ b/scripts/validate_cache.py @@ -1,6 +1,7 @@ import sys import pybaseball +import pandas as pd if __name__ == "__main__": season = 2020 From e3f44db28ac126386a4c2caa7e93c161a0025d25 Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 20 May 2022 22:34:44 -0400 Subject: [PATCH 4/4] qualname if not local --- pybaseball/cache/func_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pybaseball/cache/func_utils.py b/pybaseball/cache/func_utils.py index 10500a34..bcff0d85 100644 --- a/pybaseball/cache/func_utils.py +++ b/pybaseball/cache/func_utils.py @@ -10,7 +10,7 @@ def get_func_name(func: Callable) -> str: # This is a class method return f"{func.__getattribute__('__self__').__class__.__name__}.{func.__name__}" # it's a method of an instantiated object - elif "__qualname__" in dir(func): + elif "__qualname__" in dir(func) and r'' not in func.__qualname__: return func.__qualname__ return func.__name__