ffbb-data-client 2.4.29__tar.gz → 2.4.31__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (403) hide show
  1. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/PKG-INFO +1 -1
  2. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/api.py +279 -5
  3. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/helpers/meilisearch_client_extension.py +11 -4
  4. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client.egg-info/PKG-INFO +1 -1
  5. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client.egg-info/SOURCES.txt +1 -0
  6. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client.egg-info/scm_file_list.json +1 -0
  7. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client.egg-info/scm_version.json +2 -2
  8. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/helpers/test_meilisearch_client_extension_recursive_pagination.py +9 -0
  9. ffbb_data_client-2.4.31/tests/unit/test_314_api_endpoints.py +144 -0
  10. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.agents/rules/antigravity-rtk-rules.md +0 -0
  11. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.coveragerc +0 -0
  12. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.gitattributes +0 -0
  13. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/FUNDING.yml +0 -0
  14. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  15. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  16. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  17. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/dependabot.yml +0 -0
  18. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/scripts/ai-pr-reviewer.cjs +0 -0
  19. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/scripts/check_wrapper_parity.py +0 -0
  20. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/workflows/ai-pr-reviewer.yml +0 -0
  21. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/workflows/check_wrapper_parity.yml +0 -0
  22. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/workflows/ci.yml +0 -0
  23. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/workflows/codeql.yml +0 -0
  24. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/workflows/deploy-pages.yml +0 -0
  25. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/workflows/keep-ffbb-api-discovery-alive.yml +0 -0
  26. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/workflows/publish.yml +0 -0
  27. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/workflows/release-after-discovery-merge.yml +0 -0
  28. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.github/workflows/update-ffbb-api-discovery.yml +0 -0
  29. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.gitignore +0 -0
  30. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.isort.cfg +0 -0
  31. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.jules/bolt.md +0 -0
  32. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.omc/skills/codeql-security-hardening-expertise.md +0 -0
  33. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.omc/skills/pypi-immutable-release-workflow.md +0 -0
  34. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.omc/skills/terminal-output-hygiene-expertise.md +0 -0
  35. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.pre-commit-config.yaml +0 -0
  36. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/.readthedocs.yml +0 -0
  37. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/AGENTS.md +0 -0
  38. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/AUTHORS.rst +0 -0
  39. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/CHANGELOG.md +0 -0
  40. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/CODE_OF_CONDUCT.md +0 -0
  41. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/CONTRIBUTING.rst +0 -0
  42. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/DESIGN.md +0 -0
  43. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/Dockerfile +0 -0
  44. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/LICENSE.txt +0 -0
  45. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/LOCAL_CI_GUIDE.md +0 -0
  46. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/README.md +0 -0
  47. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/RELEASE_NOTES.md +0 -0
  48. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/SECURITY.md +0 -0
  49. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/data/api.ffbb.app.json +0 -0
  50. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/data/api_update_summary.md +0 -0
  51. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/data/collections.json +0 -0
  52. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/data/endpoint_discovery.json +0 -0
  53. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/data/field_dictionary.json +0 -0
  54. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/data/indexes.json +0 -0
  55. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/data/meilisearch-prod.ffbb.app.json +0 -0
  56. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/data/openapi.json +0 -0
  57. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/data/openapi_full.json +0 -0
  58. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/data/permission_drift_summary.md +0 -0
  59. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/data/permission_matrix.json +0 -0
  60. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/data/type_discovery_corrections.json +0 -0
  61. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/Makefile +0 -0
  62. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/_static/.gitignore +0 -0
  63. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/architecture.rst +0 -0
  64. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/authors.rst +0 -0
  65. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/changelog.rst +0 -0
  66. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/conf.py +0 -0
  67. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/contributing.rst +0 -0
  68. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/data_dictionary.rst +0 -0
  69. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/examples.rst +0 -0
  70. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/index.rst +0 -0
  71. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/license.rst +0 -0
  72. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/migration.rst +0 -0
  73. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/readme.rst +0 -0
  74. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/requirements.txt +0 -0
  75. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/test_strategy.md +0 -0
  76. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/docs/testing_conventions.md +0 -0
  77. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/examples/README.md +0 -0
  78. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/examples/complete_usage_example.py +0 -0
  79. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/examples/quick_start.py +0 -0
  80. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/examples/team_ranking_analysis.py +0 -0
  81. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/pyproject.toml +0 -0
  82. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/run-ci-locally.sh +0 -0
  83. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/scripts/benchmark_concurrent_pagination.py +0 -0
  84. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/scripts/benchmark_search_organisme.py +0 -0
  85. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/scripts/discover_endpoints.py +0 -0
  86. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/scripts/discover_permissions.py +0 -0
  87. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/scripts/discover_types.py +0 -0
  88. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/setup.cfg +0 -0
  89. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/setup.py +0 -0
  90. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/__init__.py +0 -0
  91. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/__init__.py +0 -0
  92. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/_helpers.py +0 -0
  93. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/_mixins/__init__.py +0 -0
  94. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/_mixins/competition.py +0 -0
  95. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/_mixins/external.py +0 -0
  96. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/_mixins/getters.py +0 -0
  97. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/_mixins/list_methods.py +0 -0
  98. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/_mixins/organisme.py +0 -0
  99. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/_rest_facade.py +0 -0
  100. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/_search_facade.py +0 -0
  101. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/api_ffbb_app_client.py +0 -0
  102. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/ffbb_data_client.py +0 -0
  103. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/meilisearch_client.py +0 -0
  104. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/clients/meilisearch_ffbb_client.py +0 -0
  105. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/config.py +0 -0
  106. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/data/__init__.py +0 -0
  107. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/data/collections.json +0 -0
  108. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/data/endpoint_discovery.json +0 -0
  109. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/data/field_dictionary.json +0 -0
  110. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/data/indexes.json +0 -0
  111. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/data/openapi.json +0 -0
  112. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/data/permission_matrix.json +0 -0
  113. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/exceptions.py +0 -0
  114. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/helpers/__init__.py +0 -0
  115. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/helpers/http_requests_helper.py +0 -0
  116. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/helpers/http_requests_utils.py +0 -0
  117. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/helpers/multi_search_query_helper.py +0 -0
  118. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/helpers/normalization.py +0 -0
  119. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/__init__.py +0 -0
  120. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/affiche.py +0 -0
  121. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/cartographie.py +0 -0
  122. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/categorie.py +0 -0
  123. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/categorie_type.py +0 -0
  124. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/clock.py +0 -0
  125. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/club_contacts.py +0 -0
  126. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/code.py +0 -0
  127. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/commune.py +0 -0
  128. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competition_fields.py +0 -0
  129. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competition_id.py +0 -0
  130. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competition_id_categorie.py +0 -0
  131. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competition_id_sexe.py +0 -0
  132. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competition_id_type_competition.py +0 -0
  133. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competition_id_type_competition_generique.py +0 -0
  134. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competition_origine.py +0 -0
  135. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competition_origine_categorie.py +0 -0
  136. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competition_origine_type_competition.py +0 -0
  137. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competition_origine_type_competition_generique.py +0 -0
  138. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competition_type.py +0 -0
  139. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competitions_facet_distribution.py +0 -0
  140. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competitions_facet_stats.py +0 -0
  141. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competitions_hit.py +0 -0
  142. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competitions_multi_search_query.py +0 -0
  143. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/competitions_query.py +0 -0
  144. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/configuration_models.py +0 -0
  145. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/contact_info.py +0 -0
  146. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/content_multi_search_query.py +0 -0
  147. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/coordonnees.py +0 -0
  148. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/coordonnees_type.py +0 -0
  149. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/document_flyer.py +0 -0
  150. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/document_flyer_type.py +0 -0
  151. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/engagement_contacts.py +0 -0
  152. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/engagements_facet_distribution.py +0 -0
  153. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/engagements_facet_stats.py +0 -0
  154. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/engagements_hit.py +0 -0
  155. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/engagements_multi_search_query.py +0 -0
  156. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/etat.py +0 -0
  157. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/external_competition_id.py +0 -0
  158. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/external_id.py +0 -0
  159. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/facet_distribution.py +0 -0
  160. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/facet_stats.py +0 -0
  161. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/field_set.py +0 -0
  162. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/folder.py +0 -0
  163. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/formation_session.py +0 -0
  164. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/formations_facet_distribution.py +0 -0
  165. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/formations_facet_stats.py +0 -0
  166. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/formations_hit.py +0 -0
  167. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/formations_multi_search_query.py +0 -0
  168. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/game_stats_model.py +0 -0
  169. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/game_stats_models.py +0 -0
  170. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/generic_search.py +0 -0
  171. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/geo.py +0 -0
  172. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/geo_sort_order.py +0 -0
  173. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_commune_response.py +0 -0
  174. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_competition_response.py +0 -0
  175. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_configuration_response.py +0 -0
  176. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_engagement_response.py +0 -0
  177. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_entraineur_response.py +0 -0
  178. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_formation_response.py +0 -0
  179. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_officiel_response.py +0 -0
  180. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_organisme_response.py +0 -0
  181. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_poule_response.py +0 -0
  182. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_pratique_response.py +0 -0
  183. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_rencontre_response.py +0 -0
  184. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_saisons_response.py +0 -0
  185. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_salle_response.py +0 -0
  186. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_terrain_response.py +0 -0
  187. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/get_tournoi_response.py +0 -0
  188. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/gradient_color.py +0 -0
  189. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/hit.py +0 -0
  190. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/id_engagement_equipe.py +0 -0
  191. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/id_organisme_equipe.py +0 -0
  192. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/id_organisme_equipe1_logo.py +0 -0
  193. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/id_poule.py +0 -0
  194. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/jour.py +0 -0
  195. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/label.py +0 -0
  196. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/labellisation.py +0 -0
  197. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/live.py +0 -0
  198. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/lives.py +0 -0
  199. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/logo.py +0 -0
  200. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_queries.py +0 -0
  201. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_query.py +0 -0
  202. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_result_competitions.py +0 -0
  203. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_result_engagements.py +0 -0
  204. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_result_formations.py +0 -0
  205. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_result_organismes.py +0 -0
  206. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_result_pratiques.py +0 -0
  207. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_result_rencontres.py +0 -0
  208. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_result_salles.py +0 -0
  209. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_result_terrains.py +0 -0
  210. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_result_tournois.py +0 -0
  211. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_results.py +0 -0
  212. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/multi_search_results_class.py +0 -0
  213. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/nature_sol.py +0 -0
  214. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/niveau.py +0 -0
  215. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/niveau_class.py +0 -0
  216. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/niveau_extractor.py +0 -0
  217. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/niveau_info.py +0 -0
  218. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/niveau_models.py +0 -0
  219. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/niveau_type.py +0 -0
  220. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/objectif.py +0 -0
  221. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/organisateur.py +0 -0
  222. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/organisateur_type.py +0 -0
  223. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/organisme_fields.py +0 -0
  224. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/organisme_id_pere.py +0 -0
  225. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/organismes_facet_distribution.py +0 -0
  226. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/organismes_facet_stats.py +0 -0
  227. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/organismes_hit.py +0 -0
  228. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/organismes_multi_search_query.py +0 -0
  229. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/organismes_query.py +0 -0
  230. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/phase_code.py +0 -0
  231. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/poule.py +0 -0
  232. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/poule_fields.py +0 -0
  233. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/poule_rencontre_item_model.py +0 -0
  234. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/poules_models.py +0 -0
  235. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/poules_query.py +0 -0
  236. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/pratique.py +0 -0
  237. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/pratiques_facet_distribution.py +0 -0
  238. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/pratiques_facet_stats.py +0 -0
  239. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/pratiques_hit.py +0 -0
  240. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/pratiques_hit_type.py +0 -0
  241. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/pratiques_multi_search_query.py +0 -0
  242. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/pratiques_type_class.py +0 -0
  243. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/publication_internet.py +0 -0
  244. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/purple_logo.py +0 -0
  245. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/query_fields_manager.py +0 -0
  246. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/ranking_engagement.py +0 -0
  247. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/rankings_models.py +0 -0
  248. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/rencontres_engagement.py +0 -0
  249. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/rencontres_facet_distribution.py +0 -0
  250. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/rencontres_facet_stats.py +0 -0
  251. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/rencontres_hit.py +0 -0
  252. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/rencontres_multi_search_query.py +0 -0
  253. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/saison.py +0 -0
  254. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/saison_fields.py +0 -0
  255. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/saisons_models.py +0 -0
  256. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/saisons_query.py +0 -0
  257. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/salle.py +0 -0
  258. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/salles_facet_distribution.py +0 -0
  259. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/salles_facet_stats.py +0 -0
  260. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/salles_hit.py +0 -0
  261. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/salles_multi_search_query.py +0 -0
  262. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/sexe.py +0 -0
  263. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/sexe_class.py +0 -0
  264. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/source.py +0 -0
  265. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/status.py +0 -0
  266. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/team_engagement.py +0 -0
  267. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/team_ranking.py +0 -0
  268. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/terrains_categorie_championnat_3x3_libelle.py +0 -0
  269. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/terrains_facet_distribution.py +0 -0
  270. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/terrains_facet_stats.py +0 -0
  271. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/terrains_hit.py +0 -0
  272. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/terrains_multi_search_query.py +0 -0
  273. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/terrains_name.py +0 -0
  274. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/terrains_sexe_enum.py +0 -0
  275. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/terrains_storage.py +0 -0
  276. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/tournoi_type_class.py +0 -0
  277. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/tournoi_type_enum.py +0 -0
  278. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/tournoi_types_3x3.py +0 -0
  279. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/tournoi_types_3x3_libelle.py +0 -0
  280. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/tournoi_types_3x3_libelle_enum.py +0 -0
  281. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/tournois_facet_distribution.py +0 -0
  282. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/tournois_facet_stats.py +0 -0
  283. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/tournois_hit.py +0 -0
  284. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/tournois_hit_type.py +0 -0
  285. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/tournois_libelle.py +0 -0
  286. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/tournois_multi_search_query.py +0 -0
  287. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/type_association.py +0 -0
  288. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/type_association_libelle.py +0 -0
  289. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/type_class.py +0 -0
  290. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/type_competition.py +0 -0
  291. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/type_competition_generique.py +0 -0
  292. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/type_enum.py +0 -0
  293. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/models/type_league.py +0 -0
  294. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/py.typed +0 -0
  295. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/utils/__init__.py +0 -0
  296. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/utils/cache_manager.py +0 -0
  297. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/utils/concurrency_utils.py +0 -0
  298. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/utils/converter_utils.py +0 -0
  299. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/utils/input_validation.py +0 -0
  300. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/utils/retry_utils.py +0 -0
  301. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/utils/secure_logging.py +0 -0
  302. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client/utils/token_manager.py +0 -0
  303. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client.egg-info/dependency_links.txt +0 -0
  304. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client.egg-info/not-zip-safe +0 -0
  305. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client.egg-info/requires.txt +0 -0
  306. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/src/ffbb_data_client.egg-info/top_level.txt +0 -0
  307. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/conftest.py +0 -0
  308. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/e2e/__init__.py +0 -0
  309. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/e2e/conftest.py +0 -0
  310. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/integration/__init__.py +0 -0
  311. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/integration/conftest.py +0 -0
  312. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/integration/test_500_user_journey.py +0 -0
  313. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/integration/test_501_user_journey_v3.py +0 -0
  314. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/integration/test_502_enhanced_integration.py +0 -0
  315. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/integration/test_503_secure_logging.py +0 -0
  316. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/integration/test_504_input_validation.py +0 -0
  317. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/integration/test_505_retry_timeout.py +0 -0
  318. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/integration/test_506_raw_json_model_conversion.py +0 -0
  319. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/__init__.py +0 -0
  320. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/__init__.py +0 -0
  321. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_200_api_ffbb_app_client.py +0 -0
  322. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_201_unit_tests_core.py +0 -0
  323. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_202_meilisearch_client.py +0 -0
  324. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_203_meilisearch_client_extension.py +0 -0
  325. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_204_ffbb_data_client.py +0 -0
  326. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_205_meilisearch_ffbb_client.py +0 -0
  327. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_206_coverage_gaps_clients.py +0 -0
  328. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_207_coverage_clients_extended.py +0 -0
  329. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_208_new_methods_coverage.py +0 -0
  330. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_209_automatic_token_resolution.py +0 -0
  331. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_210_targeted_clients_helpers_coverage.py +0 -0
  332. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_api_optimizations.py +0 -0
  333. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_async_methods.py +0 -0
  334. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_meilisearch_async.py +0 -0
  335. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_search_many.py +0 -0
  336. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_v2_backport_search.py +0 -0
  337. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_v3_new_features.py +0 -0
  338. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_v4_aiter_and_contacts.py +0 -0
  339. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/clients/test_warm_cache.py +0 -0
  340. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/conftest.py +0 -0
  341. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/helpers/__init__.py +0 -0
  342. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/helpers/test_400_http_helpers.py +0 -0
  343. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/helpers/test_meilisearch_pagination_concurrent.py +0 -0
  344. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/helpers/test_normalization.py +0 -0
  345. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/__init__.py +0 -0
  346. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_100_competition_id_categorie.py +0 -0
  347. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_101_competition_id_sexe.py +0 -0
  348. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_102_competition_id_type_competition.py +0 -0
  349. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_103_competition_id_type_competition_generique.py +0 -0
  350. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_104_competition_origine_categorie.py +0 -0
  351. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_105_competition_origine_type_competition_generique.py +0 -0
  352. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_106_competition_origine.py +0 -0
  353. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_107_id_engagement_equipe.py +0 -0
  354. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_108_id_organisme_equipe.py +0 -0
  355. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_109_id_organisme_equipe1_logo.py +0 -0
  356. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_110_labellisation.py +0 -0
  357. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_111_niveau_class.py +0 -0
  358. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_112_purple_logo.py +0 -0
  359. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_113_salle.py +0 -0
  360. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_114_tournoi_type_class.py +0 -0
  361. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_115_type_association_libelle.py +0 -0
  362. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_116_type_competition_generique.py +0 -0
  363. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_117_organisateur.py +0 -0
  364. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_118_competition_id.py +0 -0
  365. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_119_terrains_inner_models.py +0 -0
  366. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_120_pratiques_inner_models.py +0 -0
  367. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_121_to_dict_round_trip.py +0 -0
  368. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_122_coverage_gaps.py +0 -0
  369. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_123_missing_coverage.py +0 -0
  370. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_123_v2_backport.py +0 -0
  371. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_124_targeted_coverage_gains.py +0 -0
  372. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/models/test_dx_aliases.py +0 -0
  373. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/test_310_discover_endpoints.py +0 -0
  374. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/test_311_normalize_team_name.py +0 -0
  375. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/test_312_api_cors.py +0 -0
  376. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/test_313_api_metrics.py +0 -0
  377. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/test_314_discover_permissions.py +0 -0
  378. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/utils/__init__.py +0 -0
  379. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/utils/test_300_secure_logging.py +0 -0
  380. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/utils/test_301_input_validation.py +0 -0
  381. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/utils/test_302_retry_utils.py +0 -0
  382. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/utils/test_303_cache_manager.py +0 -0
  383. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/utils/test_304_config.py +0 -0
  384. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/utils/test_305_token_manager.py +0 -0
  385. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/utils/test_306_converter_utils.py +0 -0
  386. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/utils/test_307_coverage_gaps_utils.py +0 -0
  387. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/utils/test_308_converter_utils_extended.py +0 -0
  388. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tests/unit/utils/test_309_concurrency_utils.py +0 -0
  389. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tools/update_agents_md.py +0 -0
  390. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/tox.ini +0 -0
  391. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/assets/apple-touch-icon.png +0 -0
  392. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/assets/favicon-192x192.png +0 -0
  393. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/assets/favicon-48x48.png +0 -0
  394. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/assets/favicon-96x96.png +0 -0
  395. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/assets/favicon.ico +0 -0
  396. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/assets/logo.webp +0 -0
  397. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/css/style.css +0 -0
  398. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/favicon.ico +0 -0
  399. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/index.html +0 -0
  400. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/llms-full.txt +0 -0
  401. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/llms.txt +0 -0
  402. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/robots.txt +0 -0
  403. {ffbb_data_client-2.4.29 → ffbb_data_client-2.4.31}/website/sitemap.xml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ffbb-data-client
3
- Version: 2.4.29
3
+ Version: 2.4.31
4
4
  Summary: API FFBB — SDK Python moderne & asynchrone pour les donnees officielles de la Federation Francaise de BasketBall (clubs, classements, calendriers, lives, Meilisearch). Alternative moderne a ffbb-api-client.
5
5
  Home-page: https://github.com/nickdesi/ffbb-data-client
6
6
  Author: nickdesi
@@ -22,9 +22,10 @@ from typing import Any
22
22
  from fastapi import FastAPI, HTTPException
23
23
  from fastapi import Path as PathParam
24
24
  from fastapi import Query, Request, Response
25
+ from fastapi.exceptions import RequestValidationError
25
26
  from fastapi.middleware.cors import CORSMiddleware
26
27
  from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
27
- from fastapi.responses import FileResponse, HTMLResponse
28
+ from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
28
29
  from fastapi.staticfiles import StaticFiles
29
30
 
30
31
  from .clients.ffbb_data_client import FFBBDataClient
@@ -97,7 +98,7 @@ l'ensemble des données publiques de la **Fédération Française de BasketBall*
97
98
  - ⭐ **Code Source GitHub** : [`https://github.com/nickdesi/ffbb-data-client`](https://github.com/nickdesi/ffbb-data-client)
98
99
  - 📖 **Documentation Sphinx complète** : [`https://nickdesi.github.io/ffbb-data-client/`](https://nickdesi.github.io/ffbb-data-client/)
99
100
  """,
100
- version="2.4.25",
101
+ version="2.4.31",
101
102
  openapi_tags=TAGS_METADATA,
102
103
  docs_url=None,
103
104
  redoc_url=None,
@@ -115,6 +116,66 @@ l'ensemble des données publiques de la **Fédération Française de BasketBall*
115
116
  lifespan=lifespan,
116
117
  )
117
118
 
119
+
120
+ # ---------------------------------------------------------------------------
121
+ # Standard Error Formatting Handlers (REST Best Practices RFC 7807)
122
+ # ---------------------------------------------------------------------------
123
+ @app.exception_handler(HTTPException)
124
+ async def http_exception_handler(request: Request, exc: HTTPException):
125
+ code_map = {
126
+ 400: "BAD_REQUEST",
127
+ 401: "UNAUTHORIZED",
128
+ 403: "FORBIDDEN",
129
+ 404: "NOT_FOUND",
130
+ 409: "CONFLICT",
131
+ 422: "UNPROCESSABLE_ENTITY",
132
+ 429: "RATE_LIMIT_EXCEEDED",
133
+ 500: "INTERNAL_SERVER_ERROR",
134
+ 502: "BAD_GATEWAY",
135
+ 503: "SERVICE_UNAVAILABLE",
136
+ }
137
+ error_code = code_map.get(exc.status_code, f"HTTP_{exc.status_code}")
138
+ message = str(exc.detail)
139
+ return JSONResponse(
140
+ status_code=exc.status_code,
141
+ content={
142
+ "detail": exc.detail,
143
+ "error": {
144
+ "code": error_code,
145
+ "message": message,
146
+ "status": exc.status_code,
147
+ },
148
+ },
149
+ headers=getattr(exc, "headers", None),
150
+ )
151
+
152
+
153
+ @app.exception_handler(RequestValidationError)
154
+ async def validation_exception_handler(request: Request, exc: RequestValidationError):
155
+ errors = []
156
+ for err in exc.errors():
157
+ field = ".".join(str(loc) for loc in err.get("loc", []))
158
+ errors.append(
159
+ {
160
+ "field": field,
161
+ "message": err.get("msg", ""),
162
+ "type": err.get("type", ""),
163
+ }
164
+ )
165
+ return JSONResponse(
166
+ status_code=422,
167
+ content={
168
+ "detail": exc.errors(),
169
+ "error": {
170
+ "code": "VALIDATION_ERROR",
171
+ "message": "Erreur de validation des paramètres de la requête.",
172
+ "status": 422,
173
+ "errors": errors,
174
+ },
175
+ },
176
+ )
177
+
178
+
118
179
  _cors_env = os.getenv("FFBB_CORS_ORIGINS", "*")
119
180
  _cors_origins = [origin.strip() for origin in _cors_env.split(",") if origin.strip()]
120
181
  if "*" in _cors_origins:
@@ -589,6 +650,42 @@ async def health():
589
650
  }
590
651
 
591
652
 
653
+ @app.get(
654
+ "/health/ready",
655
+ tags=["Monitoring & Diagnostic"],
656
+ summary="Readiness probe avec dépendances (/health/ready)",
657
+ )
658
+ async def health_ready(response: Response):
659
+ """Vérifie la disponibilité réelle du serveur et de ses dépendances amont (Directus & Meilisearch)."""
660
+ client = get_client()
661
+ checks: dict[str, str] = {}
662
+ is_ready = True
663
+
664
+ try:
665
+ saisons = await client.get_saisons_async()
666
+ checks["directus"] = "ok" if saisons else "empty"
667
+ except Exception as e:
668
+ checks["directus"] = f"error: {e}"
669
+ is_ready = False
670
+
671
+ try:
672
+ res = client.multi_search(name="Clermont")
673
+ checks["meilisearch"] = "ok" if res else "empty"
674
+ except Exception as e:
675
+ checks["meilisearch"] = f"error: {e}"
676
+ is_ready = False
677
+
678
+ if not is_ready:
679
+ response.status_code = 503
680
+
681
+ return {
682
+ "status": "ready" if is_ready else "not_ready",
683
+ "service": "ffbb-data-client-api",
684
+ "timestamp": datetime.now(timezone.utc).isoformat(),
685
+ "checks": checks,
686
+ }
687
+
688
+
592
689
  @app.head("/health", include_in_schema=False)
593
690
  async def health_head():
594
691
  return Response(status_code=200)
@@ -693,9 +790,23 @@ async def search_ffbb(
693
790
  status_code=400,
694
791
  detail="Le terme de recherche doit comporter au moins 2 caractères.",
695
792
  )
793
+ # Résolution des acronymes fréquents (ex: SCBA -> Stade Clermontois Basket Auvergne)
794
+ _SEARCH_ACRONYMS = {
795
+ "SCBA": "Stade Clermontois Basket Auvergne",
796
+ "SCBF": "Stade Clermontois Basket Féminin",
797
+ "ASVEL": "LDLC ASVEL",
798
+ "SIG": "Strasbourg IG",
799
+ "JDA": "JDA Dijon",
800
+ "MSB": "Le Mans Sarthe Basket",
801
+ "EBPLO": "Elan Béarnais",
802
+ "CSP": "Limoges CSP",
803
+ "BCM": "Gravelines Dunkerque",
804
+ "ESSM": "Le Portel",
805
+ }
806
+ effective_query = _SEARCH_ACRONYMS.get(search_term.upper(), search_term)
696
807
  client = get_client()
697
808
  try:
698
- results = client.multi_search(name=search_term)
809
+ results = client.multi_search(name=effective_query)
699
810
  return results
700
811
  except Exception as e:
701
812
  raise HTTPException(status_code=500, detail=f"Erreur de recherche: {e}")
@@ -708,6 +819,7 @@ async def search_ffbb(
708
819
  response_description="Liste ordonnée des rencontres avec adresses et logos",
709
820
  )
710
821
  async def get_club_matches(
822
+ response: Response,
711
823
  organisme_id: int = PathParam(
712
824
  ...,
713
825
  ge=1,
@@ -719,6 +831,19 @@ async def get_club_matches(
719
831
  description="Filtrer par équipe (ex: 'SENIOR M1', 'U18 M1', 'ALL')",
720
832
  examples=["SENIOR M1"],
721
833
  ),
834
+ limit: int | None = Query(
835
+ None,
836
+ ge=1,
837
+ le=500,
838
+ description="Nombre maximal de rencontres à renvoyer (pagination)",
839
+ examples=[50],
840
+ ),
841
+ offset: int = Query(
842
+ 0,
843
+ ge=0,
844
+ description="Décalage de pagination",
845
+ examples=[0],
846
+ ),
722
847
  ):
723
848
  """
724
849
  Récupère l'ensemble des rencontres officielles FFBB d'un club,
@@ -975,6 +1100,14 @@ async def get_club_matches(
975
1100
  else (parsed_cat.numero_equipe if parsed_cat.numero_equipe else 1)
976
1101
  )
977
1102
 
1103
+ res1 = getattr(m, "resultatEquipe1", None)
1104
+ res2 = getattr(m, "resultatEquipe2", None)
1105
+ is_played = bool(
1106
+ getattr(m, "joue", False) or res1 is not None or res2 is not None
1107
+ )
1108
+ score_local = res1 if is_home else res2
1109
+ score_opp = res2 if is_home else res1
1110
+
978
1111
  match_data: dict[str, Any] = {
979
1112
  "ffbbMatchId": m_id,
980
1113
  "team": scba_team,
@@ -990,6 +1123,14 @@ async def get_club_matches(
990
1123
  "competition": comp_nom,
991
1124
  "poule": poule_nom,
992
1125
  "pouleId": poule_id,
1126
+ "round": getattr(m, "numeroJournee", None)
1127
+ or getattr(m, "numero_journee", None),
1128
+ "isPlayed": is_played,
1129
+ "scoreLocal": score_local,
1130
+ "scoreOpponent": score_opp,
1131
+ "scoreEquipe1": res1,
1132
+ "scoreEquipe2": res2,
1133
+ "competitionUrl": getattr(m, "url_competition", "") or "",
993
1134
  "teamLogo": club_logo_url,
994
1135
  }
995
1136
  if opponent_logo:
@@ -1003,12 +1144,27 @@ async def get_club_matches(
1003
1144
  matches_list = [m for m in built_matches if m is not None]
1004
1145
 
1005
1146
  matches_list.sort(key=lambda x: (x.get("dateISO", ""), x.get("time", "")))
1147
+ response.headers["Cache-Control"] = "public, max-age=180, stale-while-revalidate=60"
1148
+
1149
+ total_count = len(matches_list)
1150
+ paged_matches = (
1151
+ matches_list[offset : offset + limit]
1152
+ if limit is not None
1153
+ else matches_list[offset:]
1154
+ )
1006
1155
 
1007
1156
  return {
1008
1157
  "organisme_id": organisme_id,
1009
1158
  "club": club_name,
1010
- "matches": matches_list,
1011
- "count": len(matches_list),
1159
+ "matches": paged_matches,
1160
+ "count": len(paged_matches),
1161
+ "total": total_count,
1162
+ "pagination": {
1163
+ "total": total_count,
1164
+ "limit": limit if limit is not None else total_count,
1165
+ "offset": offset,
1166
+ "has_more": (offset + len(paged_matches)) < total_count,
1167
+ },
1012
1168
  }
1013
1169
 
1014
1170
 
@@ -1119,6 +1275,7 @@ async def get_poule(
1119
1275
  response_description="Classement détaillé avec points, victoires et goal-average",
1120
1276
  )
1121
1277
  async def get_poule_classement(
1278
+ response: Response,
1122
1279
  poule_id: int = PathParam(
1123
1280
  ..., ge=1, description="ID de la poule FFBB", examples=[129759]
1124
1281
  ),
@@ -1137,6 +1294,9 @@ async def get_poule_classement(
1137
1294
  or getattr(poule, "classements", [])
1138
1295
  or []
1139
1296
  )
1297
+ response.headers["Cache-Control"] = (
1298
+ "public, max-age=300, stale-while-revalidate=60"
1299
+ )
1140
1300
  return {
1141
1301
  "poule_id": poule_id,
1142
1302
  "nom": getattr(poule, "nom", "") or getattr(poule, "libelle", ""),
@@ -1164,6 +1324,120 @@ async def get_lives():
1164
1324
  raise HTTPException(status_code=500, detail=str(e))
1165
1325
 
1166
1326
 
1327
+ @app.get(
1328
+ "/api/v1/rencontre/{rencontre_id}",
1329
+ tags=["Matchs & Calendriers"],
1330
+ summary="Détails complets d'une rencontre FFBB",
1331
+ response_description="Fiche officielle détaillée de la rencontre, scores, salle et officiels",
1332
+ )
1333
+ @app.get(
1334
+ "/api/v1/match/{rencontre_id}",
1335
+ tags=["Matchs & Calendriers"],
1336
+ summary="Détails complets d'une rencontre FFBB (alias /match)",
1337
+ include_in_schema=False,
1338
+ )
1339
+ async def get_rencontre_detail(
1340
+ rencontre_id: str = PathParam(
1341
+ ...,
1342
+ description="ID FFBB de la rencontre (ex: '200000014753740')",
1343
+ examples=["200000014753740"],
1344
+ ),
1345
+ ):
1346
+ """Retourne la fiche détaillée d'un match officiel FFBB avec scores, salle résolue et détails des équipes."""
1347
+ client = get_client()
1348
+ try:
1349
+ match_data = await client.get_rencontre_async(rencontre_id)
1350
+ if not match_data:
1351
+ raise HTTPException(
1352
+ status_code=404, detail=f"Rencontre {rencontre_id} introuvable."
1353
+ )
1354
+ return match_data
1355
+ except HTTPException:
1356
+ raise
1357
+ except Exception as e:
1358
+ raise HTTPException(status_code=500, detail=str(e))
1359
+
1360
+
1361
+ @app.get(
1362
+ "/api/v1/salle/{salle_id}",
1363
+ tags=["Clubs"],
1364
+ summary="Détails d'une salle / gymnase",
1365
+ response_description="Fiche gymnase avec adresse complète et géolocalisation",
1366
+ )
1367
+ async def get_salle_detail(
1368
+ response: Response,
1369
+ salle_id: str = PathParam(
1370
+ ...,
1371
+ description="ID FFBB de la salle (ex: '6543')",
1372
+ examples=["6543"],
1373
+ ),
1374
+ ):
1375
+ """Retourne les informations complètes d'un gymnase (nom, rue, code postal, ville, cartographie)."""
1376
+ client = get_client()
1377
+ try:
1378
+ salle = await client.get_salle_async(salle_id)
1379
+ if not salle:
1380
+ raise HTTPException(
1381
+ status_code=404, detail=f"Salle {salle_id} introuvable."
1382
+ )
1383
+ response.headers["Cache-Control"] = (
1384
+ "public, max-age=86400, stale-while-revalidate=3600"
1385
+ )
1386
+ return salle
1387
+ except HTTPException:
1388
+ raise
1389
+ except Exception as e:
1390
+ raise HTTPException(status_code=500, detail=str(e))
1391
+
1392
+
1393
+ @app.get(
1394
+ "/api/v1/competition/{competition_id}",
1395
+ tags=["Compétitions & Poules"],
1396
+ summary="Détails d'une compétition",
1397
+ response_description="Informations sur la compétition et composition des poules",
1398
+ )
1399
+ async def get_competition_detail(
1400
+ competition_id: int = PathParam(
1401
+ ...,
1402
+ ge=1,
1403
+ description="ID FFBB de la compétition (ex: 200000002898785)",
1404
+ examples=[200000002898785],
1405
+ ),
1406
+ ):
1407
+ """Retourne les métadonnées et la liste des poules associées à une compétition officielle FFBB."""
1408
+ client = get_client()
1409
+ try:
1410
+ comp = await client.get_competition_async(competition_id)
1411
+ if not comp:
1412
+ raise HTTPException(
1413
+ status_code=404,
1414
+ detail=f"Compétition {competition_id} introuvable.",
1415
+ )
1416
+ return comp
1417
+ except HTTPException:
1418
+ raise
1419
+ except Exception as e:
1420
+ raise HTTPException(status_code=500, detail=str(e))
1421
+
1422
+
1423
+ @app.get(
1424
+ "/api/v1/saisons",
1425
+ tags=["Compétitions & Poules"],
1426
+ summary="Liste des saisons officielles FFBB",
1427
+ response_description="Historique et saison active",
1428
+ )
1429
+ async def get_saisons(response: Response):
1430
+ """Retourne la liste des saisons officielles FFBB avec indication de la saison en cours."""
1431
+ client = get_client()
1432
+ try:
1433
+ response.headers["Cache-Control"] = (
1434
+ "public, max-age=86400, stale-while-revalidate=3600"
1435
+ )
1436
+ return await client.get_saisons_async()
1437
+ except Exception as e:
1438
+ raise HTTPException(status_code=500, detail=str(e))
1439
+
1440
+
1167
1441
  # --------------------------------------------------------------------------
1168
1442
  # Modern API Documentation Interfaces (Scalar, Swagger UI, ReDoc)
1169
1443
  # --------------------------------------------------------------------------
@@ -79,10 +79,11 @@ def _build_pagination_jobs(
79
79
  return jobs
80
80
 
81
81
 
82
- def _single_result(multi: MultiSearchResults, index: int) -> MultiSearchResults:
82
+ def _single_result(multi: MultiSearchResults, index: int) -> MultiSearchResults | None:
83
83
  """Isole le i-ème sous-résultat d'un multi_search dans un MultiSearchResults
84
84
  à un élément, pour une fusion cohérente avec ``_merge_page``."""
85
- assert multi.results is not None
85
+ if not multi.results or index >= len(multi.results):
86
+ return None
86
87
  return MultiSearchResults(results=[multi.results[index]])
87
88
 
88
89
 
@@ -148,7 +149,10 @@ class MeilisearchClientExtension(MeilisearchClient):
148
149
  out: list[tuple[int, int, MultiSearchResults | None]] = []
149
150
  if new_result and new_result.results:
150
151
  for k, (orig_idx, offset, _q) in enumerate(batch):
151
- out.append((orig_idx, offset, _single_result(new_result, k)))
152
+ if k < len(new_result.results):
153
+ res = _single_result(new_result, k)
154
+ if res is not None:
155
+ out.append((orig_idx, offset, res))
152
156
  return out
153
157
 
154
158
  async def _fetch_batch_async(
@@ -162,7 +166,10 @@ class MeilisearchClientExtension(MeilisearchClient):
162
166
  out: list[tuple[int, int, MultiSearchResults | None]] = []
163
167
  if new_result and new_result.results:
164
168
  for k, (orig_idx, offset, _q) in enumerate(batch):
165
- out.append((orig_idx, offset, _single_result(new_result, k)))
169
+ if k < len(new_result.results):
170
+ res = _single_result(new_result, k)
171
+ if res is not None:
172
+ out.append((orig_idx, offset, res))
166
173
  return out
167
174
 
168
175
  def recursive_smart_multi_search(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ffbb-data-client
3
- Version: 2.4.29
3
+ Version: 2.4.31
4
4
  Summary: API FFBB — SDK Python moderne & asynchrone pour les donnees officielles de la Federation Francaise de BasketBall (clubs, classements, calendriers, lives, Meilisearch). Alternative moderne a ffbb-api-client.
5
5
  Home-page: https://github.com/nickdesi/ffbb-data-client
6
6
  Author: nickdesi
@@ -320,6 +320,7 @@ tests/unit/test_310_discover_endpoints.py
320
320
  tests/unit/test_311_normalize_team_name.py
321
321
  tests/unit/test_312_api_cors.py
322
322
  tests/unit/test_313_api_metrics.py
323
+ tests/unit/test_314_api_endpoints.py
323
324
  tests/unit/test_314_discover_permissions.py
324
325
  tests/unit/clients/__init__.py
325
326
  tests/unit/clients/test_200_api_ffbb_app_client.py
@@ -366,6 +366,7 @@
366
366
  "tests/unit/test_311_normalize_team_name.py",
367
367
  "tests/unit/test_312_api_cors.py",
368
368
  "tests/unit/test_313_api_metrics.py",
369
+ "tests/unit/test_314_api_endpoints.py",
369
370
  "tests/unit/test_314_discover_permissions.py",
370
371
  "tests/unit/utils/__init__.py",
371
372
  "tests/unit/utils/test_300_secure_logging.py",
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "2.4.29",
2
+ "tag": "2.4.31",
3
3
  "distance": 0,
4
- "node": "gb20d81aba622329ff8f2e58ef0050f0e37df273c",
4
+ "node": "g90a97f236b7ee1f4c1dcac417ee73a363ca4ecd8",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-09-23"
@@ -91,3 +91,12 @@ def test_merge_page_with_empty_or_missing_results():
91
91
 
92
92
  # 3. orig_idx out of bounds
93
93
  _merge_page(res, 999, empty_page)
94
+
95
+
96
+ def test_single_result_out_of_bounds_safety():
97
+ from ffbb_data_client.helpers.meilisearch_client_extension import _single_result
98
+
99
+ res = MultiSearchResults(results=[CompetitionsMultiSearchResult()])
100
+ assert _single_result(res, 0) is not None
101
+ assert _single_result(res, 1) is None
102
+ assert _single_result(MultiSearchResults(results=[]), 0) is None
@@ -0,0 +1,144 @@
1
+ """Tests for the REST endpoints, Best Practices, error envelopes, and caching in api.py."""
2
+
3
+ from unittest.mock import AsyncMock, MagicMock, patch
4
+
5
+ import pytest
6
+ from httpx import ASGITransport, AsyncClient
7
+
8
+ from ffbb_data_client.api import app
9
+
10
+
11
+ @pytest.mark.asyncio
12
+ async def test_search_acronym_expansion():
13
+ transport = ASGITransport(app=app)
14
+ mock_client = MagicMock()
15
+ mock_client.multi_search = MagicMock(
16
+ return_value=[
17
+ {"index_uid": "organismes", "hits": [{"nom": "STADE CLERMONTOIS"}]}
18
+ ]
19
+ )
20
+ with patch("ffbb_data_client.api.get_client", return_value=mock_client):
21
+ async with AsyncClient(transport=transport, base_url="http://test") as ac:
22
+ r = await ac.get("/api/v1/search?query=SCBA")
23
+ assert r.status_code == 200
24
+ mock_client.multi_search.assert_called_with(
25
+ name="Stade Clermontois Basket Auvergne"
26
+ )
27
+
28
+
29
+ @pytest.mark.asyncio
30
+ async def test_health_ready_endpoint():
31
+ transport = ASGITransport(app=app)
32
+ mock_client = MagicMock()
33
+ mock_client.get_saisons_async = AsyncMock(return_value=[{"id": "1037"}])
34
+ mock_client.multi_search = MagicMock(return_value=[{"hits": []}])
35
+
36
+ with patch("ffbb_data_client.api.get_client", return_value=mock_client):
37
+ async with AsyncClient(transport=transport, base_url="http://test") as ac:
38
+ r = await ac.get("/health/ready")
39
+ assert r.status_code == 200
40
+ data = r.json()
41
+ assert data.get("status") == "ready"
42
+ assert data.get("checks", {}).get("directus") == "ok"
43
+ assert data.get("checks", {}).get("meilisearch") == "ok"
44
+
45
+
46
+ @pytest.mark.asyncio
47
+ async def test_standard_error_envelope_404():
48
+ transport = ASGITransport(app=app)
49
+ mock_client = MagicMock()
50
+ mock_client.get_organisme_async = AsyncMock(return_value=None)
51
+
52
+ with patch("ffbb_data_client.api.get_client", return_value=mock_client):
53
+ async with AsyncClient(transport=transport, base_url="http://test") as ac:
54
+ r = await ac.get("/api/v1/club/999999")
55
+ assert r.status_code == 404
56
+ data = r.json()
57
+ assert "detail" in data
58
+ assert "error" in data
59
+ assert data["error"]["code"] == "NOT_FOUND"
60
+ assert data["error"]["status"] == 404
61
+
62
+
63
+ @pytest.mark.asyncio
64
+ async def test_standard_validation_error_422():
65
+ transport = ASGITransport(app=app)
66
+ async with AsyncClient(transport=transport, base_url="http://test") as ac:
67
+ # Invalid query param length
68
+ r = await ac.get("/api/v1/club/not_a_number")
69
+ assert r.status_code == 422
70
+ data = r.json()
71
+ assert "error" in data
72
+ assert data["error"]["code"] == "VALIDATION_ERROR"
73
+ assert len(data["error"]["errors"]) > 0
74
+
75
+
76
+ @pytest.mark.asyncio
77
+ async def test_match_card_enrichment_and_pagination():
78
+ transport = ASGITransport(app=app)
79
+ mock_client = MagicMock()
80
+ mock_org = MagicMock()
81
+ mock_org.nom = "STADE CLERMONTOIS BASKET AUVERGNE"
82
+ mock_org.logo = None
83
+ mock_org.engagements = []
84
+ mock_client.get_organisme_async = AsyncMock(return_value=mock_org)
85
+
86
+ with patch("ffbb_data_client.api.get_client", return_value=mock_client):
87
+ async with AsyncClient(transport=transport, base_url="http://test") as ac:
88
+ r = await ac.get("/api/v1/club/9326/matches?limit=10&offset=0")
89
+ assert r.status_code == 200
90
+ assert "Cache-Control" in r.headers
91
+ data = r.json()
92
+ assert "matches" in data
93
+ assert "pagination" in data
94
+ assert data["pagination"]["limit"] == 10
95
+ assert data["pagination"]["offset"] == 0
96
+
97
+
98
+ @pytest.mark.asyncio
99
+ async def test_rencontre_endpoint():
100
+ transport = ASGITransport(app=app)
101
+ mock_client = MagicMock()
102
+ mock_match = {"id": "12345", "nomEquipe1": "Eq A", "nomEquipe2": "Eq B"}
103
+ mock_client.get_rencontre_async = AsyncMock(return_value=mock_match)
104
+
105
+ with patch("ffbb_data_client.api.get_client", return_value=mock_client):
106
+ async with AsyncClient(transport=transport, base_url="http://test") as ac:
107
+ r = await ac.get("/api/v1/rencontre/12345")
108
+ assert r.status_code == 200
109
+ assert r.json().get("id") == "12345"
110
+
111
+ # Test alias /match
112
+ r_alias = await ac.get("/api/v1/match/12345")
113
+ assert r_alias.status_code == 200
114
+
115
+
116
+ @pytest.mark.asyncio
117
+ async def test_salle_and_competition_endpoints_caching():
118
+ transport = ASGITransport(app=app)
119
+ mock_client = MagicMock()
120
+ mock_client.get_salle_async = AsyncMock(
121
+ return_value={"id": "6543", "libelle": "Gymnase Fleury"}
122
+ )
123
+ mock_client.get_competition_async = AsyncMock(
124
+ return_value={"id": "999", "nom": "DMU13"}
125
+ )
126
+ mock_client.get_saisons_async = AsyncMock(
127
+ return_value=[{"id": "1037", "nom": "2026-2027"}]
128
+ )
129
+
130
+ with patch("ffbb_data_client.api.get_client", return_value=mock_client):
131
+ async with AsyncClient(transport=transport, base_url="http://test") as ac:
132
+ r_salle = await ac.get("/api/v1/salle/6543")
133
+ assert r_salle.status_code == 200
134
+ assert "Cache-Control" in r_salle.headers
135
+ assert "max-age=86400" in r_salle.headers["Cache-Control"]
136
+
137
+ r_comp = await ac.get("/api/v1/competition/999")
138
+ assert r_comp.status_code == 200
139
+ assert r_comp.json().get("nom") == "DMU13"
140
+
141
+ r_saisons = await ac.get("/api/v1/saisons")
142
+ assert r_saisons.status_code == 200
143
+ assert "Cache-Control" in r_saisons.headers
144
+ assert len(r_saisons.json()) == 1