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,92 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from dataclasses import dataclass, field
5
+ from typing import Any
6
+
7
+ from .facet_distribution import FacetDistribution
8
+ from .facet_stats import FacetStats
9
+ from .hit import Hit
10
+ from .multi_search_results import MultiSearchResult
11
+
12
+
13
+ @dataclass
14
+ class GenericSearchHit(Hit):
15
+ """Meilisearch hit for content indexes whose schema changes frequently."""
16
+
17
+ data: dict[str, Any] = field(default_factory=dict)
18
+
19
+ @property
20
+ def id(self) -> Any | None:
21
+ return self.data.get("id")
22
+
23
+ @property
24
+ def title(self) -> str | None:
25
+ title = self.data.get("title")
26
+ return str(title) if title is not None else None
27
+
28
+ @property
29
+ def type(self) -> str | None:
30
+ value = self.data.get("type")
31
+ return str(value) if value is not None else None
32
+
33
+ @staticmethod
34
+ def from_dict(obj: Any) -> GenericSearchHit:
35
+ return GenericSearchHit(data=dict(obj) if isinstance(obj, dict) else {})
36
+
37
+ def to_dict(self) -> dict[str, Any]:
38
+ return dict(self.data)
39
+
40
+ def is_valid_for_query(self, query: str) -> bool:
41
+ if not query:
42
+ return True
43
+ haystack = json.dumps(self.data, ensure_ascii=False, default=str).lower()
44
+ return query.lower() in haystack
45
+
46
+
47
+ @dataclass
48
+ class GenericFacetDistribution(FacetDistribution):
49
+ data: dict[str, Any] = field(default_factory=dict)
50
+
51
+ @staticmethod
52
+ def from_dict(obj: Any) -> GenericFacetDistribution:
53
+ return GenericFacetDistribution(data=dict(obj) if isinstance(obj, dict) else {})
54
+
55
+ def to_dict(self) -> dict[str, Any]:
56
+ return dict(self.data)
57
+
58
+
59
+ @dataclass
60
+ class GenericFacetStats(FacetStats):
61
+ data: dict[str, Any] = field(default_factory=dict)
62
+
63
+ @staticmethod
64
+ def from_dict(obj: Any) -> GenericFacetStats:
65
+ return GenericFacetStats(data=dict(obj) if isinstance(obj, dict) else {})
66
+
67
+ def to_dict(self) -> dict[str, Any]:
68
+ return dict(self.data)
69
+
70
+
71
+ class NewsMultiSearchResult(
72
+ MultiSearchResult[GenericSearchHit, GenericFacetDistribution, GenericFacetStats]
73
+ ):
74
+ """MultiSearchResult for ffbbsite_news."""
75
+
76
+
77
+ class YoutubeVideosMultiSearchResult(
78
+ MultiSearchResult[GenericSearchHit, GenericFacetDistribution, GenericFacetStats]
79
+ ):
80
+ """MultiSearchResult for youtube_videos."""
81
+
82
+
83
+ class RssMultiSearchResult(
84
+ MultiSearchResult[GenericSearchHit, GenericFacetDistribution, GenericFacetStats]
85
+ ):
86
+ """MultiSearchResult for ffbbnational_rss."""
87
+
88
+
89
+ class GaleriesMultiSearchResult(
90
+ MultiSearchResult[GenericSearchHit, GenericFacetDistribution, GenericFacetStats]
91
+ ):
92
+ """MultiSearchResult for ffbbnational_galeries."""
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from ..utils.converter_utils import from_float
7
+
8
+
9
+ @dataclass
10
+ class Geo:
11
+ lat: float | None = None
12
+ lng: float | None = None
13
+
14
+ @staticmethod
15
+ def from_dict(obj: Any) -> Geo:
16
+ assert isinstance(obj, dict)
17
+ lat = from_float(obj, "lat")
18
+ lng = from_float(obj, "lng")
19
+ return Geo(lat=lat, lng=lng)
20
+
21
+ def to_dict(self) -> dict:
22
+ result: dict = {}
23
+ if self.lat is not None:
24
+ result["lat"] = self.lat
25
+ if self.lng is not None:
26
+ result["lng"] = self.lng
27
+ return result
@@ -0,0 +1,6 @@
1
+ from enum import Enum
2
+
3
+
4
+ class GeoSortOrder(str, Enum):
5
+ NEAREST_FIRST = "asc"
6
+ FARTHEST_FIRST = "desc"
@@ -0,0 +1,18 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class GetCommuneResponse:
6
+ id: str
7
+ libelle: str | None = None
8
+ codePostal: str | None = None
9
+
10
+ @classmethod
11
+ def from_dict(cls, data: dict) -> "GetCommuneResponse | None":
12
+ if not data or not isinstance(data, dict):
13
+ return None
14
+ return cls(
15
+ id=str(data.get("id", "")),
16
+ libelle=data.get("libelle"),
17
+ codePostal=data.get("codePostal"),
18
+ )
@@ -0,0 +1,523 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import datetime
5
+ from typing import Any
6
+
7
+ from .game_stats_model import GameStatsModel
8
+
9
+
10
+ @dataclass
11
+ class GetCompetitionResponse:
12
+ id: str
13
+ nom: str
14
+ sexe: str
15
+ saison: str
16
+ code: str
17
+ typeCompetition: str
18
+ liveStat: int
19
+ competition_origine: str
20
+ competition_origine_nom: str
21
+ publicationInternet: str
22
+
23
+ @dataclass
24
+ class CategorieModel:
25
+ code: str
26
+ ordre: int
27
+
28
+ categorie: CategorieModel | None = None
29
+
30
+ @dataclass
31
+ class TypecompetitiongeneriqueModel:
32
+
33
+ @dataclass
34
+ class LogoModel:
35
+ id: str
36
+ gradient_color: str
37
+
38
+ logo: LogoModel | None = None
39
+
40
+ typeCompetitionGenerique: TypecompetitiongeneriqueModel | None = None
41
+ logo: Any | None = None
42
+ id_competition_pere: int | None = None
43
+
44
+ @dataclass
45
+ class PoulesitemModel:
46
+ id: str
47
+ nom: str
48
+
49
+ poules: list[PoulesitemModel] = field(default_factory=list)
50
+
51
+ @dataclass
52
+ class PhasesitemModel:
53
+ id: str
54
+ nom: str
55
+ liveStat: int
56
+ phase_code: str
57
+
58
+ @dataclass
59
+ class PoulesitemModel:
60
+ id: str
61
+ nom: str
62
+
63
+ @dataclass
64
+ class RencontresitemModel:
65
+ id: str
66
+ numero: str
67
+ numeroJournee: str
68
+ idPoule: str
69
+ competitionId: str
70
+ resultatEquipe1: str
71
+ resultatEquipe2: str
72
+ joue: int
73
+ nomEquipe1: str
74
+ nomEquipe2: str
75
+ date_rencontre: datetime
76
+
77
+ @dataclass
78
+ class Idorganismeequipe1Model:
79
+ logo: Any | None = None
80
+
81
+ idOrganismeEquipe1: Idorganismeequipe1Model | None = None
82
+
83
+ @dataclass
84
+ class Idorganismeequipe2Model:
85
+ logo: Any | None = None
86
+
87
+ idOrganismeEquipe2: Idorganismeequipe2Model | None = None
88
+ gsId: GameStatsModel | None = None
89
+
90
+ @dataclass
91
+ class Idengagementequipe1Model:
92
+ nom: str
93
+ id: str
94
+ nomOfficiel: str
95
+ nomUsuel: str
96
+ codeAbrege: str
97
+ logo: Any | None = None
98
+
99
+ idEngagementEquipe1: Idengagementequipe1Model | None = None
100
+
101
+ @dataclass
102
+ class Idengagementequipe2Model:
103
+ nom: str
104
+ id: str
105
+ nomOfficiel: str
106
+ nomUsuel: str
107
+ codeAbrege: str
108
+ logo: Any | None = None
109
+
110
+ idEngagementEquipe2: Idengagementequipe2Model | None = None
111
+
112
+ @dataclass
113
+ class SalleModel:
114
+ id: str
115
+ numero: str
116
+ libelle: str
117
+ libelle2: str
118
+ adresse: str
119
+ adresseComplement: str
120
+
121
+ @dataclass
122
+ class CommuneModel:
123
+ codePostal: str
124
+ libelle: str
125
+
126
+ commune: CommuneModel | None = None
127
+
128
+ @dataclass
129
+ class CartographieModel:
130
+ latitude: float
131
+ longitude: float
132
+
133
+ cartographie: CartographieModel | None = None
134
+
135
+ salle: SalleModel | None = None
136
+
137
+ @dataclass
138
+ class OfficielsitemModel:
139
+ ordre: int
140
+
141
+ @dataclass
142
+ class FonctionModel:
143
+ libelle: str
144
+
145
+ fonction: FonctionModel | None = None
146
+
147
+ @dataclass
148
+ class OfficielModel:
149
+ nom: str
150
+ prenom: str
151
+
152
+ officiel: OfficielModel | None = None
153
+
154
+ officiels: list[OfficielsitemModel] = field(default_factory=list)
155
+
156
+ rencontres: list[RencontresitemModel] = field(default_factory=list)
157
+
158
+ @dataclass
159
+ class EngagementsitemModel:
160
+ id: str
161
+
162
+ @dataclass
163
+ class IdorganismeModel:
164
+ id: str
165
+
166
+ idOrganisme: IdorganismeModel | None = None
167
+
168
+ engagements: list[EngagementsitemModel] = field(default_factory=list)
169
+
170
+ poules: list[PoulesitemModel] = field(default_factory=list)
171
+
172
+ phases: list[PhasesitemModel] = field(default_factory=list)
173
+
174
+ @classmethod
175
+ def from_dict(cls, data: dict) -> GetCompetitionResponse | None:
176
+ """Convert dictionary to CompetitionsModel instance."""
177
+ if not data:
178
+ return None
179
+
180
+ # Handle case where data is not a dictionary
181
+ if not isinstance(data, dict):
182
+ return None
183
+
184
+ # Handle API error responses
185
+ if "errors" in data:
186
+ return None
187
+
188
+ # Extract nested categorie data
189
+ categorie_data = data.get("categorie", {})
190
+ categorie = (
191
+ cls.CategorieModel(
192
+ code=str(categorie_data.get("code", "")),
193
+ ordre=int(categorie_data.get("ordre", 0)),
194
+ )
195
+ if categorie_data
196
+ else None
197
+ )
198
+
199
+ # Extract nested typeCompetitionGenerique data
200
+ type_comp_generique_data = data.get("typeCompetitionGenerique", {})
201
+ type_comp_generique = None
202
+ if type_comp_generique_data:
203
+ logo_data = type_comp_generique_data.get("logo", {})
204
+ logo_tcg = (
205
+ cls.TypecompetitiongeneriqueModel.LogoModel(
206
+ id=str(logo_data.get("id", "")),
207
+ gradient_color=str(logo_data.get("gradient_color", "")),
208
+ )
209
+ if logo_data
210
+ else None
211
+ )
212
+ type_comp_generique = cls.TypecompetitiongeneriqueModel(logo=logo_tcg)
213
+
214
+ # Extract poules data (basic level)
215
+ poules = []
216
+ for poule_data in data.get("poules", []):
217
+ if poule_data:
218
+ poule = cls.PoulesitemModel(
219
+ id=str(poule_data.get("id", "")),
220
+ nom=str(poule_data.get("nom", "")),
221
+ )
222
+ poules.append(poule)
223
+
224
+ # Extract phases data with complete nested structure
225
+ phases = []
226
+ for phase_data in data.get("phases", []):
227
+ if phase_data:
228
+ # Process poules within phases
229
+ phase_poules = []
230
+ for phase_poule_data in phase_data.get("poules", []):
231
+ if phase_poule_data:
232
+ # Process rencontres within phase poules
233
+ rencontres = []
234
+ for rencontre_data in phase_poule_data.get("rencontres", []):
235
+ if rencontre_data:
236
+ # Extract gsId (GameStats) data
237
+ gs_id_data = rencontre_data.get("gsId", {})
238
+ gs_id = (
239
+ GameStatsModel.from_dict(gs_id_data)
240
+ if gs_id_data
241
+ else None
242
+ )
243
+
244
+ # Extract idOrganismeEquipe1 data
245
+ org_equipe1_data = rencontre_data.get(
246
+ "idOrganismeEquipe1", {}
247
+ )
248
+ id_organisme_equipe1 = (
249
+ cls.PhasesitemModel.PoulesitemModel.RencontresitemModel.Idorganismeequipe1Model(
250
+ logo=org_equipe1_data.get("logo")
251
+ )
252
+ if org_equipe1_data
253
+ else None
254
+ )
255
+
256
+ # Extract idOrganismeEquipe2 data
257
+ org_equipe2_data = rencontre_data.get(
258
+ "idOrganismeEquipe2", {}
259
+ )
260
+ id_organisme_equipe2 = (
261
+ cls.PhasesitemModel.PoulesitemModel.RencontresitemModel.Idorganismeequipe2Model(
262
+ logo=org_equipe2_data.get("logo")
263
+ )
264
+ if org_equipe2_data
265
+ else None
266
+ )
267
+
268
+ # Extract idEngagementEquipe1 data
269
+ eng_equipe1_data = rencontre_data.get(
270
+ "idEngagementEquipe1", {}
271
+ )
272
+ id_engagement_equipe1 = (
273
+ cls.PhasesitemModel.PoulesitemModel.RencontresitemModel.Idengagementequipe1Model(
274
+ nom=str(eng_equipe1_data.get("nom", "")),
275
+ id=str(eng_equipe1_data.get("id", "")),
276
+ nomOfficiel=str(
277
+ eng_equipe1_data.get("nomOfficiel", "")
278
+ ),
279
+ nomUsuel=str(
280
+ eng_equipe1_data.get("nomUsuel", "")
281
+ ),
282
+ codeAbrege=str(
283
+ eng_equipe1_data.get("codeAbrege", "")
284
+ ),
285
+ logo=eng_equipe1_data.get("logo"),
286
+ )
287
+ if eng_equipe1_data
288
+ else None
289
+ )
290
+
291
+ # Extract idEngagementEquipe2 data
292
+ eng_equipe2_data = rencontre_data.get(
293
+ "idEngagementEquipe2", {}
294
+ )
295
+ id_engagement_equipe2 = (
296
+ cls.PhasesitemModel.PoulesitemModel.RencontresitemModel.Idengagementequipe2Model(
297
+ nom=str(eng_equipe2_data.get("nom", "")),
298
+ id=str(eng_equipe2_data.get("id", "")),
299
+ nomOfficiel=str(
300
+ eng_equipe2_data.get("nomOfficiel", "")
301
+ ),
302
+ nomUsuel=str(
303
+ eng_equipe2_data.get("nomUsuel", "")
304
+ ),
305
+ codeAbrege=str(
306
+ eng_equipe2_data.get("codeAbrege", "")
307
+ ),
308
+ logo=eng_equipe2_data.get("logo"),
309
+ )
310
+ if eng_equipe2_data
311
+ else None
312
+ )
313
+
314
+ # Extract salle data
315
+ salle_data = rencontre_data.get("salle", {})
316
+ salle = None
317
+ if salle_data:
318
+ salle_commune_data = salle_data.get("commune", {})
319
+ salle_commune = (
320
+ cls.PhasesitemModel.PoulesitemModel.RencontresitemModel.SalleModel.CommuneModel(
321
+ codePostal=str(
322
+ salle_commune_data.get("codePostal", "")
323
+ ),
324
+ libelle=str(
325
+ salle_commune_data.get("libelle", "")
326
+ ),
327
+ )
328
+ if salle_commune_data
329
+ else None
330
+ )
331
+
332
+ salle_cartographie_data = salle_data.get(
333
+ "cartographie", {}
334
+ )
335
+ salle_cartographie = (
336
+ (
337
+ cls.PhasesitemModel.PoulesitemModel.RencontresitemModel.SalleModel.CartographieModel
338
+ )(
339
+ latitude=float(
340
+ salle_cartographie_data.get(
341
+ "latitude", 0.0
342
+ )
343
+ ),
344
+ longitude=float(
345
+ salle_cartographie_data.get(
346
+ "longitude", 0.0
347
+ )
348
+ ),
349
+ )
350
+ if salle_cartographie_data
351
+ else None
352
+ )
353
+
354
+ salle = cls.PhasesitemModel.PoulesitemModel.RencontresitemModel.SalleModel(
355
+ id=str(salle_data.get("id", "")),
356
+ numero=str(salle_data.get("numero", "")),
357
+ libelle=str(salle_data.get("libelle", "")),
358
+ libelle2=str(salle_data.get("libelle2", "")),
359
+ adresse=str(salle_data.get("adresse", "")),
360
+ adresseComplement=str(
361
+ salle_data.get("adresseComplement", "")
362
+ ),
363
+ commune=salle_commune,
364
+ cartographie=salle_cartographie,
365
+ )
366
+
367
+ # Extract officiels data
368
+ officiels = []
369
+ for officiel_data in rencontre_data.get(
370
+ "officiels", []
371
+ ):
372
+ if officiel_data:
373
+ fonction_data = officiel_data.get(
374
+ "fonction", {}
375
+ )
376
+ fonction = (
377
+ (
378
+ cls.PhasesitemModel.PoulesitemModel.RencontresitemModel.OfficielsitemModel.FonctionModel
379
+ )(
380
+ libelle=str(
381
+ fonction_data.get("libelle", "")
382
+ ),
383
+ )
384
+ if fonction_data
385
+ else None
386
+ )
387
+
388
+ officiel_person_data = officiel_data.get(
389
+ "officiel", {}
390
+ )
391
+ officiel_person = (
392
+ (
393
+ cls.PhasesitemModel.PoulesitemModel.RencontresitemModel.OfficielsitemModel.OfficielModel
394
+ )(
395
+ nom=str(
396
+ officiel_person_data.get("nom", "")
397
+ ),
398
+ prenom=str(
399
+ officiel_person_data.get(
400
+ "prenom", ""
401
+ )
402
+ ),
403
+ )
404
+ if officiel_person_data
405
+ else None
406
+ )
407
+
408
+ officiel = (
409
+ cls.PhasesitemModel.PoulesitemModel.RencontresitemModel.OfficielsitemModel
410
+ )(
411
+ ordre=int(officiel_data.get("ordre") or 0),
412
+ fonction=fonction,
413
+ officiel=officiel_person,
414
+ )
415
+ officiels.append(officiel)
416
+
417
+ # Create the rencontre object with proper date handling
418
+ date_str = rencontre_data.get(
419
+ "date_rencontre", "1970-01-01T00:00:00"
420
+ )
421
+ try:
422
+ date_rencontre = datetime.fromisoformat(
423
+ date_str.replace("Z", "+00:00")
424
+ )
425
+ except (ValueError, AttributeError):
426
+ date_rencontre = datetime.fromisoformat(
427
+ "1970-01-01T00:00:00"
428
+ )
429
+
430
+ rencontre = cls.PhasesitemModel.PoulesitemModel.RencontresitemModel(
431
+ id=str(rencontre_data.get("id", "")),
432
+ numero=str(rencontre_data.get("numero", "")),
433
+ numeroJournee=str(
434
+ rencontre_data.get("numeroJournee", "")
435
+ ),
436
+ idPoule=str(rencontre_data.get("idPoule", "")),
437
+ competitionId=str(
438
+ rencontre_data.get("competitionId", "")
439
+ ),
440
+ resultatEquipe1=str(
441
+ rencontre_data.get("resultatEquipe1", "")
442
+ ),
443
+ resultatEquipe2=str(
444
+ rencontre_data.get("resultatEquipe2", "")
445
+ ),
446
+ joue=int(rencontre_data.get("joue", 0)),
447
+ nomEquipe1=str(
448
+ rencontre_data.get("nomEquipe1", "")
449
+ ),
450
+ nomEquipe2=str(
451
+ rencontre_data.get("nomEquipe2", "")
452
+ ),
453
+ date_rencontre=date_rencontre,
454
+ idOrganismeEquipe1=id_organisme_equipe1,
455
+ idOrganismeEquipe2=id_organisme_equipe2,
456
+ gsId=gs_id,
457
+ idEngagementEquipe1=id_engagement_equipe1,
458
+ idEngagementEquipe2=id_engagement_equipe2,
459
+ salle=salle,
460
+ officiels=officiels,
461
+ )
462
+ rencontres.append(rencontre)
463
+
464
+ # Extract engagements within phase poules
465
+ engagements = []
466
+ for engagement_data in phase_poule_data.get("engagements", []):
467
+ if engagement_data:
468
+ id_organisme_data = engagement_data.get(
469
+ "idOrganisme", {}
470
+ )
471
+ id_organisme = (
472
+ cls.PhasesitemModel.PoulesitemModel.EngagementsitemModel.IdorganismeModel(
473
+ id=str(id_organisme_data.get("id", "")),
474
+ )
475
+ if id_organisme_data
476
+ else None
477
+ )
478
+
479
+ engagement = cls.PhasesitemModel.PoulesitemModel.EngagementsitemModel(
480
+ id=str(engagement_data.get("id", "")),
481
+ idOrganisme=id_organisme,
482
+ )
483
+ engagements.append(engagement)
484
+
485
+ phase_poule = cls.PhasesitemModel.PoulesitemModel(
486
+ id=str(phase_poule_data.get("id", "")),
487
+ nom=str(phase_poule_data.get("nom", "")),
488
+ rencontres=rencontres,
489
+ engagements=engagements,
490
+ )
491
+ phase_poules.append(phase_poule)
492
+
493
+ phase = cls.PhasesitemModel(
494
+ id=str(phase_data.get("id", "")),
495
+ nom=str(phase_data.get("nom", "")),
496
+ liveStat=int(phase_data.get("liveStat", 0)),
497
+ phase_code=str(phase_data.get("phase_code", "")),
498
+ poules=phase_poules,
499
+ )
500
+ phases.append(phase)
501
+
502
+ return cls(
503
+ id=str(data.get("id", "")),
504
+ nom=str(data.get("nom", "")),
505
+ sexe=str(data.get("sexe", "")),
506
+ saison=str(data.get("saison", "")),
507
+ code=str(data.get("code", "")),
508
+ typeCompetition=str(data.get("typeCompetition", "")),
509
+ liveStat=int(data.get("liveStat", 0)),
510
+ competition_origine=str(data.get("competition_origine", "")),
511
+ competition_origine_nom=str(data.get("competition_origine_nom", "")),
512
+ publicationInternet=str(data.get("publicationInternet", "")),
513
+ categorie=categorie,
514
+ typeCompetitionGenerique=type_comp_generique,
515
+ logo=data.get("logo"),
516
+ id_competition_pere=(
517
+ int(data["idCompetitionPere"])
518
+ if data.get("idCompetitionPere")
519
+ else None
520
+ ),
521
+ poules=poules,
522
+ phases=phases,
523
+ )