ffbb-data-client 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. ffbb_api_client_v3/__init__.py +25 -0
  2. ffbb_data_client/__init__.py +175 -0
  3. ffbb_data_client/clients/__init__.py +13 -0
  4. ffbb_data_client/clients/api_ffbb_app_client.py +2475 -0
  5. ffbb_data_client/clients/ffbb_data_client.py +2789 -0
  6. ffbb_data_client/clients/meilisearch_client.py +218 -0
  7. ffbb_data_client/clients/meilisearch_ffbb_client.py +647 -0
  8. ffbb_data_client/config.py +153 -0
  9. ffbb_data_client/data/__init__.py +25 -0
  10. ffbb_data_client/data/collections.json +1364 -0
  11. ffbb_data_client/data/endpoint_discovery.json +1875 -0
  12. ffbb_data_client/data/indexes.json +501 -0
  13. ffbb_data_client/data/openapi.json +35713 -0
  14. ffbb_data_client/data/openapi_full.json +37622 -0
  15. ffbb_data_client/helpers/__init__.py +27 -0
  16. ffbb_data_client/helpers/http_requests_helper.py +73 -0
  17. ffbb_data_client/helpers/http_requests_utils.py +502 -0
  18. ffbb_data_client/helpers/meilisearch_client_extension.py +153 -0
  19. ffbb_data_client/helpers/multi_search_query_helper.py +35 -0
  20. ffbb_data_client/models/__init__.py +241 -0
  21. ffbb_data_client/models/affiche.py +45 -0
  22. ffbb_data_client/models/cartographie.py +82 -0
  23. ffbb_data_client/models/categorie.py +55 -0
  24. ffbb_data_client/models/categorie_type.py +42 -0
  25. ffbb_data_client/models/clock.py +38 -0
  26. ffbb_data_client/models/club_contacts.py +77 -0
  27. ffbb_data_client/models/code.py +7 -0
  28. ffbb_data_client/models/commune.py +66 -0
  29. ffbb_data_client/models/competition_fields.py +309 -0
  30. ffbb_data_client/models/competition_id.py +116 -0
  31. ffbb_data_client/models/competition_id_categorie.py +31 -0
  32. ffbb_data_client/models/competition_id_sexe.py +31 -0
  33. ffbb_data_client/models/competition_id_type_competition.py +27 -0
  34. ffbb_data_client/models/competition_id_type_competition_generique.py +24 -0
  35. ffbb_data_client/models/competition_origine.py +69 -0
  36. ffbb_data_client/models/competition_origine_categorie.py +23 -0
  37. ffbb_data_client/models/competition_origine_type_competition.py +14 -0
  38. ffbb_data_client/models/competition_origine_type_competition_generique.py +24 -0
  39. ffbb_data_client/models/competition_type.py +6 -0
  40. ffbb_data_client/models/competitions_facet_distribution.py +65 -0
  41. ffbb_data_client/models/competitions_facet_stats.py +14 -0
  42. ffbb_data_client/models/competitions_hit.py +232 -0
  43. ffbb_data_client/models/competitions_multi_search_query.py +40 -0
  44. ffbb_data_client/models/competitions_query.py +11 -0
  45. ffbb_data_client/models/configuration_models.py +5 -0
  46. ffbb_data_client/models/contact_info.py +18 -0
  47. ffbb_data_client/models/content_multi_search_query.py +93 -0
  48. ffbb_data_client/models/coordonnees.py +27 -0
  49. ffbb_data_client/models/coordonnees_type.py +5 -0
  50. ffbb_data_client/models/document_flyer.py +205 -0
  51. ffbb_data_client/models/document_flyer_type.py +6 -0
  52. ffbb_data_client/models/engagement_contacts.py +97 -0
  53. ffbb_data_client/models/engagements_facet_distribution.py +59 -0
  54. ffbb_data_client/models/engagements_facet_stats.py +14 -0
  55. ffbb_data_client/models/engagements_hit.py +192 -0
  56. ffbb_data_client/models/engagements_multi_search_query.py +41 -0
  57. ffbb_data_client/models/etat.py +6 -0
  58. ffbb_data_client/models/external_competition_id.py +42 -0
  59. ffbb_data_client/models/external_id.py +72 -0
  60. ffbb_data_client/models/facet_distribution.py +13 -0
  61. ffbb_data_client/models/facet_stats.py +13 -0
  62. ffbb_data_client/models/field_set.py +10 -0
  63. ffbb_data_client/models/folder.py +35 -0
  64. ffbb_data_client/models/formation_session.py +60 -0
  65. ffbb_data_client/models/formations_facet_distribution.py +61 -0
  66. ffbb_data_client/models/formations_facet_stats.py +14 -0
  67. ffbb_data_client/models/formations_hit.py +277 -0
  68. ffbb_data_client/models/formations_multi_search_query.py +41 -0
  69. ffbb_data_client/models/game_stats_model.py +57 -0
  70. ffbb_data_client/models/game_stats_models.py +5 -0
  71. ffbb_data_client/models/generic_search.py +92 -0
  72. ffbb_data_client/models/geo.py +27 -0
  73. ffbb_data_client/models/geo_sort_order.py +6 -0
  74. ffbb_data_client/models/get_commune_response.py +18 -0
  75. ffbb_data_client/models/get_competition_response.py +523 -0
  76. ffbb_data_client/models/get_configuration_response.py +45 -0
  77. ffbb_data_client/models/get_engagement_response.py +23 -0
  78. ffbb_data_client/models/get_entraineur_response.py +18 -0
  79. ffbb_data_client/models/get_formation_response.py +28 -0
  80. ffbb_data_client/models/get_officiel_response.py +18 -0
  81. ffbb_data_client/models/get_organisme_response.py +476 -0
  82. ffbb_data_client/models/get_poule_response.py +68 -0
  83. ffbb_data_client/models/get_pratique_response.py +18 -0
  84. ffbb_data_client/models/get_rencontre_response.py +93 -0
  85. ffbb_data_client/models/get_saisons_response.py +56 -0
  86. ffbb_data_client/models/get_salle_response.py +20 -0
  87. ffbb_data_client/models/get_terrain_response.py +16 -0
  88. ffbb_data_client/models/get_tournoi_response.py +16 -0
  89. ffbb_data_client/models/gradient_color.py +27 -0
  90. ffbb_data_client/models/hit.py +16 -0
  91. ffbb_data_client/models/id_engagement_equipe.py +32 -0
  92. ffbb_data_client/models/id_organisme_equipe.py +51 -0
  93. ffbb_data_client/models/id_organisme_equipe1_logo.py +28 -0
  94. ffbb_data_client/models/id_poule.py +27 -0
  95. ffbb_data_client/models/jour.py +11 -0
  96. ffbb_data_client/models/label.py +15 -0
  97. ffbb_data_client/models/labellisation.py +30 -0
  98. ffbb_data_client/models/live.py +192 -0
  99. ffbb_data_client/models/lives.py +6 -0
  100. ffbb_data_client/models/logo.py +28 -0
  101. ffbb_data_client/models/multi_search_queries.py +24 -0
  102. ffbb_data_client/models/multi_search_query.py +96 -0
  103. ffbb_data_client/models/multi_search_result_competitions.py +14 -0
  104. ffbb_data_client/models/multi_search_result_engagements.py +14 -0
  105. ffbb_data_client/models/multi_search_result_formations.py +12 -0
  106. ffbb_data_client/models/multi_search_result_organismes.py +12 -0
  107. ffbb_data_client/models/multi_search_result_pratiques.py +12 -0
  108. ffbb_data_client/models/multi_search_result_rencontres.py +12 -0
  109. ffbb_data_client/models/multi_search_result_salles.py +12 -0
  110. ffbb_data_client/models/multi_search_result_terrains.py +12 -0
  111. ffbb_data_client/models/multi_search_result_tournois.py +12 -0
  112. ffbb_data_client/models/multi_search_results.py +103 -0
  113. ffbb_data_client/models/multi_search_results_class.py +96 -0
  114. ffbb_data_client/models/nature_sol.py +57 -0
  115. ffbb_data_client/models/niveau.py +10 -0
  116. ffbb_data_client/models/niveau_class.py +27 -0
  117. ffbb_data_client/models/niveau_extractor.py +214 -0
  118. ffbb_data_client/models/niveau_info.py +64 -0
  119. ffbb_data_client/models/niveau_models.py +14 -0
  120. ffbb_data_client/models/niveau_type.py +10 -0
  121. ffbb_data_client/models/objectif.py +7 -0
  122. ffbb_data_client/models/organisateur.py +197 -0
  123. ffbb_data_client/models/organisateur_type.py +6 -0
  124. ffbb_data_client/models/organisme_fields.py +327 -0
  125. ffbb_data_client/models/organisme_id_pere.py +177 -0
  126. ffbb_data_client/models/organismes_facet_distribution.py +46 -0
  127. ffbb_data_client/models/organismes_facet_stats.py +14 -0
  128. ffbb_data_client/models/organismes_hit.py +196 -0
  129. ffbb_data_client/models/organismes_multi_search_query.py +41 -0
  130. ffbb_data_client/models/organismes_query.py +8 -0
  131. ffbb_data_client/models/phase_code.py +23 -0
  132. ffbb_data_client/models/poule.py +35 -0
  133. ffbb_data_client/models/poule_fields.py +261 -0
  134. ffbb_data_client/models/poule_rencontre_item_model.py +69 -0
  135. ffbb_data_client/models/poules_models.py +6 -0
  136. ffbb_data_client/models/poules_query.py +9 -0
  137. ffbb_data_client/models/pratique.py +7 -0
  138. ffbb_data_client/models/pratiques_facet_distribution.py +29 -0
  139. ffbb_data_client/models/pratiques_facet_stats.py +14 -0
  140. ffbb_data_client/models/pratiques_hit.py +310 -0
  141. ffbb_data_client/models/pratiques_hit_type.py +9 -0
  142. ffbb_data_client/models/pratiques_multi_search_query.py +41 -0
  143. ffbb_data_client/models/pratiques_type_class.py +45 -0
  144. ffbb_data_client/models/publication_internet.py +6 -0
  145. ffbb_data_client/models/purple_logo.py +24 -0
  146. ffbb_data_client/models/query_fields_manager.py +75 -0
  147. ffbb_data_client/models/ranking_engagement.py +41 -0
  148. ffbb_data_client/models/rankings_models.py +6 -0
  149. ffbb_data_client/models/rencontres_engagement.py +23 -0
  150. ffbb_data_client/models/rencontres_facet_distribution.py +65 -0
  151. ffbb_data_client/models/rencontres_facet_stats.py +14 -0
  152. ffbb_data_client/models/rencontres_hit.py +271 -0
  153. ffbb_data_client/models/rencontres_multi_search_query.py +41 -0
  154. ffbb_data_client/models/saison.py +23 -0
  155. ffbb_data_client/models/saison_fields.py +36 -0
  156. ffbb_data_client/models/saisons_models.py +6 -0
  157. ffbb_data_client/models/saisons_query.py +9 -0
  158. ffbb_data_client/models/salle.py +56 -0
  159. ffbb_data_client/models/salles_facet_distribution.py +14 -0
  160. ffbb_data_client/models/salles_facet_stats.py +14 -0
  161. ffbb_data_client/models/salles_hit.py +153 -0
  162. ffbb_data_client/models/salles_multi_search_query.py +40 -0
  163. ffbb_data_client/models/sexe.py +9 -0
  164. ffbb_data_client/models/sexe_class.py +31 -0
  165. ffbb_data_client/models/source.py +5 -0
  166. ffbb_data_client/models/status.py +5 -0
  167. ffbb_data_client/models/team_engagement.py +56 -0
  168. ffbb_data_client/models/team_ranking.py +108 -0
  169. ffbb_data_client/models/terrains_categorie_championnat_3x3_libelle.py +5 -0
  170. ffbb_data_client/models/terrains_facet_distribution.py +41 -0
  171. ffbb_data_client/models/terrains_facet_stats.py +14 -0
  172. ffbb_data_client/models/terrains_hit.py +223 -0
  173. ffbb_data_client/models/terrains_multi_search_query.py +42 -0
  174. ffbb_data_client/models/terrains_name.py +5 -0
  175. ffbb_data_client/models/terrains_sexe_enum.py +7 -0
  176. ffbb_data_client/models/terrains_storage.py +5 -0
  177. ffbb_data_client/models/tournoi_type_class.py +35 -0
  178. ffbb_data_client/models/tournoi_type_enum.py +7 -0
  179. ffbb_data_client/models/tournoi_types_3x3.py +43 -0
  180. ffbb_data_client/models/tournoi_types_3x3_libelle.py +60 -0
  181. ffbb_data_client/models/tournoi_types_3x3_libelle_enum.py +10 -0
  182. ffbb_data_client/models/tournois_facet_distribution.py +41 -0
  183. ffbb_data_client/models/tournois_facet_stats.py +14 -0
  184. ffbb_data_client/models/tournois_hit.py +132 -0
  185. ffbb_data_client/models/tournois_hit_type.py +5 -0
  186. ffbb_data_client/models/tournois_libelle.py +7 -0
  187. ffbb_data_client/models/tournois_multi_search_query.py +40 -0
  188. ffbb_data_client/models/type_association.py +23 -0
  189. ffbb_data_client/models/type_association_libelle.py +30 -0
  190. ffbb_data_client/models/type_class.py +23 -0
  191. ffbb_data_client/models/type_competition.py +8 -0
  192. ffbb_data_client/models/type_competition_generique.py +31 -0
  193. ffbb_data_client/models/type_enum.py +7 -0
  194. ffbb_data_client/models/type_league.py +6 -0
  195. ffbb_data_client/py.typed +0 -0
  196. ffbb_data_client/utils/__init__.py +27 -0
  197. ffbb_data_client/utils/cache_manager.py +393 -0
  198. ffbb_data_client/utils/converter_utils.py +329 -0
  199. ffbb_data_client/utils/input_validation.py +360 -0
  200. ffbb_data_client/utils/retry_utils.py +478 -0
  201. ffbb_data_client/utils/secure_logging.py +153 -0
  202. ffbb_data_client/utils/token_manager.py +115 -0
  203. ffbb_data_client-2.0.0.dist-info/METADATA +339 -0
  204. ffbb_data_client-2.0.0.dist-info/RECORD +207 -0
  205. ffbb_data_client-2.0.0.dist-info/WHEEL +5 -0
  206. ffbb_data_client-2.0.0.dist-info/licenses/LICENSE.txt +201 -0
  207. ffbb_data_client-2.0.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,214 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+
5
+ from .categorie_type import CategorieType
6
+ from .niveau_info import NiveauInfo
7
+ from .niveau_type import NiveauType
8
+
9
+
10
+ class NiveauExtractor:
11
+ """Extracteur de niveau depuis le nom d'une compétition."""
12
+
13
+ # ⚡ Bolt optimization: Pre-compile regex patterns for ~4x faster extraction in large loops
14
+ # Patterns pour identifier les niveaux
15
+ PATTERNS = {
16
+ NiveauType.ELITE: [
17
+ re.compile(r"\bELITE\b"),
18
+ re.compile(r"\bÉLITE\b"),
19
+ re.compile(r"\bELITE\s+MASCULIN\b"),
20
+ re.compile(r"\bELITE\s+FEMININ\b"),
21
+ ],
22
+ NiveauType.NATIONAL: [
23
+ re.compile(r"\bNATIONAL\b"),
24
+ re.compile(r"\bNATIONALE\b"),
25
+ re.compile(r"\bN1\b"),
26
+ re.compile(r"\bN2\b"),
27
+ re.compile(r"\bN3\b"),
28
+ re.compile(r"\bPRE\s*NATIONAL\b"),
29
+ re.compile(r"\bPRÉ\s*NATIONAL\b"),
30
+ ],
31
+ NiveauType.REGIONAL: [
32
+ re.compile(r"\bREGIONAL\b"),
33
+ re.compile(r"\bRÉGIONAL\b"),
34
+ re.compile(r"\bR1\b"),
35
+ re.compile(r"\bR2\b"),
36
+ re.compile(r"\bR3\b"),
37
+ re.compile(r"\bREGIONALE\b"),
38
+ re.compile(r"^RÉGIONALE\b"), # Format simple: "Régionale masculine seniors"
39
+ ],
40
+ NiveauType.DEPARTEMENTAL: [
41
+ re.compile(r"\bDEPARTEMENTAL\b"),
42
+ re.compile(r"\bDÉPARTEMENTAL\b"),
43
+ re.compile(r"\bD1\b"),
44
+ re.compile(r"\bD2\b"),
45
+ re.compile(r"\bD3\b"),
46
+ re.compile(r"\bDEPARTEMENTALE\b"),
47
+ re.compile(
48
+ r"^DÉPARTEMENTALE\b"
49
+ ), # Format simple: "Départementale masculine seniors"
50
+ ],
51
+ }
52
+
53
+ # Patterns pour extraire les numéros de division
54
+ DIVISION_PATTERNS = [
55
+ re.compile(r"\b[DR](\d+)\b"), # R1, R2, D1, D2, etc.
56
+ re.compile(r"\bREGIONAL\s+(\d+)\b"), # REGIONAL 1, REGIONAL 2
57
+ re.compile(r"\bDEPARTEMENTAL\s+(\d+)\b"), # DEPARTEMENTAL 1, DEPARTEMENTAL 2
58
+ re.compile(r"-\s*DIVISION\s+(\d+)\b"), # - Division 3, - DIVISION 1
59
+ ]
60
+
61
+ # Patterns pour les catégories
62
+ CATEGORIE_PATTERNS = {
63
+ # Catégories jeunes
64
+ CategorieType.U7: [re.compile(r"\bU7\b"), re.compile(r"\bU-7\b")],
65
+ CategorieType.U9: [re.compile(r"\bU9\b"), re.compile(r"\bU-9\b")],
66
+ CategorieType.U11: [re.compile(r"\bU11\b"), re.compile(r"\bU-11\b")],
67
+ CategorieType.U13: [re.compile(r"\bU13\b"), re.compile(r"\bU-13\b")],
68
+ CategorieType.U15: [re.compile(r"\bU15\b"), re.compile(r"\bU-15\b")],
69
+ CategorieType.U17: [re.compile(r"\bU17\b"), re.compile(r"\bU-17\b")],
70
+ CategorieType.U18: [re.compile(r"\bU18\b"), re.compile(r"\bU-18\b")],
71
+ CategorieType.U20: [re.compile(r"\bU20\b"), re.compile(r"\bU-20\b")],
72
+ CategorieType.U21: [re.compile(r"\bU21\b"), re.compile(r"\bU-21\b")],
73
+ # Catégories seniors
74
+ CategorieType.SENIOR: [re.compile(r"\bSENIOR\b")],
75
+ CategorieType.SENIORS: [re.compile(r"\bSENIORS\b")],
76
+ # Catégories vétérans
77
+ CategorieType.VETERAN: [re.compile(r"\bVETERAN\b"), re.compile(r"\bVÉTÉRAN\b")],
78
+ CategorieType.VETERANS: [
79
+ re.compile(r"\bVETERANS\b"),
80
+ re.compile(r"\bVÉTÉRANS\b"),
81
+ ],
82
+ CategorieType.V35: [re.compile(r"\bV35\b"), re.compile(r"\bV-35\b")],
83
+ CategorieType.V40: [re.compile(r"\bV40\b"), re.compile(r"\bV-40\b")],
84
+ CategorieType.V45: [re.compile(r"\bV45\b"), re.compile(r"\bV-45\b")],
85
+ CategorieType.V50: [re.compile(r"\bV50\b"), re.compile(r"\bV-50\b")],
86
+ # Catégories spéciales (anciennes dénominations)
87
+ CategorieType.ESPOIR: [re.compile(r"\bESPOIR\b")],
88
+ CategorieType.ESPOIRS: [re.compile(r"\bESPOIRS\b")],
89
+ CategorieType.CADET: [re.compile(r"\bCADET\b")],
90
+ CategorieType.CADETS: [re.compile(r"\bCADETS\b")],
91
+ CategorieType.MINIME: [re.compile(r"\bMINIME\b")],
92
+ CategorieType.MINIMES: [re.compile(r"\bMINIMES\b")],
93
+ CategorieType.BENJAMIN: [re.compile(r"\bBENJAMIN\b")],
94
+ CategorieType.BENJAMINS: [re.compile(r"\bBENJAMINS\b")],
95
+ CategorieType.POUSSIN: [re.compile(r"\bPOUSSIN\b")],
96
+ CategorieType.POUSSINS: [re.compile(r"\bPOUSSINS\b")],
97
+ CategorieType.MINI_POUSSIN: [re.compile(r"\bMINI\s*POUSSIN\b")],
98
+ CategorieType.MINI_POUSSINS: [re.compile(r"\bMINI\s*POUSSINS\b")],
99
+ }
100
+
101
+ # Pre-compiled regex for U+digits
102
+ _U_DIGITS_PATTERN = re.compile(r"\bU\d+\b")
103
+
104
+ @classmethod
105
+ def extract_niveau(cls, competition_name: str) -> NiveauInfo | None:
106
+ """
107
+ Extrait le niveau d'une compétition depuis son nom.
108
+
109
+ Args:
110
+ competition_name: Nom de la compétition
111
+
112
+ Returns:
113
+ Objet Niveau ou None si aucun niveau n'est détecté
114
+ """
115
+ if not competition_name:
116
+ return None
117
+
118
+ name_upper = competition_name.upper()
119
+
120
+ # Détection du type de niveau
121
+ detected_type = None
122
+ matched_text = ""
123
+
124
+ for niveau_type, patterns in cls.PATTERNS.items():
125
+ for pattern in patterns:
126
+ match = pattern.search(name_upper)
127
+ if match:
128
+ detected_type = niveau_type
129
+ matched_text = match.group(0)
130
+ break
131
+ if detected_type:
132
+ break
133
+
134
+ if not detected_type:
135
+ return None
136
+
137
+ # Détection de la division
138
+ detected_division = None
139
+ for pattern in cls.DIVISION_PATTERNS:
140
+ match = pattern.search(name_upper)
141
+ if match:
142
+ detected_division = int(match.group(1))
143
+ break
144
+
145
+ # Détection de la catégorie
146
+ detected_categorie = None
147
+ for categorie_type, patterns in cls.CATEGORIE_PATTERNS.items():
148
+ for pattern in patterns:
149
+ if pattern.search(name_upper):
150
+ detected_categorie = categorie_type
151
+ break
152
+ if detected_categorie:
153
+ break
154
+
155
+ # Si aucune catégorie spécifique n'est trouvée, essayer de déduire SENIOR
156
+ if not detected_categorie:
157
+ # Si pas de catégorie jeune détectée et que c'est une compétition, on assume SENIOR
158
+ if not cls._U_DIGITS_PATTERN.search(name_upper):
159
+ detected_categorie = CategorieType.SENIOR
160
+
161
+ # Déterminer la zone géographique
162
+ zone_geo = None
163
+ if detected_type == NiveauType.ELITE:
164
+ zone_geo = "regional" # ELITE est associé à régional
165
+
166
+ return NiveauInfo(
167
+ type=detected_type,
168
+ division=detected_division,
169
+ categorie=detected_categorie,
170
+ raw_text=matched_text,
171
+ zone_geographique=zone_geo,
172
+ )
173
+
174
+ @classmethod
175
+ def extract_from_competition_data(cls, competition_data: dict) -> NiveauInfo | None:
176
+ """
177
+ Extrait le niveau depuis les données complètes de compétition.
178
+
179
+ Args:
180
+ competition_data: Dictionnaire avec les données de compétition
181
+
182
+ Returns:
183
+ Objet Niveau ou None
184
+ """
185
+ # Essayer d'abord avec le nom de la compétition
186
+ nom = competition_data.get("nom", "")
187
+ niveau = cls.extract_niveau(nom)
188
+
189
+ if niveau:
190
+ return niveau
191
+
192
+ # Essayer avec le code de la compétition
193
+ code = competition_data.get("code", "")
194
+ if code:
195
+ niveau = cls.extract_niveau(code)
196
+
197
+ return niveau
198
+
199
+
200
+ # Fonctions utilitaires pour l'analyse
201
+ def get_niveau_from_idcompetition(idcompetition) -> NiveauInfo | None:
202
+ """
203
+ Extrait le niveau depuis un objet IdCompetitionModel.
204
+
205
+ Args:
206
+ idcompetition: Instance de IdCompetitionModel
207
+
208
+ Returns:
209
+ Objet Niveau ou None
210
+ """
211
+ if not idcompetition or not idcompetition.nom:
212
+ return None
213
+
214
+ return NiveauExtractor.extract_niveau(idcompetition.nom)
@@ -0,0 +1,64 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from .categorie_type import CategorieType
6
+ from .niveau_type import NiveauType
7
+
8
+
9
+ @dataclass
10
+ class NiveauInfo:
11
+ """
12
+ Classe pour représenter le niveau d'une compétition extrait du nom.
13
+
14
+ Attributes:
15
+ type: Type de niveau (departemental, regional, national, elite)
16
+ division: Division spécifique (D1, D2, R1, R2, etc.)
17
+ categorie: Catégorie d'âge (U7, U11, U13, U15, U17, U18, U20, U21, SENIOR, etc.)
18
+ raw_text: Texte brut extrait du nom de la compétition
19
+ zone_geographique: Zone géographique associée (regional pour ELITE)
20
+ """
21
+
22
+ type: NiveauType
23
+ division: int | None = None
24
+ categorie: CategorieType | None = None
25
+ raw_text: str = ""
26
+ zone_geographique: str | None = None
27
+
28
+ @property
29
+ def is_elite(self) -> bool:
30
+ """Vérifie si c'est un niveau ELITE."""
31
+ return self.type == NiveauType.ELITE
32
+
33
+ @property
34
+ def zone_effective(self) -> str:
35
+ """Retourne la zone géographique effective (ELITE -> regional)."""
36
+ if self.is_elite:
37
+ return "regional"
38
+ return self.type.value
39
+
40
+ def matches_filter(
41
+ self, zone_filter: str, division_filter: int | None = None
42
+ ) -> bool:
43
+ """
44
+ Vérifie si ce niveau correspond aux filtres spécifiés.
45
+
46
+ Args:
47
+ zone_filter: Zone recherchée (departemental, regional, national)
48
+ division_filter: Numéro de division recherchée (optionnel)
49
+
50
+ Returns:
51
+ True si le niveau correspond aux filtres
52
+ """
53
+ # Vérifier la zone (ELITE est considéré comme regional)
54
+ if zone_filter.lower() != self.zone_effective:
55
+ return False
56
+
57
+ # Vérifier la division si spécifiée
58
+ if division_filter is not None:
59
+ if self.division is None:
60
+ return False # Pas de division mais division demandée
61
+ if self.division != division_filter:
62
+ return False
63
+
64
+ return True
@@ -0,0 +1,14 @@
1
+ """Backward-compatibility re-export shim for niveau module."""
2
+
3
+ from .categorie_type import CategorieType
4
+ from .niveau_extractor import NiveauExtractor, get_niveau_from_idcompetition
5
+ from .niveau_info import NiveauInfo
6
+ from .niveau_type import NiveauType
7
+
8
+ __all__ = [
9
+ "CategorieType",
10
+ "NiveauExtractor",
11
+ "NiveauInfo",
12
+ "NiveauType",
13
+ "get_niveau_from_idcompetition",
14
+ ]
@@ -0,0 +1,10 @@
1
+ from enum import Enum
2
+
3
+
4
+ class NiveauType(Enum):
5
+ """Enumération des types de niveau de compétition."""
6
+
7
+ DEPARTEMENTAL = "departemental"
8
+ REGIONAL = "regional"
9
+ NATIONAL = "national"
10
+ ELITE = "elite" # ELITE est associé à régional
@@ -0,0 +1,7 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Objectif(Enum):
5
+ ACCOMPAGNEMENT = "Accompagnement"
6
+ CURATIF = "Curatif"
7
+ PREVENTIVE = "Préventif"
@@ -0,0 +1,197 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any
6
+ from uuid import UUID
7
+
8
+ from ..utils.converter_utils import (
9
+ from_bool,
10
+ from_datetime,
11
+ from_list,
12
+ from_obj,
13
+ from_str,
14
+ from_uuid,
15
+ )
16
+ from .organisme_id_pere import OrganismeIDPere
17
+
18
+
19
+ @dataclass
20
+ class Organisateur:
21
+ adresse: str | None = None
22
+ adresse_club_pro: str | None = None
23
+ cartographie: str | None = None
24
+ code: str | None = None
25
+ commune: str | None = None
26
+ commune_club_pro: str | None = None
27
+ id: str | None = None
28
+ mail: str | None = None
29
+ nom: str | None = None
30
+ nom_club_pro: str | None = None
31
+ organisme_id_pere: OrganismeIDPere | None = None
32
+ salle: str | None = None
33
+ telephone: str | None = None
34
+ type: str | None = None
35
+ type_association: str | None = None
36
+ url_site_web: str | None = None
37
+ logo: UUID | None = None
38
+ nom_simple: str | None = None
39
+ date_affiliation: datetime | None = None
40
+ saison_en_cours: bool | None = None
41
+ entreprise: bool | None = None
42
+ handibasket: bool | None = None
43
+ omnisport: bool | None = None
44
+ hors_association: bool | None = None
45
+ offres_pratiques: list[Any] | None = None
46
+ engagements: list[Any] | None = None
47
+ labellisation: list[Any] | None = None
48
+ membres: list[int] | None = None
49
+ date_created: datetime | None = None
50
+ date_updated: datetime | None = None
51
+ logo_base64: UUID | None = None
52
+ competitions: list[str] | None = None
53
+ organismes_fils: list[int] | None = None
54
+
55
+ @staticmethod
56
+ def from_dict(obj: Any) -> Organisateur:
57
+ assert isinstance(obj, dict)
58
+ adresse = from_str(obj, "adresse")
59
+ adresse_club_pro = from_str(obj, "adresseClubPro")
60
+ cartographie = from_str(obj, "cartographie")
61
+ code = from_str(obj, "code")
62
+ commune = from_str(obj, "commune")
63
+ commune_club_pro = from_str(obj, "communeClubPro")
64
+ id = from_str(obj, "id")
65
+ mail = from_str(obj, "mail")
66
+ nom = from_str(obj, "nom")
67
+ nom_club_pro = from_str(obj, "nomClubPro")
68
+ organisme_id_pere = from_obj(
69
+ OrganismeIDPere.from_dict, obj, "organisme_id_pere"
70
+ )
71
+ salle = from_str(obj, "salle")
72
+ telephone = from_str(obj, "telephone")
73
+ type = from_str(obj, "type")
74
+ type_association = from_str(obj, "type_association")
75
+ url_site_web = from_str(obj, "urlSiteWeb")
76
+ logo = from_uuid(obj, "logo")
77
+ nom_simple = from_str(obj, "nom_simple")
78
+ date_affiliation = from_datetime(obj, "dateAffiliation")
79
+ saison_en_cours = from_bool(obj, "saison_en_cours")
80
+ entreprise = from_bool(obj, "entreprise")
81
+ handibasket = from_bool(obj, "handibasket")
82
+ omnisport = from_bool(obj, "omnisport")
83
+ hors_association = from_bool(obj, "horsAssociation")
84
+ offres_pratiques = from_list(lambda x: x, obj, "offresPratiques")
85
+ engagements = from_list(lambda x: x, obj, "engagements")
86
+ labellisation = from_list(lambda x: x, obj, "labellisation")
87
+ membres = from_list(int, obj, "membres")
88
+ date_created = from_datetime(obj, "date_created")
89
+ date_updated = from_datetime(obj, "date_updated")
90
+ logo_base64 = from_uuid(obj, "logo_base64")
91
+ competitions = from_list(str, obj, "competitions")
92
+ organismes_fils = from_list(int, obj, "organismes_fils")
93
+ return Organisateur(
94
+ adresse=adresse,
95
+ adresse_club_pro=adresse_club_pro,
96
+ cartographie=cartographie,
97
+ code=code,
98
+ commune=commune,
99
+ commune_club_pro=commune_club_pro,
100
+ id=id,
101
+ mail=mail,
102
+ nom=nom,
103
+ nom_club_pro=nom_club_pro,
104
+ organisme_id_pere=organisme_id_pere,
105
+ salle=salle,
106
+ telephone=telephone,
107
+ type=type,
108
+ type_association=type_association,
109
+ url_site_web=url_site_web,
110
+ logo=logo,
111
+ nom_simple=nom_simple,
112
+ date_affiliation=date_affiliation,
113
+ saison_en_cours=saison_en_cours,
114
+ entreprise=entreprise,
115
+ handibasket=handibasket,
116
+ omnisport=omnisport,
117
+ hors_association=hors_association,
118
+ offres_pratiques=offres_pratiques,
119
+ engagements=engagements,
120
+ labellisation=labellisation,
121
+ membres=membres,
122
+ date_created=date_created,
123
+ date_updated=date_updated,
124
+ logo_base64=logo_base64,
125
+ competitions=competitions,
126
+ organismes_fils=organismes_fils,
127
+ )
128
+
129
+ def to_dict(self) -> dict:
130
+ result: dict = {}
131
+ if self.adresse is not None:
132
+ result["adresse"] = self.adresse
133
+ if self.adresse_club_pro is not None:
134
+ result["adresseClubPro"] = self.adresse_club_pro
135
+ if self.cartographie is not None:
136
+ result["cartographie"] = self.cartographie
137
+ if self.code is not None:
138
+ result["code"] = self.code
139
+ if self.commune is not None:
140
+ result["commune"] = self.commune
141
+ if self.commune_club_pro is not None:
142
+ result["communeClubPro"] = self.commune_club_pro
143
+ if self.id is not None:
144
+ result["id"] = self.id
145
+ if self.mail is not None:
146
+ result["mail"] = self.mail
147
+ if self.nom is not None:
148
+ result["nom"] = self.nom
149
+ if self.nom_club_pro is not None:
150
+ result["nomClubPro"] = self.nom_club_pro
151
+ if self.organisme_id_pere is not None:
152
+ result["organisme_id_pere"] = self.organisme_id_pere.to_dict()
153
+ if self.salle is not None:
154
+ result["salle"] = self.salle
155
+ if self.telephone is not None:
156
+ result["telephone"] = self.telephone
157
+ if self.type is not None:
158
+ result["type"] = self.type
159
+ if self.type_association is not None:
160
+ result["type_association"] = self.type_association
161
+ if self.url_site_web is not None:
162
+ result["urlSiteWeb"] = self.url_site_web
163
+ if self.logo is not None:
164
+ result["logo"] = str(self.logo)
165
+ if self.nom_simple is not None:
166
+ result["nom_simple"] = self.nom_simple
167
+ if self.date_affiliation is not None:
168
+ result["dateAffiliation"] = self.date_affiliation.isoformat()
169
+ if self.saison_en_cours is not None:
170
+ result["saison_en_cours"] = self.saison_en_cours
171
+ if self.entreprise is not None:
172
+ result["entreprise"] = self.entreprise
173
+ if self.handibasket is not None:
174
+ result["handibasket"] = self.handibasket
175
+ if self.omnisport is not None:
176
+ result["omnisport"] = self.omnisport
177
+ if self.hors_association is not None:
178
+ result["horsAssociation"] = self.hors_association
179
+ if self.offres_pratiques is not None:
180
+ result["offresPratiques"] = self.offres_pratiques
181
+ if self.engagements is not None:
182
+ result["engagements"] = self.engagements
183
+ if self.labellisation is not None:
184
+ result["labellisation"] = self.labellisation
185
+ if self.membres is not None:
186
+ result["membres"] = [str(x) for x in self.membres]
187
+ if self.date_created is not None:
188
+ result["date_created"] = self.date_created.isoformat()
189
+ if self.date_updated is not None:
190
+ result["date_updated"] = self.date_updated.isoformat()
191
+ if self.logo_base64 is not None:
192
+ result["logo_base64"] = str(self.logo_base64)
193
+ if self.competitions is not None:
194
+ result["competitions"] = self.competitions
195
+ if self.organismes_fils is not None:
196
+ result["organismes_fils"] = [str(x) for x in self.organismes_fils]
197
+ return result
@@ -0,0 +1,6 @@
1
+ from enum import Enum
2
+
3
+
4
+ class OrganisateurType(Enum):
5
+ C = "C"
6
+ L = "L"