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.
Files changed (276) hide show
  1. ghost_tdf_predictor-0.6.0/.cz.yaml +64 -0
  2. ghost_tdf_predictor-0.6.0/.env.example +10 -0
  3. ghost_tdf_predictor-0.6.0/.gitea/CODEOWNERS.md +1 -0
  4. ghost_tdf_predictor-0.6.0/.gitea/PULL_REQUEST_TEMPLATE.md +30 -0
  5. ghost_tdf_predictor-0.6.0/.gitea/workflows/pages.yml +59 -0
  6. ghost_tdf_predictor-0.6.0/.gitea/workflows/release.yml +23 -0
  7. ghost_tdf_predictor-0.6.0/.gitea/workflows/test.yml +35 -0
  8. ghost_tdf_predictor-0.6.0/.gitignore +30 -0
  9. ghost_tdf_predictor-0.6.0/.pre-commit-config.yaml +58 -0
  10. ghost_tdf_predictor-0.6.0/.secrets.baseline +127 -0
  11. ghost_tdf_predictor-0.6.0/CHANGELOG.md +50 -0
  12. ghost_tdf_predictor-0.6.0/CODEOWNERS.md +1 -0
  13. ghost_tdf_predictor-0.6.0/CONTRIBUTING.md +60 -0
  14. ghost_tdf_predictor-0.6.0/LICENSE +21 -0
  15. ghost_tdf_predictor-0.6.0/PKG-INFO +112 -0
  16. ghost_tdf_predictor-0.6.0/README.md +51 -0
  17. ghost_tdf_predictor-0.6.0/bin/build.sh +20 -0
  18. ghost_tdf_predictor-0.6.0/bin/run_tests.sh +19 -0
  19. ghost_tdf_predictor-0.6.0/data/archetypes.json +4822 -0
  20. ghost_tdf_predictor-0.6.0/data/hand_picks.json +39 -0
  21. ghost_tdf_predictor-0.6.0/data/model.json +1 -0
  22. ghost_tdf_predictor-0.6.0/data/model_weights.json +77 -0
  23. ghost_tdf_predictor-0.6.0/data/raw/_skipped.json +14 -0
  24. ghost_tdf_predictor-0.6.0/data/raw/amstel-gold-race-2021.json +1 -0
  25. ghost_tdf_predictor-0.6.0/data/raw/amstel-gold-race-2022.json +1 -0
  26. ghost_tdf_predictor-0.6.0/data/raw/amstel-gold-race-2023.json +1 -0
  27. ghost_tdf_predictor-0.6.0/data/raw/amstel-gold-race-2024.json +1 -0
  28. ghost_tdf_predictor-0.6.0/data/raw/amstel-gold-race-2025.json +1 -0
  29. ghost_tdf_predictor-0.6.0/data/raw/amstel-gold-race-2026.json +1 -0
  30. ghost_tdf_predictor-0.6.0/data/raw/dauphine-2021.json +1 -0
  31. ghost_tdf_predictor-0.6.0/data/raw/dauphine-2022.json +1 -0
  32. ghost_tdf_predictor-0.6.0/data/raw/dauphine-2023.json +1 -0
  33. ghost_tdf_predictor-0.6.0/data/raw/dauphine-2024.json +1 -0
  34. ghost_tdf_predictor-0.6.0/data/raw/dauphine-2025.json +1 -0
  35. ghost_tdf_predictor-0.6.0/data/raw/dauphine-2026.json +1 -0
  36. ghost_tdf_predictor-0.6.0/data/raw/gent-wevelgem-2021.json +1 -0
  37. ghost_tdf_predictor-0.6.0/data/raw/gent-wevelgem-2022.json +1 -0
  38. ghost_tdf_predictor-0.6.0/data/raw/gent-wevelgem-2023.json +1 -0
  39. ghost_tdf_predictor-0.6.0/data/raw/gent-wevelgem-2024.json +1 -0
  40. ghost_tdf_predictor-0.6.0/data/raw/gent-wevelgem-2025.json +1 -0
  41. ghost_tdf_predictor-0.6.0/data/raw/gent-wevelgem-2026.json +1 -0
  42. ghost_tdf_predictor-0.6.0/data/raw/giro-d-italia-2021.json +1 -0
  43. ghost_tdf_predictor-0.6.0/data/raw/giro-d-italia-2022.json +1 -0
  44. ghost_tdf_predictor-0.6.0/data/raw/giro-d-italia-2023.json +1 -0
  45. ghost_tdf_predictor-0.6.0/data/raw/giro-d-italia-2024.json +1 -0
  46. ghost_tdf_predictor-0.6.0/data/raw/giro-d-italia-2025.json +1 -0
  47. ghost_tdf_predictor-0.6.0/data/raw/giro-d-italia-2026.json +1 -0
  48. ghost_tdf_predictor-0.6.0/data/raw/il-lombardia-2021.json +1 -0
  49. ghost_tdf_predictor-0.6.0/data/raw/il-lombardia-2022.json +1 -0
  50. ghost_tdf_predictor-0.6.0/data/raw/il-lombardia-2023.json +1 -0
  51. ghost_tdf_predictor-0.6.0/data/raw/il-lombardia-2024.json +1 -0
  52. ghost_tdf_predictor-0.6.0/data/raw/il-lombardia-2025.json +1 -0
  53. ghost_tdf_predictor-0.6.0/data/raw/itzulia-basque-country-2021.json +1 -0
  54. ghost_tdf_predictor-0.6.0/data/raw/itzulia-basque-country-2022.json +1 -0
  55. ghost_tdf_predictor-0.6.0/data/raw/itzulia-basque-country-2023.json +1 -0
  56. ghost_tdf_predictor-0.6.0/data/raw/itzulia-basque-country-2024.json +1 -0
  57. ghost_tdf_predictor-0.6.0/data/raw/itzulia-basque-country-2025.json +1 -0
  58. ghost_tdf_predictor-0.6.0/data/raw/itzulia-basque-country-2026.json +1 -0
  59. ghost_tdf_predictor-0.6.0/data/raw/la-fleche-wallone-2021.json +1 -0
  60. ghost_tdf_predictor-0.6.0/data/raw/la-fleche-wallone-2022.json +1 -0
  61. ghost_tdf_predictor-0.6.0/data/raw/la-fleche-wallone-2023.json +1 -0
  62. ghost_tdf_predictor-0.6.0/data/raw/la-fleche-wallone-2024.json +1 -0
  63. ghost_tdf_predictor-0.6.0/data/raw/la-fleche-wallone-2025.json +1 -0
  64. ghost_tdf_predictor-0.6.0/data/raw/la-fleche-wallone-2026.json +1 -0
  65. ghost_tdf_predictor-0.6.0/data/raw/liege-bastogne-liege-2021.json +1 -0
  66. ghost_tdf_predictor-0.6.0/data/raw/liege-bastogne-liege-2022.json +1 -0
  67. ghost_tdf_predictor-0.6.0/data/raw/liege-bastogne-liege-2023.json +1 -0
  68. ghost_tdf_predictor-0.6.0/data/raw/liege-bastogne-liege-2024.json +1 -0
  69. ghost_tdf_predictor-0.6.0/data/raw/liege-bastogne-liege-2025.json +1 -0
  70. ghost_tdf_predictor-0.6.0/data/raw/liege-bastogne-liege-2026.json +1 -0
  71. ghost_tdf_predictor-0.6.0/data/raw/milano-sanremo-2021.json +1 -0
  72. ghost_tdf_predictor-0.6.0/data/raw/milano-sanremo-2022.json +1 -0
  73. ghost_tdf_predictor-0.6.0/data/raw/milano-sanremo-2023.json +1 -0
  74. ghost_tdf_predictor-0.6.0/data/raw/milano-sanremo-2024.json +1 -0
  75. ghost_tdf_predictor-0.6.0/data/raw/milano-sanremo-2025.json +1 -0
  76. ghost_tdf_predictor-0.6.0/data/raw/milano-sanremo-2026.json +1 -0
  77. ghost_tdf_predictor-0.6.0/data/raw/paris-nice-2021.json +1 -0
  78. ghost_tdf_predictor-0.6.0/data/raw/paris-nice-2022.json +1 -0
  79. ghost_tdf_predictor-0.6.0/data/raw/paris-nice-2023.json +1 -0
  80. ghost_tdf_predictor-0.6.0/data/raw/paris-nice-2024.json +1 -0
  81. ghost_tdf_predictor-0.6.0/data/raw/paris-nice-2025.json +1 -0
  82. ghost_tdf_predictor-0.6.0/data/raw/paris-nice-2026.json +1 -0
  83. ghost_tdf_predictor-0.6.0/data/raw/paris-roubaix-2021.json +1 -0
  84. ghost_tdf_predictor-0.6.0/data/raw/paris-roubaix-2022.json +1 -0
  85. ghost_tdf_predictor-0.6.0/data/raw/paris-roubaix-2023.json +1 -0
  86. ghost_tdf_predictor-0.6.0/data/raw/paris-roubaix-2024.json +1 -0
  87. ghost_tdf_predictor-0.6.0/data/raw/paris-roubaix-2025.json +1 -0
  88. ghost_tdf_predictor-0.6.0/data/raw/paris-roubaix-2026.json +1 -0
  89. ghost_tdf_predictor-0.6.0/data/raw/ronde-van-vlaanderen-2021.json +1 -0
  90. ghost_tdf_predictor-0.6.0/data/raw/ronde-van-vlaanderen-2022.json +1 -0
  91. ghost_tdf_predictor-0.6.0/data/raw/ronde-van-vlaanderen-2023.json +1 -0
  92. ghost_tdf_predictor-0.6.0/data/raw/ronde-van-vlaanderen-2024.json +1 -0
  93. ghost_tdf_predictor-0.6.0/data/raw/ronde-van-vlaanderen-2025.json +1 -0
  94. ghost_tdf_predictor-0.6.0/data/raw/ronde-van-vlaanderen-2026.json +1 -0
  95. ghost_tdf_predictor-0.6.0/data/raw/stage_favourites_2026.json +27 -0
  96. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage01.json +1 -0
  97. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage02.json +1 -0
  98. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage03.json +1 -0
  99. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage04.json +1 -0
  100. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage05.json +1 -0
  101. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage06.json +1 -0
  102. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage07.json +1 -0
  103. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage08.json +1 -0
  104. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage09.json +1 -0
  105. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage10.json +1 -0
  106. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage12.json +1 -0
  107. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage13.json +1 -0
  108. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage14.json +1 -0
  109. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage15.json +1 -0
  110. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage16.json +1 -0
  111. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage17.json +1 -0
  112. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage18.json +1 -0
  113. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage19.json +1 -0
  114. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage20.json +1 -0
  115. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2021-stage21.json +1 -0
  116. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage01.json +1 -0
  117. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage02.json +1 -0
  118. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage03.json +1 -0
  119. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage04.json +1 -0
  120. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage05.json +1 -0
  121. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage06.json +1 -0
  122. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage07.json +1 -0
  123. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage08.json +1 -0
  124. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage09.json +1 -0
  125. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage10.json +1 -0
  126. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage11.json +1 -0
  127. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage12.json +1 -0
  128. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage13.json +1 -0
  129. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage14.json +1 -0
  130. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage15.json +1 -0
  131. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage16.json +1 -0
  132. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage17.json +1 -0
  133. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage18.json +1 -0
  134. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage19.json +1 -0
  135. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage20.json +1 -0
  136. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2022-stage21.json +1 -0
  137. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage01.json +1 -0
  138. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage02.json +1 -0
  139. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage03.json +1 -0
  140. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage04.json +1 -0
  141. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage05.json +1 -0
  142. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage06.json +1 -0
  143. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage07.json +1 -0
  144. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage08.json +1 -0
  145. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage09.json +1 -0
  146. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage10.json +1 -0
  147. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage11.json +1 -0
  148. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage12.json +1 -0
  149. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage13.json +1 -0
  150. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage14.json +1 -0
  151. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage15.json +1 -0
  152. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage16.json +1 -0
  153. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage17.json +1 -0
  154. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage18.json +1 -0
  155. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage19.json +1 -0
  156. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage20.json +1 -0
  157. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2023-stage21.json +1 -0
  158. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage01.json +1 -0
  159. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage02.json +1 -0
  160. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage03.json +1 -0
  161. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage04.json +1 -0
  162. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage05.json +1 -0
  163. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage06.json +1 -0
  164. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage07.json +1 -0
  165. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage08.json +1 -0
  166. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage09.json +1 -0
  167. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage10.json +1 -0
  168. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage11.json +1 -0
  169. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage12.json +1 -0
  170. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage13.json +1 -0
  171. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage14.json +1 -0
  172. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage15.json +1 -0
  173. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage16.json +1 -0
  174. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage17.json +1 -0
  175. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage18.json +1 -0
  176. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage19.json +1 -0
  177. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage20.json +1 -0
  178. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2024-stage21.json +1 -0
  179. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage01.json +1 -0
  180. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage02.json +1 -0
  181. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage03.json +1 -0
  182. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage04.json +1 -0
  183. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage05.json +1 -0
  184. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage06.json +1 -0
  185. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage07.json +1 -0
  186. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage08.json +1 -0
  187. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage09.json +1 -0
  188. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage10.json +1 -0
  189. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage11.json +1 -0
  190. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage12.json +1 -0
  191. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage13.json +1 -0
  192. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage14.json +1 -0
  193. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage15.json +1 -0
  194. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage16.json +1 -0
  195. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage17.json +1 -0
  196. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage18.json +1 -0
  197. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage19.json +1 -0
  198. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage20.json +1 -0
  199. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2025-stage21.json +1 -0
  200. ghost_tdf_predictor-0.6.0/data/raw/stages/tdf-2026-stage01.json +1 -0
  201. ghost_tdf_predictor-0.6.0/data/raw/strade-bianche-2021.json +1 -0
  202. ghost_tdf_predictor-0.6.0/data/raw/strade-bianche-2022.json +1 -0
  203. ghost_tdf_predictor-0.6.0/data/raw/strade-bianche-2023.json +1 -0
  204. ghost_tdf_predictor-0.6.0/data/raw/strade-bianche-2024.json +1 -0
  205. ghost_tdf_predictor-0.6.0/data/raw/strade-bianche-2025.json +1 -0
  206. ghost_tdf_predictor-0.6.0/data/raw/strade-bianche-2026.json +1 -0
  207. ghost_tdf_predictor-0.6.0/data/raw/tdf2026_stages.json +216 -0
  208. ghost_tdf_predictor-0.6.0/data/raw/tdf_profiles.json +1 -0
  209. ghost_tdf_predictor-0.6.0/data/raw/tirreno-adriatico-2021.json +1 -0
  210. ghost_tdf_predictor-0.6.0/data/raw/tirreno-adriatico-2022.json +1 -0
  211. ghost_tdf_predictor-0.6.0/data/raw/tirreno-adriatico-2023.json +1 -0
  212. ghost_tdf_predictor-0.6.0/data/raw/tirreno-adriatico-2024.json +1 -0
  213. ghost_tdf_predictor-0.6.0/data/raw/tirreno-adriatico-2025.json +1 -0
  214. ghost_tdf_predictor-0.6.0/data/raw/tirreno-adriatico-2026.json +1 -0
  215. ghost_tdf_predictor-0.6.0/data/raw/tissot/stage-01.json +1 -0
  216. ghost_tdf_predictor-0.6.0/data/raw/tissot/stage-02.json +1 -0
  217. ghost_tdf_predictor-0.6.0/data/raw/tour-de-france-2021.json +1 -0
  218. ghost_tdf_predictor-0.6.0/data/raw/tour-de-france-2022.json +1 -0
  219. ghost_tdf_predictor-0.6.0/data/raw/tour-de-france-2023.json +1 -0
  220. ghost_tdf_predictor-0.6.0/data/raw/tour-de-france-2024.json +1 -0
  221. ghost_tdf_predictor-0.6.0/data/raw/tour-de-france-2025.json +1 -0
  222. ghost_tdf_predictor-0.6.0/data/raw/tour-de-romandie-2021.json +1 -0
  223. ghost_tdf_predictor-0.6.0/data/raw/tour-de-romandie-2022.json +1 -0
  224. ghost_tdf_predictor-0.6.0/data/raw/tour-de-romandie-2023.json +1 -0
  225. ghost_tdf_predictor-0.6.0/data/raw/tour-de-romandie-2024.json +1 -0
  226. ghost_tdf_predictor-0.6.0/data/raw/tour-de-romandie-2025.json +1 -0
  227. ghost_tdf_predictor-0.6.0/data/raw/tour-de-romandie-2026.json +1 -0
  228. ghost_tdf_predictor-0.6.0/data/raw/tour-de-suisse-2021.json +1 -0
  229. ghost_tdf_predictor-0.6.0/data/raw/tour-de-suisse-2022.json +1 -0
  230. ghost_tdf_predictor-0.6.0/data/raw/tour-de-suisse-2023.json +1 -0
  231. ghost_tdf_predictor-0.6.0/data/raw/tour-de-suisse-2024.json +1 -0
  232. ghost_tdf_predictor-0.6.0/data/raw/tour-de-suisse-2025.json +1 -0
  233. ghost_tdf_predictor-0.6.0/data/raw/tour-de-suisse-2026.json +1 -0
  234. ghost_tdf_predictor-0.6.0/data/raw/volta-a-catalunya-2021.json +1 -0
  235. ghost_tdf_predictor-0.6.0/data/raw/volta-a-catalunya-2022.json +1 -0
  236. ghost_tdf_predictor-0.6.0/data/raw/volta-a-catalunya-2023.json +1 -0
  237. ghost_tdf_predictor-0.6.0/data/raw/volta-a-catalunya-2024.json +1 -0
  238. ghost_tdf_predictor-0.6.0/data/raw/volta-a-catalunya-2025.json +1 -0
  239. ghost_tdf_predictor-0.6.0/data/raw/volta-a-catalunya-2026.json +1 -0
  240. ghost_tdf_predictor-0.6.0/data/raw/vuelta-a-espana-2021.json +1 -0
  241. ghost_tdf_predictor-0.6.0/data/raw/vuelta-a-espana-2022.json +1 -0
  242. ghost_tdf_predictor-0.6.0/data/raw/vuelta-a-espana-2023.json +1 -0
  243. ghost_tdf_predictor-0.6.0/data/raw/vuelta-a-espana-2024.json +1 -0
  244. ghost_tdf_predictor-0.6.0/data/raw/vuelta-a-espana-2025.json +1 -0
  245. ghost_tdf_predictor-0.6.0/data/riders.csv +185 -0
  246. ghost_tdf_predictor-0.6.0/data/riders_raw.json +9954 -0
  247. ghost_tdf_predictor-0.6.0/data/tissot_scoring.json +45 -0
  248. ghost_tdf_predictor-0.6.0/docker-compose.yml +9 -0
  249. ghost_tdf_predictor-0.6.0/docs/SOURCES.md +34 -0
  250. ghost_tdf_predictor-0.6.0/docs/api.md +250 -0
  251. ghost_tdf_predictor-0.6.0/docs/index.md +5 -0
  252. ghost_tdf_predictor-0.6.0/docs/tissot_api.md +99 -0
  253. ghost_tdf_predictor-0.6.0/docs/usage.md +49 -0
  254. ghost_tdf_predictor-0.6.0/mkdocs.yml +43 -0
  255. ghost_tdf_predictor-0.6.0/pyproject.toml +129 -0
  256. ghost_tdf_predictor-0.6.0/src/tdf_predictor/__init__.py +3 -0
  257. ghost_tdf_predictor-0.6.0/src/tdf_predictor/db.py +85 -0
  258. ghost_tdf_predictor-0.6.0/src/tdf_predictor/fantasy.py +439 -0
  259. ghost_tdf_predictor-0.6.0/src/tdf_predictor/ingest.py +190 -0
  260. ghost_tdf_predictor-0.6.0/src/tdf_predictor/model.py +229 -0
  261. ghost_tdf_predictor-0.6.0/src/tdf_predictor/tissot.py +107 -0
  262. ghost_tdf_predictor-0.6.0/src/tdf_predictor/tissot_ingest.py +178 -0
  263. ghost_tdf_predictor-0.6.0/src/tdf_predictor/web.py +671 -0
  264. ghost_tdf_predictor-0.6.0/src/tdf_predictor/weights_fit.py +237 -0
  265. ghost_tdf_predictor-0.6.0/src/tissot_riders.py +135 -0
  266. ghost_tdf_predictor-0.6.0/tasks.py +37 -0
  267. ghost_tdf_predictor-0.6.0/tests/__init__.py +0 -0
  268. ghost_tdf_predictor-0.6.0/tests/test_db.py +59 -0
  269. ghost_tdf_predictor-0.6.0/tests/test_fantasy.py +189 -0
  270. ghost_tdf_predictor-0.6.0/tests/test_ingest.py +33 -0
  271. ghost_tdf_predictor-0.6.0/tests/test_model.py +68 -0
  272. ghost_tdf_predictor-0.6.0/tests/test_package.py +5 -0
  273. ghost_tdf_predictor-0.6.0/tests/test_tissot.py +103 -0
  274. ghost_tdf_predictor-0.6.0/tests/test_tissot_ingest.py +29 -0
  275. ghost_tdf_predictor-0.6.0/tests/test_web.py +270 -0
  276. 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,10 @@
1
+ # ghost-tdf-predictor
2
+ # Copy to .env and fill in real values. Never commit .env.
3
+
4
+ # Tissot fantasy scraper (src/tissot_riders.py)
5
+ TISSOT_USER=
6
+ TISSOT_PASS=
7
+
8
+ # Data paths
9
+ DATA_DIR=./data
10
+ PREDICTIONS_OUTPUT=./predictions.json
@@ -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).