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,28 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+ from uuid import UUID
6
+
7
+ from ..utils.converter_utils import from_str, from_uuid
8
+
9
+
10
+ @dataclass
11
+ class Logo:
12
+ id: UUID | None = None
13
+ gradient_color: str | None = None
14
+
15
+ @staticmethod
16
+ def from_dict(obj: Any) -> Logo:
17
+ assert isinstance(obj, dict)
18
+ id = from_uuid(obj, "id")
19
+ gradient_color = from_str(obj, "gradient_color")
20
+ return Logo(id=id, gradient_color=gradient_color)
21
+
22
+ def to_dict(self) -> dict:
23
+ result: dict = {}
24
+ if self.id is not None:
25
+ result["id"] = str(self.id)
26
+ if self.gradient_color is not None:
27
+ result["gradient_color"] = self.gradient_color
28
+ return result
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from ..utils.converter_utils import from_list
7
+ from .multi_search_query import MultiSearchQuery
8
+
9
+
10
+ @dataclass
11
+ class MultiSearchQueries:
12
+ queries: list[MultiSearchQuery] | None = None
13
+
14
+ @staticmethod
15
+ def from_dict(obj: Any) -> MultiSearchQueries:
16
+ assert isinstance(obj, dict)
17
+ queries = from_list(MultiSearchQuery.from_dict, obj, "queries")
18
+ return MultiSearchQueries(queries=queries)
19
+
20
+ def to_dict(self) -> dict:
21
+ result: dict = {}
22
+ if self.queries is not None:
23
+ result["queries"] = [q.to_dict() for q in self.queries]
24
+ return result
@@ -0,0 +1,96 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Any
5
+
6
+ from ..utils.converter_utils import (
7
+ from_int,
8
+ from_list,
9
+ from_str,
10
+ )
11
+ from .facet_distribution import FacetDistribution
12
+ from .facet_stats import FacetStats
13
+ from .hit import Hit
14
+ from .multi_search_results import MultiSearchResult
15
+
16
+
17
+ @dataclass
18
+ class MultiSearchQuery:
19
+ index_uid: str | None = None
20
+ q: str | None = None
21
+ facets: list[str] | None = None
22
+ limit: int | None = 10
23
+ offset: int | None = 0
24
+ filter: list[Any] | None = None
25
+ sort: list[Any] | None = None
26
+ lower_q: str | None = field(init=False, default=None, repr=False)
27
+
28
+ def __post_init__(self) -> None:
29
+ self.lower_q = self.q.lower() if self.q else None
30
+
31
+ @staticmethod
32
+ def from_dict(obj: Any) -> MultiSearchQuery:
33
+ assert isinstance(obj, dict)
34
+ index_uid = from_str(obj, "indexUid")
35
+ q = from_str(obj, "q")
36
+ facets = from_list(str, obj, "facets")
37
+ limit = from_int(obj, "limit")
38
+ offset = from_int(obj, "offset")
39
+ filter = from_list(lambda x: x, obj, "filter")
40
+ sort = from_list(lambda x: x, obj, "sort")
41
+ return MultiSearchQuery(
42
+ index_uid=index_uid,
43
+ q=q,
44
+ facets=facets,
45
+ limit=limit,
46
+ offset=offset,
47
+ filter=filter,
48
+ sort=sort,
49
+ )
50
+
51
+ def to_dict(self) -> dict:
52
+ result: dict = {}
53
+ if self.index_uid is not None:
54
+ result["indexUid"] = self.index_uid
55
+ if self.q is not None:
56
+ result["q"] = self.q
57
+ if self.facets is not None:
58
+ result["facets"] = self.facets
59
+ if self.limit is not None:
60
+ result["limit"] = self.limit
61
+ if self.offset is not None:
62
+ result["offset"] = self.offset
63
+ if self.filter is not None:
64
+ result["filter"] = self.filter
65
+ if self.sort is not None:
66
+ result["sort"] = self.sort
67
+ return result
68
+
69
+ def is_valid_result(self, result: MultiSearchResult):
70
+ return result and (
71
+ isinstance(result, MultiSearchResult)
72
+ and (
73
+ result.facet_distribution is None
74
+ or isinstance(result.facet_distribution, FacetDistribution)
75
+ )
76
+ and (
77
+ result.facet_stats is None or isinstance(result.facet_stats, FacetStats)
78
+ )
79
+ )
80
+
81
+ def is_valid_hit(self, _hit: Hit):
82
+ return True
83
+
84
+ def filter_result(self, result: MultiSearchResult) -> MultiSearchResult:
85
+ if self.lower_q and result.hits:
86
+ # ⚡ Bolt optimization: Replace O(n²) list.remove in a loop with O(n) list comprehension for filtering hits.
87
+ valid_hits = [
88
+ hit for hit in result.hits if hit.is_valid_for_query(self.lower_q)
89
+ ]
90
+
91
+ if len(valid_hits) < len(result.hits):
92
+ if result.estimated_total_hits is not None:
93
+ result.estimated_total_hits -= len(result.hits) - len(valid_hits)
94
+
95
+ result.hits = valid_hits
96
+ return result
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+
3
+ from .competitions_facet_distribution import CompetitionsFacetDistribution
4
+ from .competitions_facet_stats import CompetitionsFacetStats
5
+ from .competitions_hit import CompetitionsHit
6
+ from .multi_search_results import MultiSearchResult
7
+
8
+
9
+ class CompetitionsMultiSearchResult(
10
+ MultiSearchResult[
11
+ CompetitionsHit, CompetitionsFacetDistribution, CompetitionsFacetStats
12
+ ]
13
+ ):
14
+ """MultiSearchResult for Competitions."""
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+
3
+ from .engagements_facet_distribution import EngagementsFacetDistribution
4
+ from .engagements_facet_stats import EngagementsFacetStats
5
+ from .engagements_hit import EngagementsHit
6
+ from .multi_search_results import MultiSearchResult
7
+
8
+
9
+ class EngagementsMultiSearchResult(
10
+ MultiSearchResult[
11
+ EngagementsHit, EngagementsFacetDistribution, EngagementsFacetStats
12
+ ]
13
+ ):
14
+ """MultiSearchResult for Engagements."""
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from .formations_facet_distribution import FormationsFacetDistribution
4
+ from .formations_facet_stats import FormationsFacetStats
5
+ from .formations_hit import FormationsHit
6
+ from .multi_search_results import MultiSearchResult
7
+
8
+
9
+ class FormationsMultiSearchResult(
10
+ MultiSearchResult[FormationsHit, FormationsFacetDistribution, FormationsFacetStats]
11
+ ):
12
+ """MultiSearchResult for Formations."""
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from .multi_search_results import MultiSearchResult
4
+ from .organismes_facet_distribution import OrganismesFacetDistribution
5
+ from .organismes_facet_stats import OrganismesFacetStats
6
+ from .organismes_hit import OrganismesHit
7
+
8
+
9
+ class OrganismesMultiSearchResult(
10
+ MultiSearchResult[OrganismesHit, OrganismesFacetDistribution, OrganismesFacetStats]
11
+ ):
12
+ """MultiSearchResult for Organismes."""
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from .multi_search_results import MultiSearchResult
4
+ from .pratiques_facet_distribution import PratiquesFacetDistribution
5
+ from .pratiques_facet_stats import PratiquesFacetStats
6
+ from .pratiques_hit import PratiquesHit
7
+
8
+
9
+ class PratiquesMultiSearchResult(
10
+ MultiSearchResult[PratiquesHit, PratiquesFacetDistribution, PratiquesFacetStats]
11
+ ):
12
+ """MultiSearchResult for Pratiques."""
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from .multi_search_results import MultiSearchResult
4
+ from .rencontres_facet_distribution import RencontresFacetDistribution
5
+ from .rencontres_facet_stats import RencontresFacetStats
6
+ from .rencontres_hit import RencontresHit
7
+
8
+
9
+ class RencontresMultiSearchResult(
10
+ MultiSearchResult[RencontresHit, RencontresFacetDistribution, RencontresFacetStats]
11
+ ):
12
+ """MultiSearchResult for Rencontres."""
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from .multi_search_results import MultiSearchResult
4
+ from .salles_facet_distribution import SallesFacetDistribution
5
+ from .salles_facet_stats import SallesFacetStats
6
+ from .salles_hit import SallesHit
7
+
8
+
9
+ class SallesMultiSearchResult(
10
+ MultiSearchResult[SallesHit, SallesFacetDistribution, SallesFacetStats]
11
+ ):
12
+ """MultiSearchResult for Salles."""
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from .multi_search_results import MultiSearchResult
4
+ from .terrains_facet_distribution import TerrainsFacetDistribution
5
+ from .terrains_facet_stats import TerrainsFacetStats
6
+ from .terrains_hit import TerrainsHit
7
+
8
+
9
+ class TerrainsMultiSearchResult(
10
+ MultiSearchResult[TerrainsHit, TerrainsFacetDistribution, TerrainsFacetStats]
11
+ ):
12
+ """MultiSearchResult for Terrains."""
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from .multi_search_results import MultiSearchResult
4
+ from .tournois_facet_distribution import TournoisFacetDistribution
5
+ from .tournois_facet_stats import TournoisFacetStats
6
+ from .tournois_hit import TournoisHit
7
+
8
+
9
+ class TournoisMultiSearchResult(
10
+ MultiSearchResult[TournoisHit, TournoisFacetDistribution, TournoisFacetStats]
11
+ ):
12
+ """MultiSearchResult for Tournois."""
@@ -0,0 +1,103 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any, Generic, TypeVar, get_args
5
+
6
+ from ..utils.converter_utils import (
7
+ from_int,
8
+ from_list,
9
+ from_str,
10
+ )
11
+ from .facet_distribution import FacetDistribution
12
+ from .facet_stats import FacetStats
13
+ from .hit import Hit
14
+
15
+ HitType = TypeVar("HitType", bound=Hit)
16
+ FacetDistributionType = TypeVar("FacetDistributionType", bound=FacetDistribution)
17
+ FacetStatsType = TypeVar("FacetStatsType", bound=FacetStats)
18
+
19
+
20
+ @dataclass
21
+ class MultiSearchResult(Generic[HitType, FacetDistributionType, FacetStatsType]):
22
+ index_uid: str | None = None
23
+ hits: list[HitType] | None = None
24
+ query: str | None = None
25
+ processing_time_ms: int | None = None
26
+ limit: int | None = None
27
+ offset: int | None = None
28
+ estimated_total_hits: int | None = None
29
+ facet_distribution: FacetDistributionType | None = None
30
+ facet_stats: FacetStatsType | None = None
31
+
32
+ @classmethod
33
+ def from_dict(
34
+ cls,
35
+ obj: Any,
36
+ ) -> MultiSearchResult[HitType, FacetDistributionType, FacetStatsType]:
37
+ """
38
+ Parse dict into the concrete MultiSearchResult subclass.
39
+ Types are extracted from the class's generic parameters.
40
+ """
41
+ assert isinstance(obj, dict)
42
+
43
+ # Extract generic type arguments from class definition
44
+ # e.g., OrganismesMultiSearchResult inherits from
45
+ # MultiSearchResult[OrganismesHit, OrganismesFacetDistribution, OrganismesFacetStats]
46
+ orig_bases = getattr(cls, "__orig_bases__", ())
47
+ if not orig_bases:
48
+ raise TypeError(f"{cls.__name__} must be a generic subclass")
49
+ type_args = get_args(orig_bases[0])
50
+ hit_type: type[HitType] = type_args[0]
51
+ facet_distribution_type: type[FacetDistributionType] = type_args[1]
52
+ facet_stats_type: type[FacetStatsType] = type_args[2]
53
+
54
+ index_uid = from_str(obj, "indexUid")
55
+ hits = from_list(hit_type.from_dict, obj, "hits")
56
+ query = from_str(obj, "query")
57
+ processing_time_ms = from_int(obj, "processingTimeMs")
58
+ limit = from_int(obj, "limit")
59
+ offset = from_int(obj, "offset")
60
+ estimated_total_hits = from_int(obj, "estimatedTotalHits")
61
+ fd_val = obj.get("facetDistribution")
62
+ facet_distribution = (
63
+ facet_distribution_type.from_dict(fd_val)
64
+ if isinstance(fd_val, dict)
65
+ else None
66
+ )
67
+ fs_val = obj.get("facetStats")
68
+ facet_stats = (
69
+ facet_stats_type.from_dict(fs_val) if isinstance(fs_val, dict) else None
70
+ )
71
+ return cls(
72
+ index_uid=index_uid,
73
+ hits=hits, # type: ignore[arg-type] # from_dict returns Hit base type
74
+ query=query,
75
+ processing_time_ms=processing_time_ms,
76
+ limit=limit,
77
+ offset=offset,
78
+ estimated_total_hits=estimated_total_hits,
79
+ facet_distribution=facet_distribution, # type: ignore[arg-type] # dynamic type from generics
80
+ facet_stats=facet_stats, # type: ignore[arg-type] # dynamic type from generics
81
+ )
82
+
83
+ def to_dict(self) -> dict:
84
+ result: dict = {}
85
+ if self.index_uid is not None:
86
+ result["indexUid"] = self.index_uid
87
+ if self.hits is not None:
88
+ result["hits"] = [hit.to_dict() for hit in self.hits]
89
+ if self.query is not None:
90
+ result["query"] = self.query
91
+ if self.processing_time_ms is not None:
92
+ result["processingTimeMs"] = self.processing_time_ms
93
+ if self.limit is not None:
94
+ result["limit"] = self.limit
95
+ if self.offset is not None:
96
+ result["offset"] = self.offset
97
+ if self.estimated_total_hits is not None:
98
+ result["estimatedTotalHits"] = self.estimated_total_hits
99
+ if self.facet_distribution is not None:
100
+ result["facetDistribution"] = self.facet_distribution.to_dict()
101
+ if self.facet_stats is not None:
102
+ result["facetStats"] = self.facet_stats.to_dict()
103
+ return result
@@ -0,0 +1,96 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable
4
+ from dataclasses import dataclass
5
+ from typing import Any
6
+
7
+ from ..config import (
8
+ MEILISEARCH_INDEX_COMPETITIONS,
9
+ MEILISEARCH_INDEX_ENGAGEMENTS,
10
+ MEILISEARCH_INDEX_FORMATIONS,
11
+ MEILISEARCH_INDEX_GALERIES,
12
+ MEILISEARCH_INDEX_NEWS,
13
+ MEILISEARCH_INDEX_ORGANISMES,
14
+ MEILISEARCH_INDEX_PRATIQUES,
15
+ MEILISEARCH_INDEX_RENCONTRES,
16
+ MEILISEARCH_INDEX_RSS,
17
+ MEILISEARCH_INDEX_SALLES,
18
+ MEILISEARCH_INDEX_TERRAINS,
19
+ MEILISEARCH_INDEX_TOURNOIS,
20
+ MEILISEARCH_INDEX_UIDS,
21
+ MEILISEARCH_INDEX_YOUTUBE_VIDEOS,
22
+ )
23
+ from .generic_search import (
24
+ GaleriesMultiSearchResult,
25
+ NewsMultiSearchResult,
26
+ RssMultiSearchResult,
27
+ YoutubeVideosMultiSearchResult,
28
+ )
29
+ from .multi_search_result_competitions import CompetitionsMultiSearchResult
30
+ from .multi_search_result_engagements import EngagementsMultiSearchResult
31
+ from .multi_search_result_formations import FormationsMultiSearchResult
32
+ from .multi_search_result_organismes import OrganismesMultiSearchResult
33
+ from .multi_search_result_pratiques import PratiquesMultiSearchResult
34
+ from .multi_search_result_rencontres import RencontresMultiSearchResult
35
+ from .multi_search_result_salles import SallesMultiSearchResult
36
+ from .multi_search_result_terrains import TerrainsMultiSearchResult
37
+ from .multi_search_result_tournois import TournoisMultiSearchResult
38
+ from .multi_search_results import MultiSearchResult
39
+
40
+ # Re-export for backward compatibility
41
+ index_uids = MEILISEARCH_INDEX_UIDS
42
+
43
+ index_uids_converters: dict[str, Callable[[Any], MultiSearchResult[Any, Any, Any]]] = {
44
+ MEILISEARCH_INDEX_ORGANISMES: OrganismesMultiSearchResult.from_dict,
45
+ MEILISEARCH_INDEX_RENCONTRES: RencontresMultiSearchResult.from_dict,
46
+ MEILISEARCH_INDEX_TERRAINS: TerrainsMultiSearchResult.from_dict,
47
+ MEILISEARCH_INDEX_SALLES: SallesMultiSearchResult.from_dict,
48
+ MEILISEARCH_INDEX_TOURNOIS: TournoisMultiSearchResult.from_dict,
49
+ MEILISEARCH_INDEX_COMPETITIONS: CompetitionsMultiSearchResult.from_dict,
50
+ MEILISEARCH_INDEX_PRATIQUES: PratiquesMultiSearchResult.from_dict,
51
+ MEILISEARCH_INDEX_ENGAGEMENTS: EngagementsMultiSearchResult.from_dict,
52
+ MEILISEARCH_INDEX_FORMATIONS: FormationsMultiSearchResult.from_dict,
53
+ MEILISEARCH_INDEX_NEWS: NewsMultiSearchResult.from_dict,
54
+ MEILISEARCH_INDEX_YOUTUBE_VIDEOS: YoutubeVideosMultiSearchResult.from_dict,
55
+ MEILISEARCH_INDEX_RSS: RssMultiSearchResult.from_dict,
56
+ MEILISEARCH_INDEX_GALERIES: GaleriesMultiSearchResult.from_dict,
57
+ }
58
+
59
+
60
+ def result_from_list(s: list[Any]) -> list[MultiSearchResult[Any, Any, Any]]:
61
+ results: list[MultiSearchResult[Any, Any, Any]] = []
62
+
63
+ if s:
64
+ for element in s:
65
+ try:
66
+ index_uid = element["indexUid"]
67
+ from_dict_func = index_uids_converters[index_uid]
68
+ result = from_dict_func(element)
69
+ results.append(result)
70
+ except (KeyError, TypeError, ValueError, AssertionError):
71
+ # Skip invalid or unsupported index results
72
+ pass
73
+
74
+ return results
75
+
76
+
77
+ @dataclass
78
+ class MultiSearchResults:
79
+ results: list[MultiSearchResult[Any, Any, Any]] | None = None
80
+
81
+ @staticmethod
82
+ def from_dict(obj: Any) -> MultiSearchResults:
83
+ assert isinstance(obj, dict)
84
+ results_raw = obj.get("results")
85
+ results = result_from_list(results_raw) if results_raw is not None else None
86
+ return MultiSearchResults(results=results)
87
+
88
+ def to_dict(self) -> dict:
89
+ result: dict = {}
90
+ if self.results is not None:
91
+ result["results"] = [r.to_dict() for r in self.results]
92
+ return result
93
+
94
+
95
+ def multi_search_results_from_dict(s: Any) -> MultiSearchResults:
96
+ return MultiSearchResults.from_dict(s)
@@ -0,0 +1,57 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any
6
+
7
+ from ..utils.converter_utils import (
8
+ from_bool,
9
+ from_datetime,
10
+ from_enum,
11
+ from_str,
12
+ )
13
+ from .code import Code
14
+
15
+
16
+ @dataclass
17
+ class NatureSol:
18
+ code: Code | None = None
19
+ date_created: datetime | None = None
20
+ date_updated: datetime | None = None
21
+ id: str | None = None
22
+ libelle: str | None = None
23
+ terrain: bool | None = None
24
+
25
+ @staticmethod
26
+ def from_dict(obj: Any) -> NatureSol:
27
+ assert isinstance(obj, dict)
28
+ code = from_enum(Code, obj, "code")
29
+ date_created = from_datetime(obj, "date_created")
30
+ date_updated = from_datetime(obj, "date_updated")
31
+ id = from_str(obj, "id")
32
+ libelle = from_str(obj, "libelle")
33
+ terrain = from_bool(obj, "terrain")
34
+ return NatureSol(
35
+ code=code,
36
+ date_created=date_created,
37
+ date_updated=date_updated,
38
+ id=id,
39
+ libelle=libelle,
40
+ terrain=terrain,
41
+ )
42
+
43
+ def to_dict(self) -> dict:
44
+ result: dict = {}
45
+ if self.code is not None:
46
+ result["code"] = self.code.value
47
+ if self.date_created is not None:
48
+ result["date_created"] = self.date_created.isoformat()
49
+ if self.date_updated is not None:
50
+ result["date_updated"] = self.date_updated.isoformat()
51
+ if self.id is not None:
52
+ result["id"] = self.id
53
+ if self.libelle is not None:
54
+ result["libelle"] = self.libelle
55
+ if self.terrain is not None:
56
+ result["terrain"] = str(self.terrain).lower()
57
+ return result
@@ -0,0 +1,10 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Niveau(Enum):
5
+ DÉPARTEMENTAL = "Départemental"
6
+ HANDIBASKET = "Handibasket"
7
+ INTERNATIONAL = "International"
8
+ NATIONAL = "National"
9
+ PRO = "Pro"
10
+ RÉGIONAL = "Régional"
@@ -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_int
7
+
8
+
9
+ @dataclass
10
+ class NiveauClass:
11
+ départemental: int | None = None
12
+ régional: int | None = None
13
+
14
+ @staticmethod
15
+ def from_dict(obj: Any) -> NiveauClass:
16
+ assert isinstance(obj, dict)
17
+ départemental = from_int(obj, "Départemental")
18
+ régional = from_int(obj, "Régional")
19
+ return NiveauClass(départemental=départemental, régional=régional)
20
+
21
+ def to_dict(self) -> dict:
22
+ result: dict = {}
23
+ if self.départemental is not None:
24
+ result["Départemental"] = self.départemental
25
+ if self.régional is not None:
26
+ result["Régional"] = self.régional
27
+ return result