Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update classifications to operate using enums #113

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

Conversation

jatkinson1000
Copy link
Owner

@jatkinson1000 jatkinson1000 commented Jan 11, 2025

This PR updates the classification routines to use enums (Flag) for age, bowstyle, and gender instead of strings.

This should partly address #112

By using Flag enums we restrict the format to a single type of input.
These are easier to handle, allowing a chunk of string handling code to be removed.
It also allows options to be made clear to the user, rather than having to guess or look at the function definitions in the source.

This is still WIP and some things I am not happy with:

  • What should the 50+ category be called in the ages enum?
    It cannot start with a number or contain a + which presents an issue around clarity.
    Currently I use P50 but I do not like this. I also don't want O50 for O/0 issues and because the category is "50 and over", not "over 50".
  • Currently I restrict the classification schemes to the precise ruling.
    By this I mean that where previously inappropriate ages or bowstyles would be coerced to something e.g. Flatbow becomes Barebow for target, this is no longer the case. This is why some tests are currently failing.
    Whilst I feel this is perhaps more "expected" behaviour - following the AGB rules - my external applications made use of this feature and will now need to handle this coercion themselves at a higher level.
    I am still unsure what the best thing to do here would be.

Other things to handle #112:

  • Make classification functions take a Round rather than a string.
  • Documentation
  • Sanity check of docstrings

Other Notes:

  • This is a breaking API change, so will be part of archeryutils v2.0.
  • Iteration over a Flag enum requires python >=3.11 which means we need to drop support for 3.10
    3.10 is in security phase and will not reach EoL until October 2026.
    This is resolved with aenum in older versions.

@jatkinson1000 jatkinson1000 self-assigned this Jan 11, 2025
@jatkinson1000 jatkinson1000 added the enhancement New feature or request label Jan 11, 2025
@jatkinson1000
Copy link
Owner Author

Quite nicely the aenum library allows us to continue supporting back to python 3.10.
It was eventually merged into python core in 3.11, with further additions in 3.12, but is needed here as an optional dependency for python <=3.12.

pyproject.toml allows us to specify dependencies based on python version, and we can check inline with sys.

See 72548cd

…tuitive naming, e.g. AGE_50_PLUS instead of P50. Also moves U18 to UNDER_18 etc. for consistency.
@jatkinson1000
Copy link
Owner Author

Update so that the AGB_ages enum has an AGE_ prefix to members.
This allows for a more intuitive AGE_50_PLUS etc.

Not the prettiest as it adds verbosity, duplicates 'age' (AGB_ages.AGE_ADULT) and inconsistency with bowstyle and gender enums, but my feeling is that this is the most elegant workaround - and if users get it wrong they will be nudged in the right direction.

Also moves junior age groups from U18 to AGE_UNDER_18

@jatkinson1000
Copy link
Owner Author

jatkinson1000 commented Jan 26, 2025

All test failures at this point are ValueErrors associated with disallowed bowstyles/ages being passed to classification schemes. e.g. there is no "flatbow" in indoor target.

A question here is whether to coax bowstyles into something that passes (as was previously the case) or make this a new error?

I am erring on making it a new error.
The AGB rules only cover specific ages/bowstyles for each scheme, and it is the responsibility of the archer/records officer/tournament organiser to move a bowstyle into the correct category e.g. "flatbow" becomes "barebow" in indoor target.
I say this because because under these circumstances the archer is not shooting as a "flatbow", but as a "barebow", albeit without maximal advantages of the rules.

I am open to thoughts/discussions on this, however, if you have opinions @TomHall2020, @mjtamlyn, or @LiamPattinson (or other users)?

@TomHall2020
Copy link
Contributor

Personally I'd like to be more forgiving, or at least have an option to. Perhaps a strict argument or option somehow that raises errors for invalid bowstyles/ages.

The use case for me upstream would be providing "unofficial" classifications. Ie show the user if their round was EMB standard, even if it wasn't an official round. Its then up to me and my UI to make it clear that it's not a real EMB score.

An alternative would be exposing separate functions for converting a handicap to a classification, and another for validating the classification against the round and category limitations.

Apologies I haven't been on this much, its all somehow gotten quite hectic recently

@jatkinson1000
Copy link
Owner Author

Note to self - could have functions coax_bowstyle(...) and coax_age(...) etc for each scheme to achieve this.

Options would be to:

  • embed these in the classification scheme itself
  • make them an optional preprocessing step for users - issue with this is how would they handle the returned options?
    • could perhaps return a dict that gets passed to classification function as **kwargs?

@jatkinson1000
Copy link
Owner Author

mypy is sad with itertools over a Flag enum, interpreting it as type object instead of the enum.
See comment on existing issue python/mypy#14977

No fix despite being open for 2 years.
Not clear what the best remedy for this is.

Captures invalid ages and bowstyles as inputs to classification calculations and coaxes them into a valid format based on ArcheryGB rules. Not applied by default in code but can be used by user to return a dict that can be unpacked directly into the classification functions. Also includes tests for this functionality.
…ll need updating to require next stable release version (suggested to be March 2025).
@jatkinson1000
Copy link
Owner Author

Mypy can be made less sad by installing directly from git which contains a bugfix for the Flag issue observed.
This should make it into a release around mid-March according to developers at which point it should updated in the pyproject.toml - if this is merged before that time an issue should be opened to follow up on this.

@TomHall2020 I have added a set of "coaxing" functions that can be used to turn an "invalid" group into a valid one as per the previous rules. The nice thing about how I wrote this is that it returns a dict that can be unpacked directly into the other classification functions to streamline usage.
I'm yet to complete the docs for this PR, but you can seen an example of this in use in the tests.

Copy link

codecov bot commented Feb 16, 2025

Codecov Report

Attention: Patch coverage is 88.84615% with 29 lines in your changes missing coverage. Please review.

Project coverage is 96.28%. Comparing base (6aa3e1d) to head (1d2704c).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...utils/classifications/agb_field_classifications.py 84.78% 7 Missing ⚠️
...tils/classifications/agb_indoor_classifications.py 81.57% 7 Missing ⚠️
...ils/classifications/agb_outdoor_classifications.py 84.78% 7 Missing ⚠️
.../classifications/agb_old_indoor_classifications.py 76.92% 6 Missing ⚠️
archeryutils/classifications/AGB_data.py 96.15% 1 Missing ⚠️
...s/classifications/agb_old_field_classifications.py 96.55% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #113      +/-   ##
==========================================
- Coverage   97.80%   96.28%   -1.53%     
==========================================
  Files          30       31       +1     
  Lines        1733     1911     +178     
==========================================
+ Hits         1695     1840     +145     
- Misses         38       71      +33     
Files with missing lines Coverage Δ
archeryutils/classifications/__init__.py 100.00% <100.00%> (ø)
...cheryutils/classifications/classification_utils.py 84.61% <100.00%> (-4.03%) ⬇️
...cheryutils/classifications/tests/test_agb_field.py 100.00% <100.00%> (ø)
...heryutils/classifications/tests/test_agb_indoor.py 100.00% <100.00%> (ø)
...yutils/classifications/tests/test_agb_old_field.py 100.00% <100.00%> (ø)
...utils/classifications/tests/test_agb_old_indoor.py 100.00% <100.00%> (ø)
...eryutils/classifications/tests/test_agb_outdoor.py 100.00% <100.00%> (ø)
...classifications/tests/test_classification_utils.py 100.00% <100.00%> (ø)
archeryutils/classifications/AGB_data.py 96.15% <96.15%> (ø)
...s/classifications/agb_old_field_classifications.py 98.41% <96.55%> (-1.59%) ⬇️
... and 4 more

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants