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.
- ffbb_api_client_v3/__init__.py +25 -0
- ffbb_data_client/__init__.py +175 -0
- ffbb_data_client/clients/__init__.py +13 -0
- ffbb_data_client/clients/api_ffbb_app_client.py +2475 -0
- ffbb_data_client/clients/ffbb_data_client.py +2789 -0
- ffbb_data_client/clients/meilisearch_client.py +218 -0
- ffbb_data_client/clients/meilisearch_ffbb_client.py +647 -0
- ffbb_data_client/config.py +153 -0
- ffbb_data_client/data/__init__.py +25 -0
- ffbb_data_client/data/collections.json +1364 -0
- ffbb_data_client/data/endpoint_discovery.json +1875 -0
- ffbb_data_client/data/indexes.json +501 -0
- ffbb_data_client/data/openapi.json +35713 -0
- ffbb_data_client/data/openapi_full.json +37622 -0
- ffbb_data_client/helpers/__init__.py +27 -0
- ffbb_data_client/helpers/http_requests_helper.py +73 -0
- ffbb_data_client/helpers/http_requests_utils.py +502 -0
- ffbb_data_client/helpers/meilisearch_client_extension.py +153 -0
- ffbb_data_client/helpers/multi_search_query_helper.py +35 -0
- ffbb_data_client/models/__init__.py +241 -0
- ffbb_data_client/models/affiche.py +45 -0
- ffbb_data_client/models/cartographie.py +82 -0
- ffbb_data_client/models/categorie.py +55 -0
- ffbb_data_client/models/categorie_type.py +42 -0
- ffbb_data_client/models/clock.py +38 -0
- ffbb_data_client/models/club_contacts.py +77 -0
- ffbb_data_client/models/code.py +7 -0
- ffbb_data_client/models/commune.py +66 -0
- ffbb_data_client/models/competition_fields.py +309 -0
- ffbb_data_client/models/competition_id.py +116 -0
- ffbb_data_client/models/competition_id_categorie.py +31 -0
- ffbb_data_client/models/competition_id_sexe.py +31 -0
- ffbb_data_client/models/competition_id_type_competition.py +27 -0
- ffbb_data_client/models/competition_id_type_competition_generique.py +24 -0
- ffbb_data_client/models/competition_origine.py +69 -0
- ffbb_data_client/models/competition_origine_categorie.py +23 -0
- ffbb_data_client/models/competition_origine_type_competition.py +14 -0
- ffbb_data_client/models/competition_origine_type_competition_generique.py +24 -0
- ffbb_data_client/models/competition_type.py +6 -0
- ffbb_data_client/models/competitions_facet_distribution.py +65 -0
- ffbb_data_client/models/competitions_facet_stats.py +14 -0
- ffbb_data_client/models/competitions_hit.py +232 -0
- ffbb_data_client/models/competitions_multi_search_query.py +40 -0
- ffbb_data_client/models/competitions_query.py +11 -0
- ffbb_data_client/models/configuration_models.py +5 -0
- ffbb_data_client/models/contact_info.py +18 -0
- ffbb_data_client/models/content_multi_search_query.py +93 -0
- ffbb_data_client/models/coordonnees.py +27 -0
- ffbb_data_client/models/coordonnees_type.py +5 -0
- ffbb_data_client/models/document_flyer.py +205 -0
- ffbb_data_client/models/document_flyer_type.py +6 -0
- ffbb_data_client/models/engagement_contacts.py +97 -0
- ffbb_data_client/models/engagements_facet_distribution.py +59 -0
- ffbb_data_client/models/engagements_facet_stats.py +14 -0
- ffbb_data_client/models/engagements_hit.py +192 -0
- ffbb_data_client/models/engagements_multi_search_query.py +41 -0
- ffbb_data_client/models/etat.py +6 -0
- ffbb_data_client/models/external_competition_id.py +42 -0
- ffbb_data_client/models/external_id.py +72 -0
- ffbb_data_client/models/facet_distribution.py +13 -0
- ffbb_data_client/models/facet_stats.py +13 -0
- ffbb_data_client/models/field_set.py +10 -0
- ffbb_data_client/models/folder.py +35 -0
- ffbb_data_client/models/formation_session.py +60 -0
- ffbb_data_client/models/formations_facet_distribution.py +61 -0
- ffbb_data_client/models/formations_facet_stats.py +14 -0
- ffbb_data_client/models/formations_hit.py +277 -0
- ffbb_data_client/models/formations_multi_search_query.py +41 -0
- ffbb_data_client/models/game_stats_model.py +57 -0
- ffbb_data_client/models/game_stats_models.py +5 -0
- ffbb_data_client/models/generic_search.py +92 -0
- ffbb_data_client/models/geo.py +27 -0
- ffbb_data_client/models/geo_sort_order.py +6 -0
- ffbb_data_client/models/get_commune_response.py +18 -0
- ffbb_data_client/models/get_competition_response.py +523 -0
- ffbb_data_client/models/get_configuration_response.py +45 -0
- ffbb_data_client/models/get_engagement_response.py +23 -0
- ffbb_data_client/models/get_entraineur_response.py +18 -0
- ffbb_data_client/models/get_formation_response.py +28 -0
- ffbb_data_client/models/get_officiel_response.py +18 -0
- ffbb_data_client/models/get_organisme_response.py +476 -0
- ffbb_data_client/models/get_poule_response.py +68 -0
- ffbb_data_client/models/get_pratique_response.py +18 -0
- ffbb_data_client/models/get_rencontre_response.py +93 -0
- ffbb_data_client/models/get_saisons_response.py +56 -0
- ffbb_data_client/models/get_salle_response.py +20 -0
- ffbb_data_client/models/get_terrain_response.py +16 -0
- ffbb_data_client/models/get_tournoi_response.py +16 -0
- ffbb_data_client/models/gradient_color.py +27 -0
- ffbb_data_client/models/hit.py +16 -0
- ffbb_data_client/models/id_engagement_equipe.py +32 -0
- ffbb_data_client/models/id_organisme_equipe.py +51 -0
- ffbb_data_client/models/id_organisme_equipe1_logo.py +28 -0
- ffbb_data_client/models/id_poule.py +27 -0
- ffbb_data_client/models/jour.py +11 -0
- ffbb_data_client/models/label.py +15 -0
- ffbb_data_client/models/labellisation.py +30 -0
- ffbb_data_client/models/live.py +192 -0
- ffbb_data_client/models/lives.py +6 -0
- ffbb_data_client/models/logo.py +28 -0
- ffbb_data_client/models/multi_search_queries.py +24 -0
- ffbb_data_client/models/multi_search_query.py +96 -0
- ffbb_data_client/models/multi_search_result_competitions.py +14 -0
- ffbb_data_client/models/multi_search_result_engagements.py +14 -0
- ffbb_data_client/models/multi_search_result_formations.py +12 -0
- ffbb_data_client/models/multi_search_result_organismes.py +12 -0
- ffbb_data_client/models/multi_search_result_pratiques.py +12 -0
- ffbb_data_client/models/multi_search_result_rencontres.py +12 -0
- ffbb_data_client/models/multi_search_result_salles.py +12 -0
- ffbb_data_client/models/multi_search_result_terrains.py +12 -0
- ffbb_data_client/models/multi_search_result_tournois.py +12 -0
- ffbb_data_client/models/multi_search_results.py +103 -0
- ffbb_data_client/models/multi_search_results_class.py +96 -0
- ffbb_data_client/models/nature_sol.py +57 -0
- ffbb_data_client/models/niveau.py +10 -0
- ffbb_data_client/models/niveau_class.py +27 -0
- ffbb_data_client/models/niveau_extractor.py +214 -0
- ffbb_data_client/models/niveau_info.py +64 -0
- ffbb_data_client/models/niveau_models.py +14 -0
- ffbb_data_client/models/niveau_type.py +10 -0
- ffbb_data_client/models/objectif.py +7 -0
- ffbb_data_client/models/organisateur.py +197 -0
- ffbb_data_client/models/organisateur_type.py +6 -0
- ffbb_data_client/models/organisme_fields.py +327 -0
- ffbb_data_client/models/organisme_id_pere.py +177 -0
- ffbb_data_client/models/organismes_facet_distribution.py +46 -0
- ffbb_data_client/models/organismes_facet_stats.py +14 -0
- ffbb_data_client/models/organismes_hit.py +196 -0
- ffbb_data_client/models/organismes_multi_search_query.py +41 -0
- ffbb_data_client/models/organismes_query.py +8 -0
- ffbb_data_client/models/phase_code.py +23 -0
- ffbb_data_client/models/poule.py +35 -0
- ffbb_data_client/models/poule_fields.py +261 -0
- ffbb_data_client/models/poule_rencontre_item_model.py +69 -0
- ffbb_data_client/models/poules_models.py +6 -0
- ffbb_data_client/models/poules_query.py +9 -0
- ffbb_data_client/models/pratique.py +7 -0
- ffbb_data_client/models/pratiques_facet_distribution.py +29 -0
- ffbb_data_client/models/pratiques_facet_stats.py +14 -0
- ffbb_data_client/models/pratiques_hit.py +310 -0
- ffbb_data_client/models/pratiques_hit_type.py +9 -0
- ffbb_data_client/models/pratiques_multi_search_query.py +41 -0
- ffbb_data_client/models/pratiques_type_class.py +45 -0
- ffbb_data_client/models/publication_internet.py +6 -0
- ffbb_data_client/models/purple_logo.py +24 -0
- ffbb_data_client/models/query_fields_manager.py +75 -0
- ffbb_data_client/models/ranking_engagement.py +41 -0
- ffbb_data_client/models/rankings_models.py +6 -0
- ffbb_data_client/models/rencontres_engagement.py +23 -0
- ffbb_data_client/models/rencontres_facet_distribution.py +65 -0
- ffbb_data_client/models/rencontres_facet_stats.py +14 -0
- ffbb_data_client/models/rencontres_hit.py +271 -0
- ffbb_data_client/models/rencontres_multi_search_query.py +41 -0
- ffbb_data_client/models/saison.py +23 -0
- ffbb_data_client/models/saison_fields.py +36 -0
- ffbb_data_client/models/saisons_models.py +6 -0
- ffbb_data_client/models/saisons_query.py +9 -0
- ffbb_data_client/models/salle.py +56 -0
- ffbb_data_client/models/salles_facet_distribution.py +14 -0
- ffbb_data_client/models/salles_facet_stats.py +14 -0
- ffbb_data_client/models/salles_hit.py +153 -0
- ffbb_data_client/models/salles_multi_search_query.py +40 -0
- ffbb_data_client/models/sexe.py +9 -0
- ffbb_data_client/models/sexe_class.py +31 -0
- ffbb_data_client/models/source.py +5 -0
- ffbb_data_client/models/status.py +5 -0
- ffbb_data_client/models/team_engagement.py +56 -0
- ffbb_data_client/models/team_ranking.py +108 -0
- ffbb_data_client/models/terrains_categorie_championnat_3x3_libelle.py +5 -0
- ffbb_data_client/models/terrains_facet_distribution.py +41 -0
- ffbb_data_client/models/terrains_facet_stats.py +14 -0
- ffbb_data_client/models/terrains_hit.py +223 -0
- ffbb_data_client/models/terrains_multi_search_query.py +42 -0
- ffbb_data_client/models/terrains_name.py +5 -0
- ffbb_data_client/models/terrains_sexe_enum.py +7 -0
- ffbb_data_client/models/terrains_storage.py +5 -0
- ffbb_data_client/models/tournoi_type_class.py +35 -0
- ffbb_data_client/models/tournoi_type_enum.py +7 -0
- ffbb_data_client/models/tournoi_types_3x3.py +43 -0
- ffbb_data_client/models/tournoi_types_3x3_libelle.py +60 -0
- ffbb_data_client/models/tournoi_types_3x3_libelle_enum.py +10 -0
- ffbb_data_client/models/tournois_facet_distribution.py +41 -0
- ffbb_data_client/models/tournois_facet_stats.py +14 -0
- ffbb_data_client/models/tournois_hit.py +132 -0
- ffbb_data_client/models/tournois_hit_type.py +5 -0
- ffbb_data_client/models/tournois_libelle.py +7 -0
- ffbb_data_client/models/tournois_multi_search_query.py +40 -0
- ffbb_data_client/models/type_association.py +23 -0
- ffbb_data_client/models/type_association_libelle.py +30 -0
- ffbb_data_client/models/type_class.py +23 -0
- ffbb_data_client/models/type_competition.py +8 -0
- ffbb_data_client/models/type_competition_generique.py +31 -0
- ffbb_data_client/models/type_enum.py +7 -0
- ffbb_data_client/models/type_league.py +6 -0
- ffbb_data_client/py.typed +0 -0
- ffbb_data_client/utils/__init__.py +27 -0
- ffbb_data_client/utils/cache_manager.py +393 -0
- ffbb_data_client/utils/converter_utils.py +329 -0
- ffbb_data_client/utils/input_validation.py +360 -0
- ffbb_data_client/utils/retry_utils.py +478 -0
- ffbb_data_client/utils/secure_logging.py +153 -0
- ffbb_data_client/utils/token_manager.py +115 -0
- ffbb_data_client-2.0.0.dist-info/METADATA +339 -0
- ffbb_data_client-2.0.0.dist-info/RECORD +207 -0
- ffbb_data_client-2.0.0.dist-info/WHEEL +5 -0
- ffbb_data_client-2.0.0.dist-info/licenses/LICENSE.txt +201 -0
- 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,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
|