spforge 0.8.31__py3-none-any.whl → 0.8.33__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of spforge might be problematic. Click here for more details.

@@ -595,7 +595,7 @@ class PlayerRatingGenerator(RatingGenerator):
595
595
  * float(pre_player.match_performance.participation_weight)
596
596
  )
597
597
 
598
- if team1_def_perf is None:
598
+ if team1_def_perf is None or (not self.use_off_def_split and perf_value is None):
599
599
  def_change = 0.0
600
600
  else:
601
601
  def_perf = float(team1_def_perf)
@@ -689,7 +689,7 @@ class PlayerRatingGenerator(RatingGenerator):
689
689
  * float(pre_player.match_performance.participation_weight)
690
690
  )
691
691
 
692
- if team2_def_perf is None:
692
+ if team2_def_perf is None or (not self.use_off_def_split and perf_value is None):
693
693
  def_change = 0.0
694
694
  else:
695
695
  def_perf = float(team2_def_perf)
spforge/scorer/_score.py CHANGED
@@ -388,16 +388,14 @@ class BaseScorer(ABC):
388
388
  return re.sub(r'[^a-zA-Z0-9_]', '_', name)
389
389
 
390
390
  def _count_user_filters(self) -> int:
391
- """Count filters excluding auto-added validation filter."""
391
+ """Count filters excluding any filter on validation column."""
392
392
  if not self.filters:
393
393
  return 0
394
394
  if self.validation_column is None:
395
395
  return len(self.filters)
396
396
  count = 0
397
397
  for f in self.filters:
398
- if not (f.column_name == self.validation_column and
399
- f.operator == Operator.EQUALS and
400
- f.value == 1):
398
+ if f.column_name != self.validation_column:
401
399
  count += 1
402
400
  return count
403
401
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spforge
3
- Version: 0.8.31
3
+ Version: 0.8.33
4
4
  Summary: A flexible framework for generating features, ratings, and building machine learning or other models for training and inference on sports data.
5
5
  Author-email: Mathias Holmstrøm <mathiasholmstom@gmail.com>
6
6
  License: See LICENSE file
@@ -51,7 +51,7 @@ spforge/performance_transformers/_performance_manager.py,sha256=WmjmlMEnq7y75MiI
51
51
  spforge/performance_transformers/_performances_transformers.py,sha256=0lxuWjAfWBRXRgQsNJHjw3P-nlTtHBu4_bOVdoy7hq4,15536
52
52
  spforge/ratings/__init__.py,sha256=OZVH2Lo6END3n1X8qi4QcyAPlThIwAYwVKCiIuOQSQU,576
53
53
  spforge/ratings/_base.py,sha256=ne4BRrYFPqMirdFPVnyDN44wjFQwOQgWoUXu_59xgWE,14687
54
- spforge/ratings/_player_rating.py,sha256=Dx_X1gl8_D_k2PZhMc-zuZ6wvX_YPgXibIfflNwT14g,67053
54
+ spforge/ratings/_player_rating.py,sha256=Ii1HNz0tC25dxZy9B2b_ULZVNwExNvdyIGw_1gRIeko,67163
55
55
  spforge/ratings/_team_rating.py,sha256=3m90-R2zW0k5EHwjw-83Hacz91fGmxW1LQ8ZUGHlgt4,24970
56
56
  spforge/ratings/enums.py,sha256=s7z_RcZS6Nlgfa_6tasO8_IABZJwywexe7sep9DJBgo,1739
57
57
  spforge/ratings/league_identifier.py,sha256=_KDUKOwoNU6RNFKE5jju4eYFGVNGBdJsv5mhNvMakfc,6019
@@ -62,7 +62,7 @@ spforge/ratings/team_performance_predictor.py,sha256=ThQOmYQUqKBB46ONYHOMM2arXFH
62
62
  spforge/ratings/team_start_rating_generator.py,sha256=vK-_m8KwcHopchch_lKNHSGLiiNm5q9Lenm0d1cP_po,5110
63
63
  spforge/ratings/utils.py,sha256=_zFemqz2jJkH8rn2EZpDt8N6FELUmYp9qCnPzRtOIGU,4497
64
64
  spforge/scorer/__init__.py,sha256=wj8PCvYIl6742Xwmt86c3oy6iqE8Ss-OpwHud6kd9IY,256
65
- spforge/scorer/_score.py,sha256=rGbzTiiS0KVbsGgJ742JoLDEoK79LbgTTuas6XHSZpw,65370
65
+ spforge/scorer/_score.py,sha256=DOl3wlHH0IlQelQA5CaNAfVtJhc544ZO5l-1mEno7nA,65276
66
66
  spforge/transformers/__init__.py,sha256=IPCsMcsgBqG52d0ttATLCY4HvFCQZddExlLt74U-zuI,390
67
67
  spforge/transformers/_base.py,sha256=-smr_McQF9bYxM5-Agx6h7Xv_fhZzPfpAdQV-qK18bs,1134
68
68
  spforge/transformers/_net_over_predicted.py,sha256=5dC8pvA1DNO0yXPSgJSMGU8zAHi-maUELm7FqFQVo-U,2321
@@ -71,7 +71,7 @@ spforge/transformers/_other_transformer.py,sha256=w2a7Wnki3vJe4GAkSa4kealw0GILIo
71
71
  spforge/transformers/_predictor.py,sha256=2sE6gfVrilXzPVcBurSrtqHw33v2ljygQcEYXt9LhZc,3119
72
72
  spforge/transformers/_simple_transformer.py,sha256=zGUFNQYMeoDSa2CoQejQNiNmKCBN5amWTvyOchiUHj0,5660
73
73
  spforge/transformers/_team_ratio_predictor.py,sha256=g8_bR53Yyv0iNCtol1O9bgJSeZcIco_AfbQuUxQJkeY,6884
74
- spforge-0.8.31.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
74
+ spforge-0.8.33.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
75
75
  tests/test_autopipeline.py,sha256=7cNAn-nmGolfyfk3THh9IKcHZfRA-pLYC_xAyMg-No4,26863
76
76
  tests/test_autopipeline_context.py,sha256=IuRUY4IA6uMObvbl2pXSaXO2_tl3qX6wEbTZY0dkTMI,1240
77
77
  tests/test_feature_generator_pipeline.py,sha256=CK0zVL8PfTncy3RmG9i-YpgwjOIV7yJhV7Q44tbetI8,19020
@@ -94,21 +94,21 @@ tests/hyperparameter_tuning/test_estimator_tuner.py,sha256=iewME41d6LR2aQ0OtohGF
94
94
  tests/hyperparameter_tuning/test_rating_tuner.py,sha256=usjC2ioO_yWRjjNAlRTyMVYheOrCi0kKocmHQHdTmpM,18699
95
95
  tests/performance_transformers/test_performance_manager.py,sha256=gjuuV_hb27kCo_kUecPKG3Cbot2Gqis1W3kw2A4ovS4,10690
96
96
  tests/performance_transformers/test_performances_transformers.py,sha256=A-tGiCx7kXrj1cVj03Bc7prOeZ1_Ryz8YFx9uj3eK6w,11064
97
- tests/ratings/test_player_rating_generator.py,sha256=clakS4RZxTWbSrb3gQiIKg4UQLI-g-K_cdvfMgJR7uw,103176
97
+ tests/ratings/test_player_rating_generator.py,sha256=9iepzvjlAlye-CkrEX5GT6Pf4Bf4qi_uDwB6Wamo1JY,104641
98
98
  tests/ratings/test_player_rating_no_mutation.py,sha256=GzO3Hl__5K68DS3uRLefwnbcTJOvBM7cZqww4M21UZM,8493
99
99
  tests/ratings/test_ratings_property.py,sha256=ckyfGILXa4tfQvsgyXEzBDNr2DUmHwFRV13N60w66iE,6561
100
100
  tests/ratings/test_team_rating_generator.py,sha256=SqQcfckNmJJc99feCdnmkNYDape-p69e92Dp8Vzpu2w,101156
101
101
  tests/ratings/test_utils_scaled_weights.py,sha256=iHxe6ZDUB_I2B6HT0xTGqXBkl7gRlqVV0e_7Lwun5po,4988
102
102
  tests/scorer/test_score.py,sha256=rw3xJs6xqWVpalVMUQz557m2JYGR7PmhrsjfTex0b0c,79121
103
103
  tests/scorer/test_score_aggregation_granularity.py,sha256=O5TRlG9UE4NBpF0tL_ywZKDmkMIorwrxgTegQ75Tr7A,15871
104
- tests/scorer/test_scorer_name.py,sha256=puwlfy_tdtFUfcWdRqUNJcytSIDlbBnksFbqqXHgOBg,10347
104
+ tests/scorer/test_scorer_name.py,sha256=lijr8vuHkieVmu_m3zcZril7rG5ByIZ-vSJq5QJFIss,10862
105
105
  tests/transformers/test_estimator_transformer_context.py,sha256=5GOHbuWCWBMFwwOTJOuD4oNDsv-qDR0OxNZYGGuMdag,1819
106
106
  tests/transformers/test_net_over_predicted.py,sha256=vh7O1iRRPf4vcW9aLhOMAOyatfM5ZnLsQBKNAYsR3SU,3363
107
107
  tests/transformers/test_other_transformer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
108
108
  tests/transformers/test_predictor_transformer.py,sha256=N1aBYLjN3ldpYZLwjih_gTFYSMitrZu-PNK78W6RHaQ,6877
109
109
  tests/transformers/test_simple_transformer.py,sha256=wWR0qjLb_uS4HXrJgGdiqugOY1X7kwd1_OPS02IT2b8,4676
110
110
  tests/transformers/test_team_ratio_predictor.py,sha256=fOUP_JvNJi-3kom3ZOs1EdG0I6Z8hpLpYKNHu1eWtOw,8562
111
- spforge-0.8.31.dist-info/METADATA,sha256=6K4WvRIGPNqP4DLegmzk95oc7rJd8yS6nZQgCoLG_yc,20048
112
- spforge-0.8.31.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
113
- spforge-0.8.31.dist-info/top_level.txt,sha256=6UW2M5a7WKOeaAi900qQmRKNj5-HZzE8-eUD9Y9LTq0,23
114
- spforge-0.8.31.dist-info/RECORD,,
111
+ spforge-0.8.33.dist-info/METADATA,sha256=LH22MH7XYeFTROBWPYVVHWyYRSwMYGozGMCtaJdkLgg,20048
112
+ spforge-0.8.33.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
113
+ spforge-0.8.33.dist-info/top_level.txt,sha256=6UW2M5a7WKOeaAi900qQmRKNj5-HZzE8-eUD9Y9LTq0,23
114
+ spforge-0.8.33.dist-info/RECORD,,
@@ -2874,3 +2874,38 @@ def test_defense_participation_weight_backwards_compatibility(base_cn, library):
2874
2874
  assert result is not None
2875
2875
  assert len(gen._player_off_ratings) > 0
2876
2876
  assert len(gen._player_def_ratings) > 0
2877
+
2878
+
2879
+ def test_fit_transform_null_perf_with_use_off_def_split_false__no_crash(base_cn):
2880
+ """
2881
+ Regression test: null performance with use_off_def_split=False should not crash.
2882
+
2883
+ Bug: When use_off_def_split=False and a player has null performance:
2884
+ - Line 598 checks `if team1_def_perf is None` (team-level avg, not None if any played)
2885
+ - Line 605 does `def_perf = float(perf_value)` where perf_value is None
2886
+ - Crash: TypeError: float() argument must be a string or a number, not 'NoneType'
2887
+
2888
+ Fix: Check `if team1_def_perf is None or perf_value is None` to skip def update
2889
+ for players who didn't play (null performance means no rating update).
2890
+ """
2891
+ df = pl.DataFrame(
2892
+ {
2893
+ "pid": ["P1", "P2", "P3", "P4", "P1", "P2", "P3", "P4"],
2894
+ "tid": ["T1", "T1", "T2", "T2", "T1", "T1", "T2", "T2"],
2895
+ "mid": ["M1", "M1", "M1", "M1", "M2", "M2", "M2", "M2"],
2896
+ "dt": ["2024-01-01"] * 4 + ["2024-01-02"] * 4,
2897
+ "perf": [0.6, 0.4, 0.5, 0.5, None, 0.6, 0.5, 0.5], # P1 null in M2
2898
+ "pw": [1.0] * 8,
2899
+ }
2900
+ )
2901
+
2902
+ gen = PlayerRatingGenerator(
2903
+ performance_column="perf",
2904
+ column_names=base_cn,
2905
+ use_off_def_split=False, # This triggers the buggy code path
2906
+ )
2907
+
2908
+ # Should not crash - before fix this raises:
2909
+ # TypeError: float() argument must be a string or a number, not 'NoneType'
2910
+ result = gen.fit_transform(df)
2911
+ assert result is not None
@@ -123,6 +123,19 @@ class TestScorerNameProperty:
123
123
  # Validation filter auto-added but not counted
124
124
  assert scorer.name == "mean_bias_scorer_yards"
125
125
 
126
+ def test_any_filter_on_validation_column_excluded_from_name(self):
127
+ scorer = MeanBiasScorer(
128
+ target="yards",
129
+ pred_column="pred",
130
+ validation_column="is_valid",
131
+ filters=[
132
+ Filter("is_valid", 0, Operator.EQUALS),
133
+ Filter("minutes", 10, Operator.GREATER_THAN),
134
+ ]
135
+ )
136
+ # Any filter on validation column should be excluded, not just value=1
137
+ assert scorer.name == "mean_bias_scorer_yards_filters:1"
138
+
126
139
  def test_complex_configuration_all_components(self):
127
140
  scorer = MeanBiasScorer(
128
141
  target="yards",