Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `OPEN` category added to `AGB_genders` for use in 2026 classifications in
[#169](https://github.com/jatkinson1000/archeryutils/pull/169)
- Addition of regression tests for classifications and handicaps using syrupy for
snapshots in [#148](https://github.com/jatkinson1000/archeryutils/pull/148)
- Addition of strict_rounds and strict_distance arguments for classifications in
Expand All @@ -23,6 +25,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Workflows update to include Python 3.14 in [#148](https://github.com/jatkinson1000/archeryutils/pull/148)
- AGB age category enums dropped the `AGE_` prefix in [#159](https://github.com/jatkinson1000/archeryutils/pull/159).
Replaced by `OVER_50`, `ADULT`, `UNDER_18` etc.
- `AGB_genders` enum updated to add `OPEN`. `MALE` remains for backwards compatibility
and legacy classifications as an alias to `OPEN`. Implemented in
[#169](https://github.com/jatkinson1000/archeryutils/pull/169)
- Long Metric Gents and Ladies renamed to Long Metric (90m) and (70m) in line with
April 2026 changes to Archery GB Rules of Shooting in
[#169](https://github.com/jatkinson1000/archeryutils/pull/169)

### Fixes

Expand Down
16 changes: 8 additions & 8 deletions archeryutils/classifications/AGB_ages.json
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
{
"OVER_50" : {
"age_group" : "50+",
"male" : [70, 80],
"open" : [70, 80],
"female" : [60, 60],
"sighted" : [60, 60],
"unsighted" : [50, 50],
"step" : 1
},
"ADULT" : {
"age_group" : "Adult",
"male" : [90, 100],
"open" : [90, 100],
"female" : [70, 80],
"sighted" : [60, 60],
"unsighted" : [50, 50],
"step" : 0
},
"UNDER_21" : {
"age_group" : "Under 21",
"male" : [90, 100],
"open" : [90, 100],
"female" : [70, 80],
"sighted" : [60, 60],
"unsighted" : [50, 50],
"step" : 1
},
"UNDER_18" : {
"age_group" : "Under 18",
"male" : [70, 80],
"open" : [70, 80],
"female" : [60, 60],
"sighted" : [60, 60],
"unsighted" : [50, 50],
"step" : 2
},
"UNDER_16" : {
"age_group" : "Under 16",
"male" : [60, 60],
"open" : [60, 60],
"female" : [50, 50],
"sighted" : [50, 60],
"unsighted" : [40, 50],
"step" : 3
},
"UNDER_15" : {
"age_group" : "Under 15",
"male" : [50, 50],
"open" : [50, 50],
"female" : [50, 50],
"sighted" : [40, 60],
"unsighted" : [30, 50],
"step" : 4
},
"UNDER_14" : {
"age_group" : "Under 14",
"male" : [40, 40],
"open" : [40, 40],
"female" : [40, 40],
"sighted" : [30, 60],
"unsighted" : [30, 50],
"step" : 5
},
"UNDER_12" : {
"age_group" : "Under 12",
"male" : [30, 30],
"open" : [30, 30],
"female" : [30, 30],
"sighted" : [30, 60],
"unsighted" : [30, 50],
Expand Down
10 changes: 8 additions & 2 deletions archeryutils/classifications/AGB_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@


class AGB_genders(Enum):
"""An enum for holding information about AGB genders."""
"""
An enum for holding information about AGB genders.

The Open category is equivalent to Male for scores following 2025 rule changes.
Scores remain the same, only branding has changed.
"""

MALE = auto()
OPEN = auto()
MALE = OPEN
FEMALE = auto()


Expand Down
2 changes: 1 addition & 1 deletion archeryutils/classifications/AGB_genders.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"genders" : ["Male", "Female"]}
{"genders" : ["Male", "Female", "Open"]}
6 changes: 3 additions & 3 deletions archeryutils/classifications/agb_field_classifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ def calculate_agb_field_classification( # noqa: PLR0913 Too many arguments
... 177,
... wa_field.wa_field_24_blue_marked,
... cf.AGB_bowstyles.TRADITIONAL,
... cf.AGB_genders.MALE,
... cf.AGB_genders.OPEN,
... cf.AGB_ages.UNDER_18,
... )
'B1'
Expand Down Expand Up @@ -507,7 +507,7 @@ def agb_field_classification_scores(
>>> cf.agb_field_classification_scores(
... wa_field.wa_field_24_red_marked,
... cf.AGB_bowstyles.COMPOUND,
... cf.AGB_genders.MALE,
... cf.AGB_genders.OPEN,
... cf.AGB_ages.ADULT,
... )
[408, 391, 369, 345, 318, 286, 248, 204, 157]
Expand All @@ -517,7 +517,7 @@ def agb_field_classification_scores(
>>> cf.agb_field_classification_scores(
... wa_field.wa_field_12_red_unmarked,
... cf.AGB_bowstyles.COMPOUND,
... cf.AGB_genders.MALE,
... cf.AGB_genders.OPEN,
... cf.AGB_ages.ADULT,
... )
[-9999, -9999, -9999, 173, 159, 143, 124, 102, 79],
Expand Down
4 changes: 2 additions & 2 deletions archeryutils/classifications/agb_indoor_classifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ def calculate_agb_indoor_classification(
... 547,
... agb_indoor.wa18,
... cf.AGB_bowstyles.COMPOUND,
... cf.AGB_genders.MALE,
... cf.AGB_genders.OPEN,
... cf.AGB_ages.OVER_50,
... )
'I-B2'
Expand Down Expand Up @@ -415,7 +415,7 @@ def agb_indoor_classification_scores(
>>> cf.agb_indoor_classification_scores(
... agb_indoor.portsmouth,
... cf.AGB_bowstyles.BAREBOW,
... cf.AGB_genders.MALE,
... cf.AGB_genders.OPEN,
... cf.AGB_ages.UNDER_12,
... )
[411, 360, 301, 240, 183, 134, 95, 66]
Expand Down
10 changes: 5 additions & 5 deletions archeryutils/classifications/agb_outdoor_classifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def _make_agb_outdoor_classification_dict() -> dict[str, GroupData]:

# Get max dists for category from json file data
# Use metres as corresponding yards >= metric
gender_key = cast(Literal["male", "female"], gender.name.lower())
gender_key = cast(Literal["open", "female"], gender.name.lower())
max_dists = agb_age_data[age.name][gender_key]

# set step from datum based on age and gender steps required
Expand Down Expand Up @@ -279,9 +279,9 @@ def _assign_min_dist(
max_dist_index = dists.index(np.min(max_dists))

# Age group trickery:
# U15 males and younger step down for B2 and below to align with female scores/hcs
# U15 opens and younger step down for B2 and below to align with female scores/hcs
if (
gender is AGB_genders.MALE
gender is AGB_genders.OPEN
and age_group not in AGB_ages.UNDER_15 | AGB_ages.UNDER_14 | AGB_ages.UNDER_12
):
idxs = np.array([0, 0, 0, 0, 1, 2, 3, 4, 5])
Expand Down Expand Up @@ -393,8 +393,8 @@ def _assign_outdoor_prestige(
# Check rest for junior eligible shorter rounds
distance_check = distance_check + prestige_720[1:]

# Additional fix for Male 50+, U18, and U16 recurve/longbow
if gender is AGB_genders.MALE:
# Additional fix for Open 50+, U18, and U16 recurve/longbow
if gender is AGB_genders.OPEN:
if age in AGB_ages.OVER_50 | AGB_ages.UNDER_18:
prestige_rounds.append(prestige_720[1]) # 60m
elif age is AGB_ages.UNDER_16:
Expand Down
8 changes: 4 additions & 4 deletions archeryutils/classifications/classification_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class AGBAgeData(TypedDict):

desc: str
age_group: str
male: list[float]
open: list[float]
female: list[float]
sighted: list[float]
unsighted: list[float]
Expand Down Expand Up @@ -132,7 +132,7 @@ def read_bowstyles_json(

def read_genders_json(
genders_file: Path = Path(__file__).parent / "AGB_genders.json",
) -> list[Literal["Male", "Female"]]:
) -> list[Literal["Open", "Female"]]:
"""
Read AGB genders in from neighbouring json file to list of dict.

Expand Down Expand Up @@ -265,7 +265,7 @@ def get_age_gender_step(
"""
Calculate AGB indoor age and gender step for classification dictionaries.

Contains a tricky fiddle for aligning Male and Female under 15 scores and below,
Contains a tricky fiddle for aligning Open and Female under 15 scores and below,
and a necessary check to ensure that gender step doesnt overtake age step when
doing this.

Expand Down Expand Up @@ -300,7 +300,7 @@ def get_age_gender_step(
if gender is AGB_genders.FEMALE and age_cat <= under_16_int:
return gender_step + age_cat * age_step

# Default case for males, and females aged U15 or younger - apply only age steps
# Default case for open, and females aged U15 or younger - apply only age steps
return age_cat * age_step


Expand Down
8 changes: 4 additions & 4 deletions archeryutils/round_data_files/AGB_outdoor_metric.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,17 @@
},


{"name" : "Long Metric Gents",
"codename" : "long_metric_gents",
{"name" : "Long Metric (90m)",
"codename" : "long_metric_90",
"location" : "outdoor",
"body" : "AGB",
"family" : "metriclong",
"passes" : [{"n_arrows" : 36, "diameter" : 122, "scoring" : "10_zone", "distance" : 90, "dist_unit" : "metre"},
{"n_arrows" : 36, "diameter" : 122, "scoring" : "10_zone", "distance" : 70, "dist_unit" : "metre"}
]
},
{"name" : "Long Metric Ladies",
"codename" : "long_metric_ladies",
{"name" : "Long Metric (70m)",
"codename" : "long_metric_70",
"location" : "outdoor",
"body" : "AGB",
"family" : "metriclong",
Expand Down
8 changes: 4 additions & 4 deletions docs/getting-started/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,11 @@ Given a score we can calculate the classification it achieves:
965,
agb_outdoor_imperial.hereford,
AGB_bowstyles.RECURVE,
AGB_genders.MALE,
AGB_genders.OPEN,
AGB_ages.OVER_50,
)
print(
f"A score of 965 on a Hereford is class {class_from_score} for a 50+ male recurve."
f"A score of 965 on a Hereford is class {class_from_score} for a 50+ open recurve."
)

# AGB Indoor
Expand All @@ -330,7 +330,7 @@ Given a score we can calculate the classification it achieves:
AGB_ages.ADULT,
)
print(
f"A score of 168 on a WA Unmarked 24 is class {class_from_score} for an under 18 male traditional."
f"A score of 168 on a WA Unmarked 24 is class {class_from_score} for an under adult female traditional."
)

Or, given a round we can output the scores required for each classification band:
Expand All @@ -341,7 +341,7 @@ Or, given a round we can output the scores required for each classification band
class_scores = cf.agb_outdoor_classification_scores(
agb_outdoor_imperial.hereford,
AGB_bowstyles.RECURVE,
AGB_genders.MALE,
AGB_genders.OPEN,
AGB_ages.ADULT,
)
print(class_scores)
Expand Down
10 changes: 5 additions & 5 deletions examples.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -737,11 +737,11 @@
" 965,\n",
" agb_outdoor_imperial.hereford,\n",
" AGB_bowstyles.RECURVE,\n",
" AGB_genders.MALE,\n",
" AGB_genders.OPEN,\n",
" AGB_ages.OVER_50,\n",
")\n",
"print(\n",
" f\"A score of 965 on a Hereford is class {class_from_score} for a 50+ male recurve.\"\n",
" f\"A score of 965 on a Hereford is class {class_from_score} for a 50+ open recurve.\"\n",
")"
]
},
Expand Down Expand Up @@ -784,11 +784,11 @@
" 168,\n",
" wa_field.wa_field_24_blue_unmarked,\n",
" AGB_bowstyles.TRADITIONAL,\n",
" AGB_genders.MALE,\n",
" AGB_genders.OPEN,\n",
" AGB_ages.UNDER_18,\n",
")\n",
"print(\n",
" f\"A score of 168 on a WA Unmarked 24 is class {class_from_score} for an under 18 male traditional.\"\n",
" f\"A score of 168 on a WA Unmarked 24 is class {class_from_score} for an under 18 open traditional.\"\n",
")"
]
},
Expand Down Expand Up @@ -816,7 +816,7 @@
"class_scores = cf.agb_outdoor_classification_scores(\n",
" agb_outdoor_imperial.hereford,\n",
" AGB_bowstyles.RECURVE,\n",
" AGB_genders.MALE,\n",
" AGB_genders.OPEN,\n",
" AGB_ages.ADULT,\n",
")\n",
"print(class_scores)"
Expand Down
Loading
Loading