ghost-tdf-predictor 0.6.0__tar.gz
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.
- ghost_tdf_predictor-0.6.0/.cz.yaml +64 -0
- ghost_tdf_predictor-0.6.0/.env.example +10 -0
- ghost_tdf_predictor-0.6.0/.gitea/CODEOWNERS.md +1 -0
- ghost_tdf_predictor-0.6.0/.gitea/PULL_REQUEST_TEMPLATE.md +30 -0
- ghost_tdf_predictor-0.6.0/.gitea/workflows/pages.yml +59 -0
- ghost_tdf_predictor-0.6.0/.gitea/workflows/release.yml +23 -0
- ghost_tdf_predictor-0.6.0/.gitea/workflows/test.yml +35 -0
- ghost_tdf_predictor-0.6.0/.gitignore +30 -0
- ghost_tdf_predictor-0.6.0/.pre-commit-config.yaml +58 -0
- ghost_tdf_predictor-0.6.0/.secrets.baseline +127 -0
- ghost_tdf_predictor-0.6.0/CHANGELOG.md +50 -0
- ghost_tdf_predictor-0.6.0/CODEOWNERS.md +1 -0
- ghost_tdf_predictor-0.6.0/CONTRIBUTING.md +60 -0
- ghost_tdf_predictor-0.6.0/LICENSE +21 -0
- ghost_tdf_predictor-0.6.0/PKG-INFO +112 -0
- ghost_tdf_predictor-0.6.0/README.md +51 -0
- ghost_tdf_predictor-0.6.0/bin/build.sh +20 -0
- ghost_tdf_predictor-0.6.0/bin/run_tests.sh +19 -0
- ghost_tdf_predictor-0.6.0/data/archetypes.json +4822 -0
- ghost_tdf_predictor-0.6.0/data/hand_picks.json +39 -0
- ghost_tdf_predictor-0.6.0/data/model.json +1 -0
- ghost_tdf_predictor-0.6.0/data/model_weights.json +77 -0
- ghost_tdf_predictor-0.6.0/data/raw/_skipped.json +14 -0
- ghost_tdf_predictor-0.6.0/data/raw/amstel-gold-race-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/amstel-gold-race-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/amstel-gold-race-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/amstel-gold-race-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/amstel-gold-race-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/amstel-gold-race-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/dauphine-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/dauphine-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/dauphine-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/dauphine-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/dauphine-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/dauphine-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/gent-wevelgem-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/gent-wevelgem-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/gent-wevelgem-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/gent-wevelgem-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/gent-wevelgem-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/gent-wevelgem-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/giro-d-italia-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/giro-d-italia-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/giro-d-italia-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/giro-d-italia-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/giro-d-italia-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/giro-d-italia-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/il-lombardia-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/il-lombardia-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/il-lombardia-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/il-lombardia-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/il-lombardia-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/itzulia-basque-country-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/itzulia-basque-country-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/itzulia-basque-country-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/itzulia-basque-country-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/itzulia-basque-country-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/itzulia-basque-country-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/la-fleche-wallone-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/la-fleche-wallone-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/la-fleche-wallone-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/la-fleche-wallone-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/la-fleche-wallone-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/la-fleche-wallone-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/liege-bastogne-liege-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/liege-bastogne-liege-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/liege-bastogne-liege-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/liege-bastogne-liege-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/liege-bastogne-liege-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/liege-bastogne-liege-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/milano-sanremo-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/milano-sanremo-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/milano-sanremo-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/milano-sanremo-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/milano-sanremo-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/milano-sanremo-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/paris-nice-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/paris-nice-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/paris-nice-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/paris-nice-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/paris-nice-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/paris-nice-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/paris-roubaix-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/paris-roubaix-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/paris-roubaix-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/paris-roubaix-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/paris-roubaix-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/paris-roubaix-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/ronde-van-vlaanderen-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/ronde-van-vlaanderen-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/ronde-van-vlaanderen-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/ronde-van-vlaanderen-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/ronde-van-vlaanderen-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/ronde-van-vlaanderen-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stage_favourites_2026.json +27 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage01.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage02.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage03.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage04.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage05.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage06.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage07.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage08.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage09.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage10.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage12.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage13.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage14.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage15.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage16.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage17.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage18.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage19.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage20.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage21.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage01.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage02.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage03.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage04.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage05.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage06.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage07.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage08.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage09.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage10.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage11.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage12.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage13.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage14.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage15.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage16.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage17.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage18.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage19.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage20.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage21.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage01.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage02.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage03.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage04.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage05.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage06.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage07.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage08.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage09.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage10.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage11.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage12.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage13.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage14.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage15.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage16.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage17.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage18.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage19.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage20.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage21.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage01.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage02.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage03.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage04.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage05.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage06.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage07.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage08.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage09.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage10.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage11.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage12.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage13.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage14.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage15.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage16.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage17.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage18.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage19.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage20.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage21.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage01.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage02.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage03.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage04.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage05.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage06.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage07.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage08.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage09.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage10.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage11.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage12.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage13.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage14.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage15.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage16.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage17.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage18.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage19.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage20.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage21.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2026-stage01.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/strade-bianche-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/strade-bianche-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/strade-bianche-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/strade-bianche-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/strade-bianche-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/strade-bianche-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tdf2026_stages.json +216 -0
- ghost_tdf_predictor-0.6.0/data/raw/tdf_profiles.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tirreno-adriatico-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tirreno-adriatico-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tirreno-adriatico-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tirreno-adriatico-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tirreno-adriatico-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tirreno-adriatico-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tissot/stage-01.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tissot/stage-02.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-france-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-france-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-france-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-france-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-france-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-romandie-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-romandie-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-romandie-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-romandie-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-romandie-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-romandie-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-suisse-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-suisse-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-suisse-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-suisse-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-suisse-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/tour-de-suisse-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/volta-a-catalunya-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/volta-a-catalunya-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/volta-a-catalunya-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/volta-a-catalunya-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/volta-a-catalunya-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/volta-a-catalunya-2026.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/vuelta-a-espana-2021.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/vuelta-a-espana-2022.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/vuelta-a-espana-2023.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/vuelta-a-espana-2024.json +1 -0
- ghost_tdf_predictor-0.6.0/data/raw/vuelta-a-espana-2025.json +1 -0
- ghost_tdf_predictor-0.6.0/data/riders.csv +185 -0
- ghost_tdf_predictor-0.6.0/data/riders_raw.json +9954 -0
- ghost_tdf_predictor-0.6.0/data/tissot_scoring.json +45 -0
- ghost_tdf_predictor-0.6.0/docker-compose.yml +9 -0
- ghost_tdf_predictor-0.6.0/docs/SOURCES.md +34 -0
- ghost_tdf_predictor-0.6.0/docs/api.md +250 -0
- ghost_tdf_predictor-0.6.0/docs/index.md +5 -0
- ghost_tdf_predictor-0.6.0/docs/tissot_api.md +99 -0
- ghost_tdf_predictor-0.6.0/docs/usage.md +49 -0
- ghost_tdf_predictor-0.6.0/mkdocs.yml +43 -0
- ghost_tdf_predictor-0.6.0/pyproject.toml +129 -0
- ghost_tdf_predictor-0.6.0/src/tdf_predictor/__init__.py +3 -0
- ghost_tdf_predictor-0.6.0/src/tdf_predictor/db.py +85 -0
- ghost_tdf_predictor-0.6.0/src/tdf_predictor/fantasy.py +439 -0
- ghost_tdf_predictor-0.6.0/src/tdf_predictor/ingest.py +190 -0
- ghost_tdf_predictor-0.6.0/src/tdf_predictor/model.py +229 -0
- ghost_tdf_predictor-0.6.0/src/tdf_predictor/tissot.py +107 -0
- ghost_tdf_predictor-0.6.0/src/tdf_predictor/tissot_ingest.py +178 -0
- ghost_tdf_predictor-0.6.0/src/tdf_predictor/web.py +671 -0
- ghost_tdf_predictor-0.6.0/src/tdf_predictor/weights_fit.py +237 -0
- ghost_tdf_predictor-0.6.0/src/tissot_riders.py +135 -0
- ghost_tdf_predictor-0.6.0/tasks.py +37 -0
- ghost_tdf_predictor-0.6.0/tests/__init__.py +0 -0
- ghost_tdf_predictor-0.6.0/tests/test_db.py +59 -0
- ghost_tdf_predictor-0.6.0/tests/test_fantasy.py +189 -0
- ghost_tdf_predictor-0.6.0/tests/test_ingest.py +33 -0
- ghost_tdf_predictor-0.6.0/tests/test_model.py +68 -0
- ghost_tdf_predictor-0.6.0/tests/test_package.py +5 -0
- ghost_tdf_predictor-0.6.0/tests/test_tissot.py +103 -0
- ghost_tdf_predictor-0.6.0/tests/test_tissot_ingest.py +29 -0
- ghost_tdf_predictor-0.6.0/tests/test_web.py +270 -0
- ghost_tdf_predictor-0.6.0/uv.lock +1684 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
commitizen:
|
|
2
|
+
name: cz_customize
|
|
3
|
+
version_provider: uv
|
|
4
|
+
version_scheme: semver
|
|
5
|
+
major_version_zero: true
|
|
6
|
+
update_changelog_on_bump: true
|
|
7
|
+
tag_format: v$version
|
|
8
|
+
bump_message: ":ghost: chore: release v$current_version -> v$new_version [skip ci]"
|
|
9
|
+
|
|
10
|
+
customize:
|
|
11
|
+
bump_map:
|
|
12
|
+
Break: MAJOR
|
|
13
|
+
break: MAJOR
|
|
14
|
+
Feature: MINOR
|
|
15
|
+
feature: MINOR
|
|
16
|
+
Fix: PATCH
|
|
17
|
+
fix: PATCH
|
|
18
|
+
Bug: PATCH
|
|
19
|
+
bug: PATCH
|
|
20
|
+
|
|
21
|
+
bump_pattern: '(feature|fix|bug|break|Feature|Fix|Bug|Break)/[A-Z]{3}-\d{5}'
|
|
22
|
+
|
|
23
|
+
commit_parser: '.*?(?P<change_type>feature|fix|bug|break|Feature|Fix|Bug|Break)/[A-Z]{3}-\d{5}: (?P<message>.*)'
|
|
24
|
+
|
|
25
|
+
change_type_map:
|
|
26
|
+
Break: "Breaking Changes"
|
|
27
|
+
break: "Breaking Changes"
|
|
28
|
+
Feature: "Features"
|
|
29
|
+
feature: "Features"
|
|
30
|
+
Fix: "Bug Fixes"
|
|
31
|
+
fix: "Bug Fixes"
|
|
32
|
+
Bug: "Bug Fixes"
|
|
33
|
+
bug: "Bug Fixes"
|
|
34
|
+
|
|
35
|
+
change_type_order:
|
|
36
|
+
- break
|
|
37
|
+
- Break
|
|
38
|
+
- feature
|
|
39
|
+
- Feature
|
|
40
|
+
- fix
|
|
41
|
+
- Fix
|
|
42
|
+
- bug
|
|
43
|
+
- Bug
|
|
44
|
+
|
|
45
|
+
changelog_pattern: '.*(feature|fix|bug|break|Feature|Fix|Bug|Break)/[A-Z]{3}-\d{5}'
|
|
46
|
+
|
|
47
|
+
example: '👻 feature/TJP-00001: implement sovereign automation'
|
|
48
|
+
message_template: '{{change_type}}: {{message}}'
|
|
49
|
+
|
|
50
|
+
questions:
|
|
51
|
+
- name: change_type
|
|
52
|
+
type: list
|
|
53
|
+
message: Select the type of change you are committing
|
|
54
|
+
choices:
|
|
55
|
+
- {name: "break: A breaking change", value: break}
|
|
56
|
+
- {name: "feature: A new feature", value: feature}
|
|
57
|
+
- {name: "fix: A standard fix", value: fix}
|
|
58
|
+
- {name: "bug: A specific bug fix", value: bug}
|
|
59
|
+
- name: message
|
|
60
|
+
type: input
|
|
61
|
+
message: "Enter a brief description:"
|
|
62
|
+
|
|
63
|
+
schema: '<type>/<ticket>: <body>'
|
|
64
|
+
schema_pattern: '^.*(feature|fix|bug|break|Feature|Fix|Bug|Break)/[A-Z]{3}-\d{5}: (.*)'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @thomaspeoples
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# 👻 Ghost Stack Pull Request
|
|
2
|
+
|
|
3
|
+
## 🎯 Purpose
|
|
4
|
+
_What are we haunting today? Briefly describe the change._
|
|
5
|
+
|
|
6
|
+
**Fixes:** # (Link the Gitea Issue here)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 🛠️ Proposed Changes
|
|
11
|
+
- [ ] Logic updated in `src/`
|
|
12
|
+
- [ ] Dependencies synced via `uv lock`
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 🚦 Quality Gate (The Ghost Protocol)
|
|
17
|
+
- [ ] **uv Sync:** Environment is healthy and `uv.lock` is up to date.
|
|
18
|
+
- [ ] **Tests:** `./bin/run_tests.sh` passes with >80% coverage.
|
|
19
|
+
- [ ] **Linting:** `pre-commit run --all-files` passes.
|
|
20
|
+
- [ ] **Commits:** Messages follow the `cz_customize` regex (Fix/Feature/Break).
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🧪 Deployment & Verification
|
|
25
|
+
- [ ] Branch is synced with the latest `main`.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 👤 Author's Final Word
|
|
30
|
+
_Any specific notes for the reviewer or warnings about breaking changes?_
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: Deploy Gitea Pages
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
deploy:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- name: Install uv
|
|
15
|
+
uses: astral-sh/setup-uv@v3
|
|
16
|
+
with:
|
|
17
|
+
version: "latest"
|
|
18
|
+
|
|
19
|
+
- name: Install dependencies
|
|
20
|
+
run: uv sync --extra dev
|
|
21
|
+
|
|
22
|
+
- name: Run Tests & Coverage
|
|
23
|
+
run: uv run pytest --cov=src --cov-report=xml
|
|
24
|
+
|
|
25
|
+
- name: Generate Coverage Badge
|
|
26
|
+
run: uv run genbadge coverage -i coverage.xml -o docs/coverage.svg
|
|
27
|
+
|
|
28
|
+
- name: Build Documentation
|
|
29
|
+
run: uv run mkdocs build
|
|
30
|
+
|
|
31
|
+
- name: Sync to Main Website Repo
|
|
32
|
+
env:
|
|
33
|
+
MY_TOKEN: ${{ secrets.GITEATOKEN }}
|
|
34
|
+
MY_URL: ${{ secrets.GITEAURL }}
|
|
35
|
+
|
|
36
|
+
run: |
|
|
37
|
+
# 1. Clone your main website repo
|
|
38
|
+
CLEAN_URL=${MY_URL#*//}
|
|
39
|
+
git clone https://${MY_TOKEN}@${CLEAN_URL}/thomaspeoples/ghost-site.git main_site
|
|
40
|
+
|
|
41
|
+
# 2. Create the target directory if it doesn't exist
|
|
42
|
+
TARGET_DIR="main_site/www/gitea-repos/ghost-tdf-predictor"
|
|
43
|
+
mkdir -p $TARGET_DIR
|
|
44
|
+
|
|
45
|
+
# 3. Clean and Copy
|
|
46
|
+
rm -rf $TARGET_DIR/*
|
|
47
|
+
cp -r site/* $TARGET_DIR/
|
|
48
|
+
|
|
49
|
+
# 4. Commit and Push to the OTHER repo
|
|
50
|
+
cd main_site
|
|
51
|
+
git config user.name "Ghost Runner"
|
|
52
|
+
git config user.email "runner@ghost-stack.local"
|
|
53
|
+
git add .
|
|
54
|
+
if git diff --staged --quiet; then
|
|
55
|
+
echo "No changes to documentation. Skipping commit."
|
|
56
|
+
else
|
|
57
|
+
git commit -m ":books: main: Update docs for ghost-tdf-predictor: ${{ gitea.sha }}"
|
|
58
|
+
git push origin main
|
|
59
|
+
fi
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: 'Sovereign Release'
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
release:
|
|
10
|
+
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
|
11
|
+
runs-on: ghost-runner
|
|
12
|
+
steps:
|
|
13
|
+
- name: Check out code
|
|
14
|
+
uses: actions/checkout@v4
|
|
15
|
+
with:
|
|
16
|
+
fetch-depth: 0
|
|
17
|
+
token: ${{ secrets.GITEA_TOKEN }}
|
|
18
|
+
|
|
19
|
+
- name: Run Ghost Bump
|
|
20
|
+
uses: https://git.thomaspeoples.com/thomaspeoples/ci-actions/version-bump@main
|
|
21
|
+
with:
|
|
22
|
+
gitea_token: ${{ secrets.giteatoken }}
|
|
23
|
+
api_url: "${{ secrets.giteaurl }}/api/v1"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: TDF Predictor CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches-ignore:
|
|
6
|
+
- 'main'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test-and-verify:
|
|
10
|
+
runs-on: ghost-runner
|
|
11
|
+
steps:
|
|
12
|
+
- name: Check out code
|
|
13
|
+
uses: actions/checkout@v4
|
|
14
|
+
with:
|
|
15
|
+
fetch-depth: 0
|
|
16
|
+
- name: Install dependencies
|
|
17
|
+
run: uv sync --extra dev
|
|
18
|
+
- name: Run Tests
|
|
19
|
+
run: |
|
|
20
|
+
chmod +x bin/run_tests.sh
|
|
21
|
+
./bin/run_tests.sh
|
|
22
|
+
env:
|
|
23
|
+
PYTHONPATH: .
|
|
24
|
+
|
|
25
|
+
auto-merge:
|
|
26
|
+
needs: test-and-verify
|
|
27
|
+
if: github.ref != 'refs/heads/main'
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
- name: Call Central Merge Action
|
|
32
|
+
uses: https://git.thomaspeoples.com/thomaspeoples/ci-actions/auto-merge@main
|
|
33
|
+
with:
|
|
34
|
+
gitea_token: ${{ secrets.giteatoken }}
|
|
35
|
+
api_url: "${{ secrets.giteaurl }}/api/v1"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
.uv/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.so
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
.eggs/
|
|
9
|
+
htmlcov/
|
|
10
|
+
.coverage
|
|
11
|
+
.coverage.*
|
|
12
|
+
.cache
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.tox/
|
|
15
|
+
.venv
|
|
16
|
+
venv/
|
|
17
|
+
env/
|
|
18
|
+
ENV/
|
|
19
|
+
.env
|
|
20
|
+
.env.private
|
|
21
|
+
/site
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.ruff_cache/
|
|
24
|
+
*.db
|
|
25
|
+
*.sqlite3
|
|
26
|
+
src/debug/
|
|
27
|
+
|
|
28
|
+
# Claude Code
|
|
29
|
+
CLAUDE.md
|
|
30
|
+
.claude/
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
+
rev: v6.0.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: trailing-whitespace
|
|
6
|
+
- id: end-of-file-fixer
|
|
7
|
+
- id: check-yaml
|
|
8
|
+
exclude: mkdocs.yml
|
|
9
|
+
- id: check-toml
|
|
10
|
+
- id: check-json
|
|
11
|
+
- id: check-added-large-files
|
|
12
|
+
- id: check-merge-conflict
|
|
13
|
+
- id: check-case-conflict
|
|
14
|
+
- id: debug-statements
|
|
15
|
+
- id: check-executables-have-shebangs
|
|
16
|
+
- id: check-shebang-scripts-are-executable
|
|
17
|
+
|
|
18
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
19
|
+
rev: v0.15.20
|
|
20
|
+
hooks:
|
|
21
|
+
- id: ruff-check
|
|
22
|
+
args: [--fix]
|
|
23
|
+
- id: ruff-format
|
|
24
|
+
|
|
25
|
+
- repo: https://github.com/codespell-project/codespell
|
|
26
|
+
rev: v2.4.1
|
|
27
|
+
hooks:
|
|
28
|
+
- id: codespell
|
|
29
|
+
exclude: uv.lock|\.secrets\.baseline
|
|
30
|
+
# rider surnames are not typos (Paret-Peintre)
|
|
31
|
+
args: [-L, "paret"]
|
|
32
|
+
|
|
33
|
+
- repo: https://github.com/astral-sh/uv-pre-commit
|
|
34
|
+
rev: 0.11.26
|
|
35
|
+
hooks:
|
|
36
|
+
- id: uv-lock
|
|
37
|
+
|
|
38
|
+
- repo: https://github.com/Yelp/detect-secrets
|
|
39
|
+
rev: v1.5.0
|
|
40
|
+
hooks:
|
|
41
|
+
- id: detect-secrets
|
|
42
|
+
args: ['--baseline', '.secrets.baseline']
|
|
43
|
+
exclude: uv.lock
|
|
44
|
+
|
|
45
|
+
- repo: local
|
|
46
|
+
hooks:
|
|
47
|
+
- id: pytest-coverage
|
|
48
|
+
name: pytest-coverage
|
|
49
|
+
entry: ./bin/run_tests.sh
|
|
50
|
+
language: system
|
|
51
|
+
pass_filenames: false
|
|
52
|
+
always_run: true
|
|
53
|
+
|
|
54
|
+
- id: commitizen
|
|
55
|
+
name: commitizen check
|
|
56
|
+
entry: uv run cz check --commit-msg-file
|
|
57
|
+
language: system
|
|
58
|
+
stages: [commit-msg]
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.5.0",
|
|
3
|
+
"plugins_used": [
|
|
4
|
+
{
|
|
5
|
+
"name": "ArtifactoryDetector"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"name": "AWSKeyDetector"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "AzureStorageKeyDetector"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "Base64HighEntropyString",
|
|
15
|
+
"limit": 4.5
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "BasicAuthDetector"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "CloudantDetector"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "DiscordBotTokenDetector"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "GitHubTokenDetector"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "GitLabTokenDetector"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "HexHighEntropyString",
|
|
34
|
+
"limit": 3.0
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "IbmCloudIamDetector"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "IbmCosHmacDetector"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "IPPublicDetector"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "JwtTokenDetector"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "KeywordDetector",
|
|
50
|
+
"keyword_exclude": ""
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "MailchimpDetector"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "NpmDetector"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "OpenAIDetector"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"name": "PrivateKeyDetector"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"name": "PypiTokenDetector"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "SendGridDetector"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"name": "SlackDetector"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "SoftlayerDetector"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "SquareOAuthDetector"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"name": "StripeDetector"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "TelegramBotTokenDetector"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "TwilioKeyDetector"
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"filters_used": [
|
|
90
|
+
{
|
|
91
|
+
"path": "detect_secrets.filters.allowlist.is_line_allowlisted"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies",
|
|
95
|
+
"min_level": 2
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"path": "detect_secrets.filters.heuristic.is_indirect_reference"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"path": "detect_secrets.filters.heuristic.is_likely_id_string"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"path": "detect_secrets.filters.heuristic.is_lock_file"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"path": "detect_secrets.filters.heuristic.is_potential_uuid"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"path": "detect_secrets.filters.heuristic.is_sequential_string"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"path": "detect_secrets.filters.heuristic.is_swagger_file"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"path": "detect_secrets.filters.heuristic.is_templated_secret"
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
"results": {},
|
|
126
|
+
"generated_at": "2026-07-02T12:34:25Z"
|
|
127
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. Generated by
|
|
4
|
+
commitizen on version bump.
|
|
5
|
+
|
|
6
|
+
## v0.6.0 (2026-07-05)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- Stage teams stay ex-ante on raced stages for pred-vs-actual grading' (#5) from feature/TJP-05071 into main
|
|
11
|
+
- Stage teams stay ex-ante on raced stages for pred-vs-actual grading
|
|
12
|
+
- Restore cloudscraper, procyclingstats needs it behind Cloudflare
|
|
13
|
+
- Empty hand picks, stage-2 riders stay model-driven
|
|
14
|
+
- Delete dead forest code, cloudscraper and sklearn extras per ponytail audit
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
- Breakaway hand picks, stage-2 actuals, same-day raced fix
|
|
19
|
+
- Blend prior-TDF into predictions, in-tour form updating with DNF zeroing, hand-pick overlay and display names
|
|
20
|
+
- Three weight schemes with overlay, per-stage knapsack teams, jersey predictions and client-side transfer planner
|
|
21
|
+
|
|
22
|
+
## v0.5.0 (2026-07-05)
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
- Updated model for actual fantasy scoring over ProCyclingStats points' (#4) from feature/TJP-04075 into main
|
|
27
|
+
- Updated model for actual fantasy scoring over ProCyclingStats points
|
|
28
|
+
|
|
29
|
+
## v0.4.0 (2026-07-04)
|
|
30
|
+
|
|
31
|
+
### Features
|
|
32
|
+
|
|
33
|
+
- Added random forest for some reason' (#3) from feature/TJP-04074 into main
|
|
34
|
+
- Added random forest for some reason
|
|
35
|
+
|
|
36
|
+
## v0.3.0 (2026-07-04)
|
|
37
|
+
|
|
38
|
+
### Features
|
|
39
|
+
|
|
40
|
+
- Full rider data.json output' (#2) from feature/TJP-04073 into main
|
|
41
|
+
- Full rider data.json output
|
|
42
|
+
|
|
43
|
+
## v0.2.0 (2026-07-04)
|
|
44
|
+
|
|
45
|
+
### Features
|
|
46
|
+
|
|
47
|
+
- Removed playwright from dev deps' (#1) from feature/TJP-04071 into main
|
|
48
|
+
- Removed playwright from dev deps
|
|
49
|
+
- Removed playwright from dev deps
|
|
50
|
+
- Initial commit
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @thomaspeoples
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Contributing to ghost-tdf-predictor
|
|
2
|
+
|
|
3
|
+
## Prerequisites
|
|
4
|
+
|
|
5
|
+
- Python 3.12+
|
|
6
|
+
- [`uv`](https://docs.astral.sh/uv/) for dependency management
|
|
7
|
+
|
|
8
|
+
## Setup
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
git clone https://git.thomaspeoples.com/thomaspeoples/ghost-tdf-predictor.git
|
|
12
|
+
cd ghost-tdf-predictor
|
|
13
|
+
uv run poe setup
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This syncs all dependencies and installs pre-commit hooks.
|
|
17
|
+
|
|
18
|
+
## Running tests
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
uv run poe test
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Coverage must stay above 80%. The suite runs without any external services.
|
|
25
|
+
|
|
26
|
+
## Code style
|
|
27
|
+
|
|
28
|
+
Ruff handles formatting and linting:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
uv run poe lint
|
|
32
|
+
uv run poe format
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Line length is 79 characters.
|
|
36
|
+
|
|
37
|
+
## Commits
|
|
38
|
+
|
|
39
|
+
Commits follow the Ghost Stack convention via commitizen:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
👻 <type>/<ticket>: <message>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uv run cz commit
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Do not bypass pre-commit hooks with `--no-verify`.
|
|
50
|
+
|
|
51
|
+
## Pull requests
|
|
52
|
+
|
|
53
|
+
- One concern per PR.
|
|
54
|
+
- Include or update tests for any behaviour change.
|
|
55
|
+
- Run the full pre-commit suite before opening: `uv run pre-commit run --all-files`.
|
|
56
|
+
|
|
57
|
+
## Reporting issues
|
|
58
|
+
|
|
59
|
+
Open a Gitea issue with the input data (anonymised if needed) and the exact
|
|
60
|
+
command you ran.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Thomas Peoples
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ghost-tdf-predictor
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Tour de France race outcome prediction for the Ghost Stack.
|
|
5
|
+
Project-URL: Homepage, https://git.thomaspeoples.com/thomaspeoples/ghost-tdf-predictor
|
|
6
|
+
Project-URL: Repository, https://git.thomaspeoples.com/thomaspeoples/ghost-tdf-predictor.git
|
|
7
|
+
Project-URL: Documentation, https://www.thomaspeoples.com/gitea-repos/ghost-tdf-predictor/
|
|
8
|
+
Project-URL: Issues, https://git.thomaspeoples.com/thomaspeoples/ghost-tdf-predictor/issues
|
|
9
|
+
Project-URL: Changelog, https://git.thomaspeoples.com/thomaspeoples/ghost-tdf-predictor/src/branch/main/CHANGELOG.md
|
|
10
|
+
Author-email: Thomas Peoples <hello@thomaspeoples.com>
|
|
11
|
+
License: MIT License
|
|
12
|
+
|
|
13
|
+
Copyright (c) 2026 Thomas Peoples
|
|
14
|
+
|
|
15
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
16
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
17
|
+
in the Software without restriction, including without limitation the rights
|
|
18
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
20
|
+
furnished to do so, subject to the following conditions:
|
|
21
|
+
|
|
22
|
+
The above copyright notice and this permission notice shall be included in all
|
|
23
|
+
copies or substantial portions of the Software.
|
|
24
|
+
|
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
30
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
31
|
+
SOFTWARE.
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Keywords: cycling,ghost-stack,prediction,tour-de-france
|
|
34
|
+
Classifier: Development Status :: 3 - Alpha
|
|
35
|
+
Classifier: Intended Audience :: Developers
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Programming Language :: Python :: 3
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
39
|
+
Requires-Python: >=3.12
|
|
40
|
+
Requires-Dist: cloudscraper>=1.2.71
|
|
41
|
+
Requires-Dist: procyclingstats>=0.2.8
|
|
42
|
+
Provides-Extra: dev
|
|
43
|
+
Requires-Dist: commitizen; extra == 'dev'
|
|
44
|
+
Requires-Dist: detect-secrets; extra == 'dev'
|
|
45
|
+
Requires-Dist: genbadge[coverage]>=1.1.1; extra == 'dev'
|
|
46
|
+
Requires-Dist: mkdocs; extra == 'dev'
|
|
47
|
+
Requires-Dist: mkdocs-material; extra == 'dev'
|
|
48
|
+
Requires-Dist: mkdocstrings[python]; extra == 'dev'
|
|
49
|
+
Requires-Dist: poethepoet; extra == 'dev'
|
|
50
|
+
Requires-Dist: pre-commit; extra == 'dev'
|
|
51
|
+
Requires-Dist: pydoc-markdown; extra == 'dev'
|
|
52
|
+
Requires-Dist: pymdown-extensions; extra == 'dev'
|
|
53
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
54
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
55
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
56
|
+
Requires-Dist: ty; extra == 'dev'
|
|
57
|
+
Requires-Dist: typer; extra == 'dev'
|
|
58
|
+
Provides-Extra: scrape
|
|
59
|
+
Requires-Dist: playwright>=1.40; extra == 'scrape'
|
|
60
|
+
Description-Content-Type: text/markdown
|
|
61
|
+
|
|
62
|
+
# ghost-tdf-predictor 🚴💨
|
|
63
|
+
|
|
64
|
+
Who cracks the top 10 in July? Six seasons of ProCyclingStats results,
|
|
65
|
+
a from-scratch model, and a Tissot fantasy team picked by exact
|
|
66
|
+
knapsack — all in pure Python. No torch, no sklearn, no 200 MB wheel
|
|
67
|
+
for a model with nine weights.
|
|
68
|
+
|
|
69
|
+
The 2026 hot take so far: Pogačar. Groundbreaking stuff.
|
|
70
|
+
|
|
71
|
+
## What it does
|
|
72
|
+
|
|
73
|
+
- **Scrapes** grand tours, one-week stage races, monuments and top
|
|
74
|
+
classics (men's elite, 2021–2026) into SQLite
|
|
75
|
+
- **Clusters** riders into archetypes with hand-rolled k-means
|
|
76
|
+
- **Predicts** top-10 finishes with class-weighted logistic regression
|
|
77
|
+
(test AUC ~0.89 — form really is everything in cycling)
|
|
78
|
+
- **Picks** a 10-rider, 120-star Tissot fantasy team via 0/1 knapsack
|
|
79
|
+
with cardinality, backtested leave-one-year-out against the
|
|
80
|
+
hindsight-optimal team
|
|
81
|
+
|
|
82
|
+
## Run it
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
uv run poe setup # once
|
|
86
|
+
uv run python -m tdf_predictor.ingest # scrape PCS -> data/raw/*.json
|
|
87
|
+
uv run python -m tdf_predictor.db # load -> data/races.db (SQLite)
|
|
88
|
+
uv run python -m tdf_predictor.model # archetypes + top-10 model
|
|
89
|
+
uv run python -m tdf_predictor.fantasy # backtest + 2026 team pick
|
|
90
|
+
docker compose up -d # browse the DB at :8080
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Outputs land in `data/`: `archetypes.json`, `model.json`, and a
|
|
94
|
+
printed team that will absolutely not win your league.
|
|
95
|
+
|
|
96
|
+
Where the data comes from (and how politely it's scraped):
|
|
97
|
+
[docs/SOURCES.md](docs/SOURCES.md).
|
|
98
|
+
|
|
99
|
+
## Hacking on it
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
uv run poe test # pytest, coverage >80% enforced
|
|
103
|
+
uv run poe tidy # ruff lint + format
|
|
104
|
+
uv run poe docs-serve # MkDocs on :8000
|
|
105
|
+
uv run cz commit # commits go through commitizen, no exceptions
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Full workflow in [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT — see [LICENSE](LICENSE).
|