ffbb-data-client 2.4.0__tar.gz → 2.4.2__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 (386) hide show
  1. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/CHANGELOG.md +12 -0
  2. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/PKG-INFO +1 -1
  3. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/RELEASE_NOTES.md +17 -1
  4. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/pyproject.toml +1 -0
  5. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/api.py +84 -39
  6. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/helpers/http_requests_utils.py +20 -1
  7. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/helpers/normalization.py +15 -3
  8. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/utils/secure_logging.py +4 -4
  9. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client.egg-info/PKG-INFO +1 -1
  10. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client.egg-info/scm_version.json +2 -2
  11. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/helpers/test_normalization.py +1 -0
  12. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tox.ini +1 -0
  13. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.agents/rules/antigravity-rtk-rules.md +0 -0
  14. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.coveragerc +0 -0
  15. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.gitattributes +0 -0
  16. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/FUNDING.yml +0 -0
  17. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  18. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  19. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  20. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/dependabot.yml +0 -0
  21. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/scripts/ai-pr-reviewer.cjs +0 -0
  22. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/scripts/check_wrapper_parity.py +0 -0
  23. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/workflows/ai-pr-reviewer.yml +0 -0
  24. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/workflows/check_wrapper_parity.yml +0 -0
  25. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/workflows/ci.yml +0 -0
  26. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/workflows/codeql.yml +0 -0
  27. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/workflows/deploy-pages.yml +0 -0
  28. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/workflows/keep-ffbb-api-discovery-alive.yml +0 -0
  29. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/workflows/publish.yml +0 -0
  30. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/workflows/release-after-discovery-merge.yml +0 -0
  31. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.github/workflows/update-ffbb-api-discovery.yml +0 -0
  32. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.gitignore +0 -0
  33. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.isort.cfg +0 -0
  34. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.jules/bolt.md +0 -0
  35. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.pre-commit-config.yaml +0 -0
  36. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/.readthedocs.yml +0 -0
  37. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/AGENTS.md +0 -0
  38. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/AUTHORS.rst +0 -0
  39. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/CODE_OF_CONDUCT.md +0 -0
  40. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/CONTRIBUTING.rst +0 -0
  41. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/DESIGN.md +0 -0
  42. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/Dockerfile +0 -0
  43. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/LICENSE.txt +0 -0
  44. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/LOCAL_CI_GUIDE.md +0 -0
  45. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/README.md +0 -0
  46. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/SECURITY.md +0 -0
  47. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/data/api.ffbb.app.json +0 -0
  48. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/data/api_update_summary.md +0 -0
  49. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/data/collections.json +0 -0
  50. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/data/endpoint_discovery.json +0 -0
  51. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/data/indexes.json +0 -0
  52. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/data/meilisearch-prod.ffbb.app.json +0 -0
  53. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/data/openapi.json +0 -0
  54. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/data/openapi_full.json +0 -0
  55. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/data/type_discovery_corrections.json +0 -0
  56. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/Makefile +0 -0
  57. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/_static/.gitignore +0 -0
  58. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/architecture.rst +0 -0
  59. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/authors.rst +0 -0
  60. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/changelog.rst +0 -0
  61. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/conf.py +0 -0
  62. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/contributing.rst +0 -0
  63. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/examples.rst +0 -0
  64. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/index.rst +0 -0
  65. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/license.rst +0 -0
  66. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/migration.rst +0 -0
  67. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/readme.rst +0 -0
  68. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/requirements.txt +0 -0
  69. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/test_strategy.md +0 -0
  70. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/docs/testing_conventions.md +0 -0
  71. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/examples/README.md +0 -0
  72. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/examples/complete_usage_example.py +0 -0
  73. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/examples/quick_start.py +0 -0
  74. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/examples/team_ranking_analysis.py +0 -0
  75. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/pytest.ini +0 -0
  76. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/run-ci-locally.sh +0 -0
  77. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/scripts/benchmark_concurrent_pagination.py +0 -0
  78. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/scripts/benchmark_search_organisme.py +0 -0
  79. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/scripts/discover_endpoints.py +0 -0
  80. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/scripts/discover_types.py +0 -0
  81. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/setup.cfg +0 -0
  82. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/setup.py +0 -0
  83. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/__init__.py +0 -0
  84. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/__init__.py +0 -0
  85. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/_helpers.py +0 -0
  86. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/_mixins/__init__.py +0 -0
  87. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/_mixins/competition.py +0 -0
  88. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/_mixins/external.py +0 -0
  89. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/_mixins/getters.py +0 -0
  90. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/_mixins/list_methods.py +0 -0
  91. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/_mixins/organisme.py +0 -0
  92. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/_rest_facade.py +0 -0
  93. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/_search_facade.py +0 -0
  94. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/api_ffbb_app_client.py +0 -0
  95. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/ffbb_data_client.py +0 -0
  96. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/meilisearch_client.py +0 -0
  97. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/clients/meilisearch_ffbb_client.py +0 -0
  98. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/config.py +0 -0
  99. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/data/__init__.py +0 -0
  100. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/data/collections.json +0 -0
  101. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/data/endpoint_discovery.json +0 -0
  102. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/data/indexes.json +0 -0
  103. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/data/openapi.json +0 -0
  104. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/helpers/__init__.py +0 -0
  105. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/helpers/http_requests_helper.py +0 -0
  106. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/helpers/meilisearch_client_extension.py +0 -0
  107. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/helpers/multi_search_query_helper.py +0 -0
  108. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/__init__.py +0 -0
  109. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/affiche.py +0 -0
  110. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/cartographie.py +0 -0
  111. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/categorie.py +0 -0
  112. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/categorie_type.py +0 -0
  113. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/clock.py +0 -0
  114. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/club_contacts.py +0 -0
  115. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/code.py +0 -0
  116. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/commune.py +0 -0
  117. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competition_fields.py +0 -0
  118. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competition_id.py +0 -0
  119. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competition_id_categorie.py +0 -0
  120. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competition_id_sexe.py +0 -0
  121. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competition_id_type_competition.py +0 -0
  122. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competition_id_type_competition_generique.py +0 -0
  123. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competition_origine.py +0 -0
  124. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competition_origine_categorie.py +0 -0
  125. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competition_origine_type_competition.py +0 -0
  126. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competition_origine_type_competition_generique.py +0 -0
  127. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competition_type.py +0 -0
  128. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competitions_facet_distribution.py +0 -0
  129. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competitions_facet_stats.py +0 -0
  130. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competitions_hit.py +0 -0
  131. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competitions_multi_search_query.py +0 -0
  132. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/competitions_query.py +0 -0
  133. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/configuration_models.py +0 -0
  134. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/contact_info.py +0 -0
  135. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/content_multi_search_query.py +0 -0
  136. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/coordonnees.py +0 -0
  137. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/coordonnees_type.py +0 -0
  138. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/document_flyer.py +0 -0
  139. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/document_flyer_type.py +0 -0
  140. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/engagement_contacts.py +0 -0
  141. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/engagements_facet_distribution.py +0 -0
  142. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/engagements_facet_stats.py +0 -0
  143. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/engagements_hit.py +0 -0
  144. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/engagements_multi_search_query.py +0 -0
  145. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/etat.py +0 -0
  146. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/external_competition_id.py +0 -0
  147. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/external_id.py +0 -0
  148. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/facet_distribution.py +0 -0
  149. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/facet_stats.py +0 -0
  150. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/field_set.py +0 -0
  151. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/folder.py +0 -0
  152. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/formation_session.py +0 -0
  153. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/formations_facet_distribution.py +0 -0
  154. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/formations_facet_stats.py +0 -0
  155. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/formations_hit.py +0 -0
  156. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/formations_multi_search_query.py +0 -0
  157. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/game_stats_model.py +0 -0
  158. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/game_stats_models.py +0 -0
  159. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/generic_search.py +0 -0
  160. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/geo.py +0 -0
  161. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/geo_sort_order.py +0 -0
  162. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_commune_response.py +0 -0
  163. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_competition_response.py +0 -0
  164. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_configuration_response.py +0 -0
  165. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_engagement_response.py +0 -0
  166. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_entraineur_response.py +0 -0
  167. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_formation_response.py +0 -0
  168. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_officiel_response.py +0 -0
  169. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_organisme_response.py +0 -0
  170. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_poule_response.py +0 -0
  171. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_pratique_response.py +0 -0
  172. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_rencontre_response.py +0 -0
  173. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_saisons_response.py +0 -0
  174. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_salle_response.py +0 -0
  175. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_terrain_response.py +0 -0
  176. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/get_tournoi_response.py +0 -0
  177. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/gradient_color.py +0 -0
  178. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/hit.py +0 -0
  179. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/id_engagement_equipe.py +0 -0
  180. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/id_organisme_equipe.py +0 -0
  181. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/id_organisme_equipe1_logo.py +0 -0
  182. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/id_poule.py +0 -0
  183. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/jour.py +0 -0
  184. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/label.py +0 -0
  185. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/labellisation.py +0 -0
  186. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/live.py +0 -0
  187. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/lives.py +0 -0
  188. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/logo.py +0 -0
  189. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_queries.py +0 -0
  190. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_query.py +0 -0
  191. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_result_competitions.py +0 -0
  192. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_result_engagements.py +0 -0
  193. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_result_formations.py +0 -0
  194. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_result_organismes.py +0 -0
  195. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_result_pratiques.py +0 -0
  196. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_result_rencontres.py +0 -0
  197. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_result_salles.py +0 -0
  198. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_result_terrains.py +0 -0
  199. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_result_tournois.py +0 -0
  200. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_results.py +0 -0
  201. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/multi_search_results_class.py +0 -0
  202. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/nature_sol.py +0 -0
  203. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/niveau.py +0 -0
  204. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/niveau_class.py +0 -0
  205. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/niveau_extractor.py +0 -0
  206. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/niveau_info.py +0 -0
  207. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/niveau_models.py +0 -0
  208. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/niveau_type.py +0 -0
  209. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/objectif.py +0 -0
  210. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/organisateur.py +0 -0
  211. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/organisateur_type.py +0 -0
  212. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/organisme_fields.py +0 -0
  213. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/organisme_id_pere.py +0 -0
  214. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/organismes_facet_distribution.py +0 -0
  215. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/organismes_facet_stats.py +0 -0
  216. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/organismes_hit.py +0 -0
  217. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/organismes_multi_search_query.py +0 -0
  218. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/organismes_query.py +0 -0
  219. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/phase_code.py +0 -0
  220. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/poule.py +0 -0
  221. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/poule_fields.py +0 -0
  222. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/poule_rencontre_item_model.py +0 -0
  223. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/poules_models.py +0 -0
  224. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/poules_query.py +0 -0
  225. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/pratique.py +0 -0
  226. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/pratiques_facet_distribution.py +0 -0
  227. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/pratiques_facet_stats.py +0 -0
  228. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/pratiques_hit.py +0 -0
  229. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/pratiques_hit_type.py +0 -0
  230. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/pratiques_multi_search_query.py +0 -0
  231. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/pratiques_type_class.py +0 -0
  232. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/publication_internet.py +0 -0
  233. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/purple_logo.py +0 -0
  234. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/query_fields_manager.py +0 -0
  235. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/ranking_engagement.py +0 -0
  236. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/rankings_models.py +0 -0
  237. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/rencontres_engagement.py +0 -0
  238. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/rencontres_facet_distribution.py +0 -0
  239. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/rencontres_facet_stats.py +0 -0
  240. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/rencontres_hit.py +0 -0
  241. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/rencontres_multi_search_query.py +0 -0
  242. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/saison.py +0 -0
  243. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/saison_fields.py +0 -0
  244. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/saisons_models.py +0 -0
  245. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/saisons_query.py +0 -0
  246. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/salle.py +0 -0
  247. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/salles_facet_distribution.py +0 -0
  248. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/salles_facet_stats.py +0 -0
  249. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/salles_hit.py +0 -0
  250. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/salles_multi_search_query.py +0 -0
  251. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/sexe.py +0 -0
  252. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/sexe_class.py +0 -0
  253. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/source.py +0 -0
  254. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/status.py +0 -0
  255. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/team_engagement.py +0 -0
  256. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/team_ranking.py +0 -0
  257. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/terrains_categorie_championnat_3x3_libelle.py +0 -0
  258. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/terrains_facet_distribution.py +0 -0
  259. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/terrains_facet_stats.py +0 -0
  260. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/terrains_hit.py +0 -0
  261. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/terrains_multi_search_query.py +0 -0
  262. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/terrains_name.py +0 -0
  263. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/terrains_sexe_enum.py +0 -0
  264. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/terrains_storage.py +0 -0
  265. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/tournoi_type_class.py +0 -0
  266. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/tournoi_type_enum.py +0 -0
  267. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/tournoi_types_3x3.py +0 -0
  268. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/tournoi_types_3x3_libelle.py +0 -0
  269. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/tournoi_types_3x3_libelle_enum.py +0 -0
  270. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/tournois_facet_distribution.py +0 -0
  271. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/tournois_facet_stats.py +0 -0
  272. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/tournois_hit.py +0 -0
  273. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/tournois_hit_type.py +0 -0
  274. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/tournois_libelle.py +0 -0
  275. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/tournois_multi_search_query.py +0 -0
  276. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/type_association.py +0 -0
  277. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/type_association_libelle.py +0 -0
  278. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/type_class.py +0 -0
  279. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/type_competition.py +0 -0
  280. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/type_competition_generique.py +0 -0
  281. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/type_enum.py +0 -0
  282. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/models/type_league.py +0 -0
  283. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/py.typed +0 -0
  284. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/utils/__init__.py +0 -0
  285. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/utils/cache_manager.py +0 -0
  286. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/utils/concurrency_utils.py +0 -0
  287. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/utils/converter_utils.py +0 -0
  288. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/utils/input_validation.py +0 -0
  289. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/utils/retry_utils.py +0 -0
  290. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client/utils/token_manager.py +0 -0
  291. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client.egg-info/SOURCES.txt +0 -0
  292. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client.egg-info/dependency_links.txt +0 -0
  293. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client.egg-info/not-zip-safe +0 -0
  294. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client.egg-info/requires.txt +0 -0
  295. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client.egg-info/scm_file_list.json +0 -0
  296. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/src/ffbb_data_client.egg-info/top_level.txt +0 -0
  297. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/conftest.py +0 -0
  298. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/e2e/__init__.py +0 -0
  299. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/e2e/conftest.py +0 -0
  300. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/integration/__init__.py +0 -0
  301. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/integration/conftest.py +0 -0
  302. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/integration/test_500_user_journey.py +0 -0
  303. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/integration/test_501_user_journey_v3.py +0 -0
  304. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/integration/test_502_enhanced_integration.py +0 -0
  305. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/integration/test_503_secure_logging.py +0 -0
  306. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/integration/test_504_input_validation.py +0 -0
  307. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/integration/test_505_retry_timeout.py +0 -0
  308. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/integration/test_506_raw_json_model_conversion.py +0 -0
  309. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/__init__.py +0 -0
  310. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/__init__.py +0 -0
  311. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_200_api_ffbb_app_client.py +0 -0
  312. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_201_unit_tests_core.py +0 -0
  313. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_202_meilisearch_client.py +0 -0
  314. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_203_meilisearch_client_extension.py +0 -0
  315. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_204_ffbb_data_client.py +0 -0
  316. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_205_meilisearch_ffbb_client.py +0 -0
  317. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_206_coverage_gaps_clients.py +0 -0
  318. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_207_coverage_clients_extended.py +0 -0
  319. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_208_new_methods_coverage.py +0 -0
  320. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_209_automatic_token_resolution.py +0 -0
  321. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_210_targeted_clients_helpers_coverage.py +0 -0
  322. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_async_methods.py +0 -0
  323. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_meilisearch_async.py +0 -0
  324. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_search_many.py +0 -0
  325. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_v2_backport_search.py +0 -0
  326. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_v3_new_features.py +0 -0
  327. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/clients/test_warm_cache.py +0 -0
  328. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/conftest.py +0 -0
  329. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/helpers/__init__.py +0 -0
  330. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/helpers/test_400_http_helpers.py +0 -0
  331. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/helpers/test_meilisearch_client_extension_recursive_pagination.py +0 -0
  332. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/helpers/test_meilisearch_pagination_concurrent.py +0 -0
  333. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/__init__.py +0 -0
  334. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_100_competition_id_categorie.py +0 -0
  335. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_101_competition_id_sexe.py +0 -0
  336. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_102_competition_id_type_competition.py +0 -0
  337. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_103_competition_id_type_competition_generique.py +0 -0
  338. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_104_competition_origine_categorie.py +0 -0
  339. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_105_competition_origine_type_competition_generique.py +0 -0
  340. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_106_competition_origine.py +0 -0
  341. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_107_id_engagement_equipe.py +0 -0
  342. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_108_id_organisme_equipe.py +0 -0
  343. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_109_id_organisme_equipe1_logo.py +0 -0
  344. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_110_labellisation.py +0 -0
  345. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_111_niveau_class.py +0 -0
  346. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_112_purple_logo.py +0 -0
  347. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_113_salle.py +0 -0
  348. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_114_tournoi_type_class.py +0 -0
  349. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_115_type_association_libelle.py +0 -0
  350. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_116_type_competition_generique.py +0 -0
  351. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_117_organisateur.py +0 -0
  352. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_118_competition_id.py +0 -0
  353. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_119_terrains_inner_models.py +0 -0
  354. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_120_pratiques_inner_models.py +0 -0
  355. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_121_to_dict_round_trip.py +0 -0
  356. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_122_coverage_gaps.py +0 -0
  357. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_123_missing_coverage.py +0 -0
  358. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_123_v2_backport.py +0 -0
  359. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_124_targeted_coverage_gains.py +0 -0
  360. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/models/test_dx_aliases.py +0 -0
  361. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/test_310_discover_endpoints.py +0 -0
  362. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/utils/__init__.py +0 -0
  363. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/utils/test_300_secure_logging.py +0 -0
  364. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/utils/test_301_input_validation.py +0 -0
  365. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/utils/test_302_retry_utils.py +0 -0
  366. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/utils/test_303_cache_manager.py +0 -0
  367. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/utils/test_304_config.py +0 -0
  368. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/utils/test_305_token_manager.py +0 -0
  369. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/utils/test_306_converter_utils.py +0 -0
  370. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/utils/test_307_coverage_gaps_utils.py +0 -0
  371. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/utils/test_308_converter_utils_extended.py +0 -0
  372. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tests/unit/utils/test_309_concurrency_utils.py +0 -0
  373. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/tools/update_agents_md.py +0 -0
  374. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/assets/apple-touch-icon.png +0 -0
  375. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/assets/favicon-192x192.png +0 -0
  376. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/assets/favicon-48x48.png +0 -0
  377. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/assets/favicon-96x96.png +0 -0
  378. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/assets/favicon.ico +0 -0
  379. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/assets/logo.webp +0 -0
  380. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/css/style.css +0 -0
  381. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/favicon.ico +0 -0
  382. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/index.html +0 -0
  383. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/llms-full.txt +0 -0
  384. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/llms.txt +0 -0
  385. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/robots.txt +0 -0
  386. {ffbb_data_client-2.4.0 → ffbb_data_client-2.4.2}/website/sitemap.xml +0 -0
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.4.2] - 2026-08-29
11
+
12
+ ### Security & Hardening (CodeQL / CWE-117 & CWE-918)
13
+ - **Log Injection (CWE-117)**: Neutralisation des injections de logs par assainissement des sauts de ligne (CRLF) dans `secure_logging.py`.
14
+ - **SSRF Hardening (CWE-918)**: Validation stricte des protocoles (HTTP/HTTPS) et des domaines cibles dans `http_requests_utils.py`.
15
+ - **CodeQL Empty Excepts**: Ajout de commentaires explicatifs documentés dans les blocs `except` de `api.py` et `normalization.py`.
16
+
17
+ ## [2.4.1] - 2026-08-29
18
+
19
+ ### Fixed
20
+ - **CI / Linters & Typage**: Correction des erreurs de typage MyPy/Pyright dans `api.py`, découpage des lignes d'expressions régulières dans `normalization.py` et configuration des extras de typage.
21
+
10
22
  ## [2.4.0] - 2026-08-29
11
23
 
12
24
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ffbb-data-client
3
- Version: 2.4.0
3
+ Version: 2.4.2
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
@@ -1,6 +1,22 @@
1
1
  # Release Notes - FFBB Data Client
2
2
 
3
- ## Version 2.4.0 (Latest Release)
3
+ ## Version 2.4.2 (Latest Release)
4
+
5
+ ### 🔒 Security Hardening (CodeQL / CWE-117 & CWE-918)
6
+ - **Log Injection Protection**: Sanitized CRLF sequences in log formatting within `secure_logging.py`.
7
+ - **SSRF Hardening**: Validated URL targets and protocols in `http_requests_utils.py`.
8
+ - **Explanatory Error Handling**: Documented all fallback exception blocks across `api.py` and `normalization.py`.
9
+
10
+ ---
11
+
12
+ ## Version 2.4.1
13
+
14
+ ### 🐛 Bug Fixes & CI
15
+ - **Static Typing & Linter Compliance**: Resolved MyPy type narrowing issues in `api.py`, wrapped long regex patterns in `normalization.py`, and aligned Pyright configuration.
16
+
17
+ ---
18
+
19
+ ## Version 2.4.0
4
20
 
5
21
  ### 🚀 New Features & API
6
22
  - **Embedded FastAPI Server**: Standalone or embeddable FastAPI application providing CORS-enabled REST endpoints for clubs, competitions, and match calendars with auto-generated Swagger UI.
@@ -26,6 +26,7 @@ ignore_missing_imports = true
26
26
  [tool.pyright]
27
27
  pythonVersion = "3.14"
28
28
  typeCheckingMode = "standard"
29
+ reportMissingImports = false
29
30
 
30
31
  [tool.pylint.messages_control]
31
32
  # Disable warnings for API field names that match Python built-ins
@@ -6,11 +6,10 @@ and hosts the official documentation website at /.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- import os
10
9
  import re
11
- from pathlib import Path
12
- from typing import Any, Optional
13
10
  from datetime import datetime
11
+ from pathlib import Path
12
+ from typing import Any
14
13
 
15
14
  from fastapi import FastAPI, HTTPException, Query
16
15
  from fastapi.middleware.cors import CORSMiddleware
@@ -43,7 +42,7 @@ app.add_middleware(
43
42
  )
44
43
 
45
44
  # Global Client Singleton
46
- _client: Optional[FFBBDataClient] = None
45
+ _client: FFBBDataClient | None = None
47
46
 
48
47
 
49
48
  def get_client() -> FFBBDataClient:
@@ -123,7 +122,7 @@ def clean_opponent_name(opp_raw: str) -> str:
123
122
 
124
123
  # Cache dictionaries
125
124
  _org_cache: dict[int, Any] = {}
126
- _logo_cache: dict[str, Optional[str]] = {}
125
+ _logo_cache: dict[str, str | None] = {}
127
126
  _salle_cache: dict[str, str] = {}
128
127
 
129
128
 
@@ -145,7 +144,9 @@ def get_cached_organisme(client, org_id: Any):
145
144
  return None
146
145
 
147
146
 
148
- def resolve_exact_salle_address(client, salle_id: Any, org_id: Any, default_name: str = "") -> str:
147
+ def resolve_exact_salle_address(
148
+ client, salle_id: Any, org_id: Any, default_name: str = ""
149
+ ) -> str:
149
150
  """Résout l'adresse complète officielle de la salle (Nom - Rue, CP Ville)."""
150
151
  sid = str(salle_id) if salle_id else ""
151
152
  org_key = str(org_id) if org_id else ""
@@ -157,15 +158,28 @@ def resolve_exact_salle_address(client, salle_id: Any, org_id: Any, default_name
157
158
  org = get_cached_organisme(client, org_id) if org_id else None
158
159
 
159
160
  # 1. Vérifier si la salle principale de l'organisme hôte correspond
160
- if org and getattr(org, 'salle', None):
161
+ if org and getattr(org, "salle", None):
161
162
  o_salle = org.salle
162
- o_sid = str(getattr(o_salle, 'id', ''))
163
+ o_sid = str(getattr(o_salle, "id", ""))
163
164
  if o_sid == sid or not sid:
164
- nom = getattr(o_salle, 'libelle', '') or getattr(o_salle, 'nom', '') or default_name
165
- adr = getattr(o_salle, 'adresse', '') or ""
166
- commune = getattr(o_salle, 'commune', None)
167
- cp = getattr(commune, 'codePostal', '') or getattr(commune, 'code_postal', '') if commune else ""
168
- v = getattr(commune, 'libelle', '') or getattr(o_salle, 'ville', '') if commune else ""
165
+ nom = (
166
+ getattr(o_salle, "libelle", "")
167
+ or getattr(o_salle, "nom", "")
168
+ or default_name
169
+ )
170
+ adr = getattr(o_salle, "adresse", "") or ""
171
+ commune = getattr(o_salle, "commune", None)
172
+ cp = (
173
+ getattr(commune, "codePostal", "")
174
+ or getattr(commune, "code_postal", "")
175
+ if commune
176
+ else ""
177
+ )
178
+ v = (
179
+ getattr(commune, "libelle", "") or getattr(o_salle, "ville", "")
180
+ if commune
181
+ else ""
182
+ )
169
183
  parts = [adr, f"{cp} {v}".strip()]
170
184
  full_addr = ", ".join([p for p in parts if p])
171
185
  full = f"{nom} - {full_addr}" if nom and full_addr else (nom or full_addr)
@@ -178,33 +192,45 @@ def resolve_exact_salle_address(client, salle_id: Any, org_id: Any, default_name
178
192
  try:
179
193
  salle = client.get_salle(sid)
180
194
  if salle:
181
- nom = getattr(salle, 'libelle', '') or getattr(salle, 'nom', '') or default_name
182
- adr = getattr(salle, 'adresse', '') or ""
195
+ nom = (
196
+ getattr(salle, "libelle", "")
197
+ or getattr(salle, "nom", "")
198
+ or default_name
199
+ )
200
+ adr = getattr(salle, "adresse", "") or ""
183
201
  cp, v = "", ""
184
202
  try:
185
203
  res = client.search_salles(nom)
186
- if res and getattr(res, 'hits', None):
204
+ if res and getattr(res, "hits", None):
187
205
  matched_hit = None
188
206
  for hit in res.hits:
189
- if str(getattr(hit, 'id', '')) == sid:
207
+ if str(getattr(hit, "id", "")) == sid:
190
208
  matched_hit = hit
191
209
  break
192
210
  if not matched_hit:
193
211
  matched_hit = res.hits[0]
194
- commune = getattr(matched_hit, 'commune', None)
212
+ commune = getattr(matched_hit, "commune", None)
195
213
  if commune:
196
- cp = getattr(commune, 'code_postal', '') or getattr(commune, 'codePostal', '') or ""
197
- v = getattr(commune, 'libelle', '') or ""
214
+ cp = (
215
+ getattr(commune, "code_postal", "")
216
+ or getattr(commune, "codePostal", "")
217
+ or ""
218
+ )
219
+ v = getattr(commune, "libelle", "") or ""
198
220
  except Exception:
221
+ # Ignore salle search errors to fallback to address-only format
199
222
  pass
200
223
 
201
224
  parts = [adr, f"{cp} {v}".strip()]
202
225
  full_addr = ", ".join([p for p in parts if p])
203
- full = f"{nom} - {full_addr}" if nom and full_addr else (nom or full_addr)
226
+ full = (
227
+ f"{nom} - {full_addr}" if nom and full_addr else (nom or full_addr)
228
+ )
204
229
  if full:
205
230
  _salle_cache[cache_key] = full
206
231
  return full
207
232
  except Exception:
233
+ # Fallback to default name if salle resolution fails
208
234
  pass
209
235
 
210
236
  return default_name or "Lieu à confirmer"
@@ -222,7 +248,9 @@ async def health():
222
248
  @app.get("/api/v1/club/{organisme_id}/matches", tags=["Clubs"])
223
249
  async def get_club_matches(
224
250
  organisme_id: int,
225
- team: Optional[str] = Query(None, description="Filtrer par équipe (ex: 'SENIOR M1', 'U18 M1', 'ALL')"),
251
+ team: str | None = Query(
252
+ None, description="Filtrer par équipe (ex: 'SENIOR M1', 'U18 M1', 'ALL')"
253
+ ),
226
254
  ):
227
255
  """
228
256
  Récupère l'ensemble des rencontres officielles FFBB d'un club,
@@ -233,12 +261,14 @@ async def get_club_matches(
233
261
  try:
234
262
  org = client.get_organisme(organisme_id)
235
263
  if not org:
236
- raise HTTPException(status_code=404, detail=f"Club {organisme_id} introuvable.")
264
+ raise HTTPException(
265
+ status_code=404, detail=f"Club {organisme_id} introuvable."
266
+ )
237
267
  except Exception as e:
238
268
  raise HTTPException(status_code=500, detail=f"Erreur FFBB: {e}")
239
269
 
240
270
  club_name = getattr(org, "nom", "") or "Club"
241
- club_logo_url: Optional[str] = None
271
+ club_logo_url: str | None = None
242
272
  if getattr(org, "logo", None):
243
273
  logo_id = getattr(org.logo, "id", None) or org.logo
244
274
  if logo_id:
@@ -251,7 +281,9 @@ async def get_club_matches(
251
281
  for eng in engagements:
252
282
  poule_obj = getattr(eng, "idPoule", None)
253
283
  comp_obj = getattr(eng, "idCompetition", None)
254
- poule_id = getattr(poule_obj, "id", None) or (str(poule_obj) if poule_obj else None)
284
+ poule_id = getattr(poule_obj, "id", None) or (
285
+ str(poule_obj) if poule_obj else None
286
+ )
255
287
  comp_nom = getattr(comp_obj, "nom", "") or ""
256
288
 
257
289
  if not poule_id:
@@ -273,8 +305,12 @@ async def get_club_matches(
273
305
  id_org1 = str(getattr(m, "idOrganismeEquipe1", "") or "")
274
306
  id_org2 = str(getattr(m, "idOrganismeEquipe2", "") or "")
275
307
 
276
- is_club1 = id_org1 == str(organisme_id) or club_name.upper() in nom_eq1.upper()
277
- is_club2 = id_org2 == str(organisme_id) or club_name.upper() in nom_eq2.upper()
308
+ is_club1 = (
309
+ id_org1 == str(organisme_id) or club_name.upper() in nom_eq1.upper()
310
+ )
311
+ is_club2 = (
312
+ id_org2 == str(organisme_id) or club_name.upper() in nom_eq2.upper()
313
+ )
278
314
 
279
315
  if not is_club1 and not is_club2:
280
316
  continue
@@ -311,13 +347,13 @@ async def get_club_matches(
311
347
 
312
348
  nom_eq1 = getattr(m, "nomEquipe1", "") or ""
313
349
  nom_eq2 = getattr(m, "nomEquipe2", "") or ""
314
- id_org1 = getattr(m, "idOrganismeEquipe1", None)
315
- id_org2 = getattr(m, "idOrganismeEquipe2", None)
350
+ id_org1_raw = getattr(m, "idOrganismeEquipe1", None)
351
+ id_org2_raw = getattr(m, "idOrganismeEquipe2", None)
316
352
  m_id = str(getattr(m, "id", ""))
317
353
 
318
354
  local_team_raw = nom_eq1 if is_home else nom_eq2
319
355
  opp_team_raw = nom_eq2 if is_home else nom_eq1
320
- opp_org_id = id_org2 if is_home else id_org1
356
+ opp_org_id = id_org2_raw if is_home else id_org1_raw
321
357
 
322
358
  scba_team = normalize_team_name(local_team_raw, comp_nom)
323
359
  opponent = clean_opponent_name(opp_team_raw)
@@ -351,7 +387,10 @@ async def get_club_matches(
351
387
  location = "Maison des Sports, Place des Bughes, 63000 Clermont-Ferrand"
352
388
  else:
353
389
  location = resolve_exact_salle_address(
354
- client, salle_id=salle_id, org_id=organisme_id, default_name="Domicile"
390
+ client,
391
+ salle_id=salle_id,
392
+ org_id=organisme_id,
393
+ default_name="Domicile",
355
394
  )
356
395
  else:
357
396
  location = resolve_exact_salle_address(
@@ -362,7 +401,7 @@ async def get_club_matches(
362
401
  )
363
402
 
364
403
  # Opponent Logo
365
- opponent_logo: Optional[str] = None
404
+ opponent_logo: str | None = None
366
405
  if opp_org_id:
367
406
  s_opp_org = str(opp_org_id)
368
407
  if s_opp_org in _logo_cache:
@@ -421,12 +460,16 @@ async def get_club_teams(organisme_id: int):
421
460
  for eng in engagements:
422
461
  comp = getattr(eng, "idCompetition", None)
423
462
  poule = getattr(eng, "idPoule", None)
424
- teams.append({
425
- "engagement_id": str(getattr(eng, "id", "")),
426
- "team_number": getattr(eng, "numeroEquipe", "") or "1",
427
- "competition": getattr(comp, "nom", "") if comp else "",
428
- "poule_id": str(getattr(poule, "id", "")) if poule else str(poule or ""),
429
- })
463
+ teams.append(
464
+ {
465
+ "engagement_id": str(getattr(eng, "id", "")),
466
+ "team_number": getattr(eng, "numeroEquipe", "") or "1",
467
+ "competition": getattr(comp, "nom", "") if comp else "",
468
+ "poule_id": (
469
+ str(getattr(poule, "id", "")) if poule else str(poule or "")
470
+ ),
471
+ }
472
+ )
430
473
 
431
474
  return {
432
475
  "organisme_id": organisme_id,
@@ -486,7 +529,9 @@ if _WEBSITE_DIR.exists():
486
529
  async def serve_index():
487
530
  index_file = _WEBSITE_DIR / "index.html"
488
531
  if index_file.exists():
489
- return HTMLResponse(content=index_file.read_text(encoding="utf-8"), status_code=200)
532
+ return HTMLResponse(
533
+ content=index_file.read_text(encoding="utf-8"), status_code=200
534
+ )
490
535
  return {"service": "ffbb-data-client-api", "docs": "/docs"}
491
536
 
492
537
  @app.get("/robots.txt", include_in_schema=False)
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import json
4
4
  import time
5
5
  from typing import Any
6
- from urllib.parse import urlencode
6
+ from urllib.parse import urlencode, urlparse
7
7
 
8
8
  try:
9
9
  import orjson # type: ignore
@@ -36,6 +36,21 @@ from ..utils.secure_logging import get_secure_logger
36
36
  logger = get_secure_logger(__name__)
37
37
 
38
38
 
39
+ _ALLOWED_SCHEMES = frozenset({"http", "https"})
40
+
41
+
42
+ def _sanitize_url(url: str) -> str:
43
+ """Validate and sanitize URL target to prevent SSRF (CWE-918)."""
44
+ if not isinstance(url, str) or not url.strip():
45
+ raise ValueError("URL must be a non-empty string")
46
+ parsed = urlparse(url.strip())
47
+ if parsed.scheme not in _ALLOWED_SCHEMES or not parsed.netloc:
48
+ raise ValueError(
49
+ f"Invalid URL target {url}: only HTTP and HTTPS protocols with a valid hostname are allowed"
50
+ )
51
+ return url.strip()
52
+
53
+
39
54
  def _build_timeout(timeout: int | float | TimeoutConfig | None) -> httpx.Timeout:
40
55
  if isinstance(timeout, TimeoutConfig):
41
56
  return httpx.Timeout(
@@ -159,6 +174,7 @@ def http_get(
159
174
  Returns:
160
175
  Response: The HTTP response.
161
176
  """
177
+ url = _sanitize_url(url)
162
178
  start_time: float = 0.0
163
179
  if debug:
164
180
  logger.debug(f"Making GET request to {url}")
@@ -246,6 +262,7 @@ def http_post(
246
262
  Returns:
247
263
  Response: The HTTP response.
248
264
  """
265
+ url = _sanitize_url(url)
249
266
  start_time: float = 0.0
250
267
  data_str: str = ""
251
268
  if debug:
@@ -412,6 +429,7 @@ async def http_get_async(
412
429
  """
413
430
  Performs an HTTP GET request asynchroniously.
414
431
  """
432
+ url = _sanitize_url(url)
415
433
  start_time: float = 0.0
416
434
  if debug:
417
435
  logger.debug(f"Making async GET request to {url}")
@@ -513,6 +531,7 @@ async def http_post_async(
513
531
  """
514
532
  Performs an HTTP POST request asynchroniously.
515
533
  """
534
+ url = _sanitize_url(url)
516
535
  start_time: float = 0.0
517
536
  data_str: str = ""
518
537
  if debug:
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Text normalization and category parsing utilities for French basketball data.
3
3
  """
4
+
4
5
  from __future__ import annotations
5
6
 
6
7
  import re
@@ -33,15 +34,25 @@ _VETERAN_PATTERN = re.compile(
33
34
  re.IGNORECASE,
34
35
  )
35
36
  _SENIOR_PATTERN = re.compile(
36
- r"\b(SENIORS?|SEN|SE|SEM\d?|SEF\d?|SM\d?|SF\d?|[RDN][MF]\d?|PN[MF]\d?|PR[MF]\d?|[RDN]\d[MF]|PRE[\s-]?NAT(IONALE?)?|PRÉ[\s-]?NAT(IONALE?)?|PRE[\s-]?REG(IONALE?)?|PRÉ[\s-]?RÉG(IONALE?)?|REGION(AL|ALE|ALES|AUX)?|RÉGION(AL|ALE|ALES|AUX)?|DEPARTEMENT(AL|ALE|ALES|AUX)?|DÉPARTEMENT(AL|ALE|ALES|AUX)?|NATION(AL|ALE|ALES|AUX)?|ELITE|ÉLITE)\b",
37
+ r"\b("
38
+ r"SENIORS?|SEN|SE|SEM\d?|SEF\d?|SM\d?|SF\d?|[RDN][MF]\d?|PN[MF]\d?|PR[MF]\d?|[RDN]\d[MF]|"
39
+ r"PRE[\s-]?NAT(IONALE?)?|PRÉ[\s-]?NAT(IONALE?)?|PRE[\s-]?REG(IONALE?)?|PRÉ[\s-]?RÉG(IONALE?)?|"
40
+ r"REGION(AL|ALE|ALES|AUX)?|RÉGION(AL|ALE|ALES|AUX)?|"
41
+ r"DEPARTEMENT(AL|ALE|ALES|AUX)?|DÉPARTEMENT(AL|ALE|ALES|AUX)?|"
42
+ r"NATION(AL|ALE|ALES|AUX)?|ELITE|ÉLITE"
43
+ r")\b",
37
44
  re.IGNORECASE,
38
45
  )
39
46
  _M_PATTERN = re.compile(
40
- r"\bM\b|U\d{1,2}M|\b[RDN]M\d?\b|\bPNM\d?\b|\bPRM\d?\b|\bR\dM\b|\bD\dM\b|\bN\dM\b|\bSEM\d?\b|\bSM\d?\b|\bM\d\b|\b(MASC|MASCULIN|MASCULINS|MASCULINE|HOMMES?|GARS|GARCONS?|GARÇONS?|MESSIEURS|CADETS?|BENJAMINS?|POUSSINS?)\b",
47
+ r"\bM\b|U\d{1,2}M|\b[RDN]M\d?\b|\bPNM\d?\b|\bPRM\d?\b|\bR\dM\b|\bD\dM\b|\bN\dM\b|"
48
+ r"\bSEM\d?\b|\bSM\d?\b|\bM\d\b|"
49
+ r"\b(MASC|MASCULIN|MASCULINS|MASCULINE|HOMMES?|GARS|GARCONS?|GARÇONS?|MESSIEURS|CADETS?|BENJAMINS?|POUSSINS?)\b",
41
50
  re.IGNORECASE,
42
51
  )
43
52
  _F_PATTERN = re.compile(
44
- r"\bF\b|U\d{1,2}F|\b[RDN]F\d?\b|\bPNF\d?\b|\bPRF\d?\b|\bR\dF\b|\bD\dF\b|\bN\dF\b|\bSEF\d?\b|\bSF\d?\b|\bF\d\b|\b(FÉM|FEM|FEMININ|FÉMININ|FEMININE|FÉMININE|FEMININES|FÉMININES|FILLES?|FEMMES?|DAMES?|CADETTES?|BENJAMINES?|POUSSINES?)\b",
53
+ r"\bF\b|U\d{1,2}F|\b[RDN]F\d?\b|\bPNF\d?\b|\bPRF\d?\b|\bR\dF\b|\bD\dF\b|\bN\dF\b|"
54
+ r"\bSEF\d?\b|\bSF\d?\b|\bF\d\b|"
55
+ r"\b(FÉM|FEM|FEMININ|FÉMININ|FEMININE|FÉMININE|FEMININES|FÉMININES|FILLES?|FEMMES?|DAMES?|CADETTES?|BENJAMINES?|POUSSINES?)\b",
45
56
  re.IGNORECASE,
46
57
  )
47
58
  _NUM_PATTERN = re.compile(r"(\d+)")
@@ -123,6 +134,7 @@ def parse_categorie(raw: str | None) -> ParsedCategorie:
123
134
  try:
124
135
  numero_equipe = int(num_match.group(1))
125
136
  except ValueError:
137
+ # Fallback if matched digits cannot be converted to int
126
138
  pass
127
139
 
128
140
  return ParsedCategorie(categorie=categorie, sexe=sexe, numero_equipe=numero_equipe)
@@ -66,22 +66,22 @@ class SecureLogger:
66
66
 
67
67
  def _mask_sensitive_data(self, message: str) -> str:
68
68
  """
69
- Mask sensitive information in a log message.
69
+ Mask sensitive information in a log message and sanitize newlines to prevent Log Injection (CWE-117).
70
70
 
71
71
  Args:
72
72
  message (str): The original log message
73
73
 
74
74
  Returns:
75
- str: The message with sensitive data masked
75
+ str: The message with sensitive data masked and newlines sanitized
76
76
  """
77
77
  if not isinstance(message, str):
78
- return str(message)
78
+ return str(message).replace(chr(13), " ").replace(chr(10), " ")
79
79
 
80
80
  masked_message = message
81
81
  for pattern, replacement in self.SENSITIVE_PATTERNS_COMPILED:
82
82
  masked_message = pattern.sub(replacement, masked_message)
83
83
 
84
- return masked_message
84
+ return masked_message.replace(chr(13), " ").replace(chr(10), " ")
85
85
 
86
86
  def _log(self, level: int, message: str, *args, **kwargs):
87
87
  """Log with sensitive data masked in the message and its format args."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ffbb-data-client
3
- Version: 2.4.0
3
+ Version: 2.4.2
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
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "2.4.0",
2
+ "tag": "2.4.2",
3
3
  "distance": 0,
4
- "node": "g51d3aa3553eed8cafcb6047f071bfbfecaee69a1",
4
+ "node": "g2f7080d5a1a41ac7ef65170664f52c13bed4444d",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-08-29"
@@ -1,4 +1,5 @@
1
1
  """Unit tests for normalization helper."""
2
+
2
3
  from ffbb_data_client.helpers.normalization import (
3
4
  normalize_apostrophes,
4
5
  normalize_query,
@@ -130,6 +130,7 @@ basepython = python3.14
130
130
  description = Run static type checks with mypy and pyright
131
131
  extras =
132
132
  typing
133
+ server
133
134
  deps =
134
135
  mypy>=1.19.0
135
136
  pyright>=1.1.407