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 diff --git a/pybaseball/cache/func_utils.py b/pybaseball/cache/func_utils.py index 2f122790..bcff0d85 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) and r'' not in func.__qualname__: + 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 new file mode 100644 index 00000000..3e8d45d5 --- /dev/null +++ b/scripts/validate_cache.py @@ -0,0 +1,14 @@ + +import sys +import pybaseball +import pandas as pd + +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))