fmp-data 2.2.1__tar.gz → 2.3.1__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 (201) hide show
  1. {fmp_data-2.2.1 → fmp_data-2.3.1}/PKG-INFO +25 -19
  2. {fmp_data-2.2.1 → fmp_data-2.3.1}/README.md +6 -0
  3. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/alternative/models.py +2 -2
  4. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/base.py +4 -4
  5. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/cache/redis_backend.py +6 -3
  6. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/company/models.py +1 -1
  7. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/lc/embedding.py +1 -1
  8. {fmp_data-2.2.1 → fmp_data-2.3.1}/pyproject.toml +36 -36
  9. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_company.py +1 -1
  10. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/lc/test_embedding.py +1 -1
  11. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_alternative.py +33 -1
  12. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_base.py +42 -0
  13. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_company.py +37 -0
  14. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_intelligence.py +49 -50
  15. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_mcp.py +3 -3
  16. {fmp_data-2.2.1 → fmp_data-2.3.1}/.gitignore +0 -0
  17. {fmp_data-2.2.1 → fmp_data-2.3.1}/LICENSE +0 -0
  18. {fmp_data-2.2.1 → fmp_data-2.3.1}/NOTICE +0 -0
  19. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/__init__.py +0 -0
  20. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/alternative/__init__.py +0 -0
  21. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/alternative/async_client.py +0 -0
  22. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/alternative/client.py +0 -0
  23. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/alternative/endpoints.py +0 -0
  24. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/alternative/mapping.py +0 -0
  25. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/alternative/schema.py +0 -0
  26. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/async_client.py +0 -0
  27. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/batch/__init__.py +0 -0
  28. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/batch/_csv_utils.py +0 -0
  29. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/batch/async_client.py +0 -0
  30. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/batch/client.py +0 -0
  31. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/batch/endpoints.py +0 -0
  32. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/batch/mapping.py +0 -0
  33. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/batch/models.py +0 -0
  34. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/cache/__init__.py +0 -0
  35. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/cache/base.py +0 -0
  36. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/cache/config.py +0 -0
  37. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/cache/file.py +0 -0
  38. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/cache/memory.py +0 -0
  39. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/client.py +0 -0
  40. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/company/__init__.py +0 -0
  41. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/company/async_client.py +0 -0
  42. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/company/client.py +0 -0
  43. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/company/endpoints.py +0 -0
  44. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/company/hints.py +0 -0
  45. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/company/mapping.py +0 -0
  46. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/company/schema.py +0 -0
  47. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/config.py +0 -0
  48. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/economics/__init__.py +0 -0
  49. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/economics/async_client.py +0 -0
  50. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/economics/client.py +0 -0
  51. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/economics/endpoints.py +0 -0
  52. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/economics/mapping.py +0 -0
  53. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/economics/models.py +0 -0
  54. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/economics/schema.py +0 -0
  55. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/exceptions.py +0 -0
  56. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/fundamental/__init__.py +0 -0
  57. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/fundamental/async_client.py +0 -0
  58. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/fundamental/client.py +0 -0
  59. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/fundamental/endpoints.py +0 -0
  60. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/fundamental/mapping.py +0 -0
  61. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/fundamental/models.py +0 -0
  62. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/fundamental/schema.py +0 -0
  63. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/helpers.py +0 -0
  64. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/index/__init__.py +0 -0
  65. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/index/async_client.py +0 -0
  66. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/index/client.py +0 -0
  67. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/index/endpoints.py +0 -0
  68. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/index/mapping.py +0 -0
  69. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/index/models.py +0 -0
  70. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/institutional/__init__.py +0 -0
  71. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/institutional/async_client.py +0 -0
  72. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/institutional/client.py +0 -0
  73. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/institutional/endpoints.py +0 -0
  74. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/institutional/mapping.py +0 -0
  75. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/institutional/models.py +0 -0
  76. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/institutional/schema.py +0 -0
  77. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/intelligence/__init__.py +0 -0
  78. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/intelligence/async_client.py +0 -0
  79. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/intelligence/client.py +0 -0
  80. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/intelligence/endpoints.py +0 -0
  81. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/intelligence/mapping.py +0 -0
  82. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/intelligence/models.py +0 -0
  83. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/intelligence/schema.py +0 -0
  84. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/investment/__init__.py +0 -0
  85. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/investment/async_client.py +0 -0
  86. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/investment/client.py +0 -0
  87. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/investment/endpoints.py +0 -0
  88. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/investment/mapping.py +0 -0
  89. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/investment/models.py +0 -0
  90. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/investment/schema.py +0 -0
  91. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/lc/__init__.py +0 -0
  92. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/lc/config.py +0 -0
  93. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/lc/hints.py +0 -0
  94. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/lc/mapping.py +0 -0
  95. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/lc/models.py +0 -0
  96. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/lc/registry.py +0 -0
  97. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/lc/utils.py +0 -0
  98. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/lc/validation.py +0 -0
  99. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/lc/vector_store.py +0 -0
  100. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/logger.py +0 -0
  101. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/market/__init__.py +0 -0
  102. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/market/async_client.py +0 -0
  103. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/market/client.py +0 -0
  104. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/market/endpoints.py +0 -0
  105. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/market/hints.py +0 -0
  106. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/market/mapping.py +0 -0
  107. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/market/models.py +0 -0
  108. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/market/schema.py +0 -0
  109. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/mcp/__init__.py +0 -0
  110. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/mcp/__main__.py +0 -0
  111. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/mcp/cli.py +0 -0
  112. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/mcp/discovery.py +0 -0
  113. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/mcp/server.py +0 -0
  114. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/mcp/setup.py +0 -0
  115. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/mcp/tool_loader.py +0 -0
  116. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/mcp/tools_manifest.py +0 -0
  117. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/mcp/utils.py +0 -0
  118. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/models.py +0 -0
  119. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/py.typed +0 -0
  120. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/rate_limit.py +0 -0
  121. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/schema.py +0 -0
  122. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/sec/__init__.py +0 -0
  123. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/sec/async_client.py +0 -0
  124. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/sec/client.py +0 -0
  125. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/sec/endpoints.py +0 -0
  126. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/sec/mapping.py +0 -0
  127. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/sec/models.py +0 -0
  128. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/technical/__init__.py +0 -0
  129. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/technical/async_client.py +0 -0
  130. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/technical/client.py +0 -0
  131. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/technical/endpoints.py +0 -0
  132. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/technical/mapping.py +0 -0
  133. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/technical/models.py +0 -0
  134. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/technical/schema.py +0 -0
  135. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/transcripts/__init__.py +0 -0
  136. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/transcripts/async_client.py +0 -0
  137. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/transcripts/client.py +0 -0
  138. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/transcripts/endpoints.py +0 -0
  139. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/transcripts/mapping.py +0 -0
  140. {fmp_data-2.2.1 → fmp_data-2.3.1}/fmp_data/transcripts/models.py +0 -0
  141. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/__init__.py +0 -0
  142. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/examples/__init__.py +0 -0
  143. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/examples/test_examples_smoke.py +0 -0
  144. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/__init__.py +0 -0
  145. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/base.py +0 -0
  146. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/conftest.py +0 -0
  147. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_alternative.py +0 -0
  148. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_batch.py +0 -0
  149. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_economics.py +0 -0
  150. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_fundamental.py +0 -0
  151. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_index.py +0 -0
  152. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_institutional.py +0 -0
  153. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_intelligence.py +0 -0
  154. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_investment.py +0 -0
  155. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_lc.py +0 -0
  156. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_market.py +0 -0
  157. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_sec.py +0 -0
  158. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_technical.py +0 -0
  159. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/integration/test_transcripts.py +0 -0
  160. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/__init__.py +0 -0
  161. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/conftest.py +0 -0
  162. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/lc/__init__.py +0 -0
  163. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/lc/conftest.py +0 -0
  164. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/lc/test_config.py +0 -0
  165. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/lc/test_endpoint_based_rules.py +0 -0
  166. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/lc/test_imports.py +0 -0
  167. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/lc/test_mapping.py +0 -0
  168. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/lc/test_models.py +0 -0
  169. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/lc/test_utils.py +0 -0
  170. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/lc/test_validation_registry.py +0 -0
  171. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/lc/test_vector_store.py +0 -0
  172. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_alternative_coverage.py +0 -0
  173. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_async_clients.py +0 -0
  174. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_base_async.py +0 -0
  175. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_base_coverage.py +0 -0
  176. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_batch.py +0 -0
  177. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_cache_backends.py +0 -0
  178. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_cache_integration.py +0 -0
  179. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_cassette_contracts.py +0 -0
  180. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_client.py +0 -0
  181. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_company_coverage.py +0 -0
  182. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_config.py +0 -0
  183. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_economics.py +0 -0
  184. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_exceptions.py +0 -0
  185. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_fundamental.py +0 -0
  186. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_helpers.py +0 -0
  187. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_index.py +0 -0
  188. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_institutional.py +0 -0
  189. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_investment.py +0 -0
  190. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_logger.py +0 -0
  191. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_market.py +0 -0
  192. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_mcp_cli.py +0 -0
  193. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_models.py +0 -0
  194. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_rate_limit.py +0 -0
  195. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_rate_limit_async.py +0 -0
  196. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_rate_limit_coverage.py +0 -0
  197. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_sec.py +0 -0
  198. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_technical.py +0 -0
  199. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_technical_coverage.py +0 -0
  200. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_transcripts.py +0 -0
  201. {fmp_data-2.2.1 → fmp_data-2.3.1}/tests/unit/test_vcr_sanitization.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmp-data
3
- Version: 2.2.1
3
+ Version: 2.3.1
4
4
  Summary: Python client for the Financial Modeling Prep API
5
5
  Project-URL: Homepage, https://github.com/MehdiZare/fmp-data
6
6
  Project-URL: Repository, https://github.com/MehdiZare/fmp-data
@@ -29,42 +29,42 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
29
29
  Requires-Python: <3.15,>=3.10
30
30
  Requires-Dist: httpx>=0.28.1
31
31
  Requires-Dist: pydantic>=2.12.5
32
- Requires-Dist: tenacity>=9.1.2
32
+ Requires-Dist: tenacity>=9.1.4
33
33
  Provides-Extra: cache-redis
34
- Requires-Dist: redis>=5.0.0; extra == 'cache-redis'
34
+ Requires-Dist: redis>=7.4.0; extra == 'cache-redis'
35
35
  Provides-Extra: dev
36
- Requires-Dist: bandit[toml]>=1.9.3; extra == 'dev'
37
- Requires-Dist: coverage>=7.13.1; extra == 'dev'
36
+ Requires-Dist: bandit[toml]>=1.9.4; extra == 'dev'
37
+ Requires-Dist: coverage>=7.13.5; extra == 'dev'
38
38
  Requires-Dist: freezegun>=1.5.5; extra == 'dev'
39
- Requires-Dist: mypy>=1.19.1; extra == 'dev'
40
- Requires-Dist: nox>=2025.11.12; extra == 'dev'
39
+ Requires-Dist: mypy>=1.20.0; extra == 'dev'
40
+ Requires-Dist: nox>=2026.2.9; extra == 'dev'
41
41
  Requires-Dist: pip-audit>=2.10.0; extra == 'dev'
42
42
  Requires-Dist: pre-commit>=4.5.1; extra == 'dev'
43
43
  Requires-Dist: pytest-asyncio>=1.3.0; extra == 'dev'
44
- Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
44
+ Requires-Dist: pytest-cov>=7.1.0; extra == 'dev'
45
45
  Requires-Dist: pytest-mock>=3.15.1; extra == 'dev'
46
46
  Requires-Dist: pytest-xdist>=3.6.1; extra == 'dev'
47
47
  Requires-Dist: pytest>=9.0.2; extra == 'dev'
48
- Requires-Dist: python-dotenv>=1.1.1; extra == 'dev'
49
- Requires-Dist: responses>=0.25.8; extra == 'dev'
50
- Requires-Dist: rich>=14.3.2; extra == 'dev'
51
- Requires-Dist: ruff>=0.14.13; extra == 'dev'
48
+ Requires-Dist: python-dotenv>=1.2.2; extra == 'dev'
49
+ Requires-Dist: responses>=0.26.0; extra == 'dev'
50
+ Requires-Dist: rich>=14.3.3; extra == 'dev'
51
+ Requires-Dist: ruff>=0.15.9; extra == 'dev'
52
52
  Requires-Dist: twine>=6.2.0; extra == 'dev'
53
53
  Requires-Dist: vcrpy>=8.1.1; extra == 'dev'
54
54
  Provides-Extra: docs
55
- Requires-Dist: mkdocs-material>=9.7.1; extra == 'docs'
55
+ Requires-Dist: mkdocs-material>=9.7.6; extra == 'docs'
56
56
  Requires-Dist: mkdocs>=1.6.1; extra == 'docs'
57
- Requires-Dist: mkdocstrings-python>=2.0.1; extra == 'docs'
57
+ Requires-Dist: mkdocstrings-python>=2.0.3; extra == 'docs'
58
58
  Provides-Extra: langchain
59
59
  Requires-Dist: faiss-cpu>=1.13.2; extra == 'langchain'
60
60
  Requires-Dist: langchain-community>=0.4.1; extra == 'langchain'
61
- Requires-Dist: langchain-core>=1.2.8; extra == 'langchain'
62
- Requires-Dist: langchain-openai>=1.1.7; extra == 'langchain'
63
- Requires-Dist: langgraph>=1.0.6; extra == 'langchain'
64
- Requires-Dist: openai>=2.15.0; extra == 'langchain'
61
+ Requires-Dist: langchain-core>=1.2.26; extra == 'langchain'
62
+ Requires-Dist: langchain-openai>=1.1.12; extra == 'langchain'
63
+ Requires-Dist: langgraph>=1.1.6; extra == 'langchain'
64
+ Requires-Dist: openai>=2.30.0; extra == 'langchain'
65
65
  Requires-Dist: tiktoken>=0.12.0; extra == 'langchain'
66
66
  Provides-Extra: mcp
67
- Requires-Dist: mcp[cli]>=1.25.0; extra == 'mcp'
67
+ Requires-Dist: mcp[cli]>=1.27.0; extra == 'mcp'
68
68
  Requires-Dist: pyyaml>=6.0.3; extra == 'mcp'
69
69
  Description-Content-Type: text/markdown
70
70
 
@@ -118,6 +118,12 @@ To use this library, you'll need an API key from Financial Modeling Prep (FMP).
118
118
 
119
119
  ## Installation
120
120
 
121
+ ## Launch Notes
122
+
123
+ - Price-history volume fields now normalize to `float` so integer and fractional FMP payloads share one stable return type.
124
+ - This affects `alternative.HistoricalPrice.volume`, `alternative.HistoricalPrice.unadjusted_volume`, and `company.IntradayPrice.volume`.
125
+ - Whole-number payloads for those models now deserialize as values like `123.0`, which is why this ships as a minor release instead of a patch.
126
+
121
127
  ### Using UV (Recommended)
122
128
 
123
129
  ```bash
@@ -48,6 +48,12 @@ To use this library, you'll need an API key from Financial Modeling Prep (FMP).
48
48
 
49
49
  ## Installation
50
50
 
51
+ ## Launch Notes
52
+
53
+ - Price-history volume fields now normalize to `float` so integer and fractional FMP payloads share one stable return type.
54
+ - This affects `alternative.HistoricalPrice.volume`, `alternative.HistoricalPrice.unadjusted_volume`, and `company.IntradayPrice.volume`.
55
+ - Whole-number payloads for those models now deserialize as values like `123.0`, which is why this ships as a minor release instead of a patch.
56
+
51
57
  ### Using UV (Recommended)
52
58
 
53
59
  ```bash
@@ -119,8 +119,8 @@ class HistoricalPrice(BaseModel):
119
119
  adj_close: float | None = Field(
120
120
  None, alias="adjClose", description="Adjusted closing price"
121
121
  )
122
- volume: int = Field(description="Volume traded")
123
- unadjusted_volume: int | None = Field(
122
+ volume: float = Field(description="Volume traded")
123
+ unadjusted_volume: float | None = Field(
124
124
  None, alias="unadjustedVolume", description="Unadjusted trading volume"
125
125
  )
126
126
  change: float = Field(description="Price change")
@@ -564,27 +564,27 @@ class BaseClient:
564
564
  status_code=429,
565
565
  response=error_details,
566
566
  retry_after=wait_time,
567
- ) from error
567
+ ) from None
568
568
 
569
569
  if status_code == 401:
570
570
  raise AuthenticationError(
571
571
  "Invalid API key or authentication failed",
572
572
  status_code=401,
573
573
  response=error_details,
574
- ) from error
574
+ ) from None
575
575
 
576
576
  if status_code == 400:
577
577
  raise ValidationError(
578
578
  f"Invalid request parameters: {error_details}",
579
579
  status_code=400,
580
580
  response=error_details,
581
- ) from error
581
+ ) from None
582
582
 
583
583
  raise FMPError(
584
584
  f"HTTP {status_code} error occurred: {error_details}",
585
585
  status_code=status_code,
586
586
  response=error_details,
587
- ) from error
587
+ ) from None
588
588
 
589
589
  @staticmethod
590
590
  def _check_error_response(data: dict[str, Any]) -> None:
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import json
6
6
  import logging
7
- from typing import Any
7
+ from typing import Any, cast
8
8
 
9
9
  from fmp_data.cache.base import CacheBackend
10
10
 
@@ -44,7 +44,7 @@ class RedisCache(CacheBackend):
44
44
 
45
45
  def get(self, key: str) -> Any | None:
46
46
  try:
47
- raw = self._client.get(self._prefixed(key))
47
+ raw = cast(str | None, self._client.get(self._prefixed(key)))
48
48
  except Exception:
49
49
  logger.warning("Redis get error for key %s", key, exc_info=True)
50
50
  return None
@@ -74,7 +74,10 @@ class RedisCache(CacheBackend):
74
74
  cursor: int = 0
75
75
  try:
76
76
  while True:
77
- cursor, keys = self._client.scan(cursor, match=pattern, count=100)
77
+ cursor, keys = cast(
78
+ tuple[int, list[str]],
79
+ self._client.scan(cursor, match=pattern, count=100),
80
+ )
78
81
  if keys:
79
82
  self._client.delete(*keys)
80
83
  if cursor == 0:
@@ -517,7 +517,7 @@ class IntradayPrice(BaseModel):
517
517
  low: float = Field(description="Low price")
518
518
  high: float = Field(description="High price")
519
519
  close: float = Field(description="Closing price")
520
- volume: int = Field(description="Trading volume")
520
+ volume: float = Field(description="Trading volume")
521
521
 
522
522
 
523
523
  class ExecutiveCompensation(BaseModel):
@@ -64,7 +64,7 @@ class EmbeddingConfig(BaseModel):
64
64
  from langchain_openai import OpenAIEmbeddings
65
65
 
66
66
  return OpenAIEmbeddings(
67
- api_key=self.api_key,
67
+ openai_api_key=self.api_key,
68
68
  model=self.model_name or "text-embedding-ada-002",
69
69
  **self.additional_kwargs,
70
70
  )
@@ -1,7 +1,7 @@
1
1
  [build-system]
2
2
  requires = [
3
- "hatchling>=1.22.0",
4
- "hatch-vcs>=0.4.0",
3
+ "hatchling>=1.29.0",
4
+ "hatch-vcs>=0.5.0",
5
5
  ]
6
6
  build-backend = "hatchling.build"
7
7
 
@@ -48,7 +48,7 @@ classifiers = [
48
48
  dependencies = [
49
49
  "httpx>=0.28.1",
50
50
  "pydantic>=2.12.5",
51
- "tenacity>=9.1.2",
51
+ "tenacity>=9.1.4",
52
52
  ]
53
53
 
54
54
  [project.license]
@@ -64,84 +64,84 @@ fmp-mcp = "fmp_data.mcp.cli:main"
64
64
 
65
65
  [project.optional-dependencies]
66
66
  mcp = [
67
- "mcp[cli]>=1.25.0",
67
+ "mcp[cli]>=1.27.0",
68
68
  "pyyaml>=6.0.3",
69
69
  ]
70
70
  cache-redis = [
71
- "redis>=5.0.0",
71
+ "redis>=7.4.0",
72
72
  ]
73
73
  langchain = [
74
74
  "faiss-cpu>=1.13.2",
75
- "langchain-core>=1.2.8",
75
+ "langchain-core>=1.2.26",
76
76
  "langchain-community>=0.4.1",
77
- "langchain-openai>=1.1.7",
78
- "langgraph>=1.0.6",
79
- "openai>=2.15.0",
77
+ "langchain-openai>=1.1.12",
78
+ "langgraph>=1.1.6",
79
+ "openai>=2.30.0",
80
80
  "tiktoken>=0.12.0",
81
81
  ]
82
82
  dev = [
83
- "ruff>=0.14.13",
84
- "mypy>=1.19.1",
85
- "bandit[toml]>=1.9.3",
83
+ "ruff>=0.15.9",
84
+ "mypy>=1.20.0",
85
+ "bandit[toml]>=1.9.4",
86
86
  "pip-audit>=2.10.0",
87
- "python-dotenv>=1.1.1",
87
+ "python-dotenv>=1.2.2",
88
88
  "pytest>=9.0.2",
89
89
  "pytest-asyncio>=1.3.0",
90
- "pytest-cov>=7.0.0",
90
+ "pytest-cov>=7.1.0",
91
91
  "pytest-mock>=3.15.1",
92
92
  "pytest-xdist>=3.6.1",
93
93
  "freezegun>=1.5.5",
94
- "responses>=0.25.8",
94
+ "responses>=0.26.0",
95
95
  "vcrpy>=8.1.1",
96
- "coverage>=7.13.1",
96
+ "coverage>=7.13.5",
97
97
  "pre-commit>=4.5.1",
98
- "rich>=14.3.2",
98
+ "rich>=14.3.3",
99
99
  "twine>=6.2.0",
100
- "nox>=2025.11.12",
100
+ "nox>=2026.2.9",
101
101
  ]
102
102
  docs = [
103
103
  "mkdocs>=1.6.1",
104
- "mkdocs-material>=9.7.1",
105
- "mkdocstrings-python>=2.0.1",
104
+ "mkdocs-material>=9.7.6",
105
+ "mkdocstrings-python>=2.0.3",
106
106
  ]
107
107
 
108
108
  [dependency-groups]
109
109
  dev = [
110
- "ruff>=0.14.13",
111
- "mypy>=1.19.1",
112
- "bandit[toml]>=1.9.3",
110
+ "ruff>=0.15.9",
111
+ "mypy>=1.20.0",
112
+ "bandit[toml]>=1.9.4",
113
113
  "pip-audit>=2.10.0",
114
- "python-dotenv>=1.1.1",
114
+ "python-dotenv>=1.2.2",
115
115
  "pytest>=9.0.2",
116
116
  "pytest-asyncio>=1.3.0",
117
- "pytest-cov>=7.0.0",
117
+ "pytest-cov>=7.1.0",
118
118
  "pytest-mock>=3.15.1",
119
119
  "pytest-xdist>=3.6.1",
120
120
  "freezegun>=1.5.5",
121
- "responses>=0.25.8",
121
+ "responses>=0.26.0",
122
122
  "vcrpy>=8.1.1",
123
- "coverage>=7.13.1",
123
+ "coverage>=7.13.5",
124
124
  "pre-commit>=4.5.1",
125
- "rich>=14.3.2",
125
+ "rich>=14.3.3",
126
126
  "twine>=6.2.0",
127
- "nox>=2025.11.12",
127
+ "nox>=2026.2.9",
128
128
  ]
129
129
  docs = [
130
130
  "mkdocs>=1.6.1",
131
- "mkdocs-material>=9.7.1",
132
- "mkdocstrings-python>=2.0.1",
131
+ "mkdocs-material>=9.7.6",
132
+ "mkdocstrings-python>=2.0.3",
133
133
  ]
134
134
  langchain = [
135
135
  "faiss-cpu>=1.13.2",
136
- "langchain-core>=1.2.8",
136
+ "langchain-core>=1.2.26",
137
137
  "langchain-community>=0.4.1",
138
- "langchain-openai>=1.1.7",
139
- "langgraph>=1.0.6",
140
- "openai>=2.15.0",
138
+ "langchain-openai>=1.1.12",
139
+ "langgraph>=1.1.6",
140
+ "openai>=2.30.0",
141
141
  "tiktoken>=0.12.0",
142
142
  ]
143
143
  mcp = [
144
- "mcp[cli]>=1.25.0",
144
+ "mcp[cli]>=1.27.0",
145
145
  "pyyaml>=6.0.3",
146
146
  ]
147
147
 
@@ -130,7 +130,7 @@ class TestCompanyEndpoints(BaseTestCase):
130
130
  assert isinstance(price.high, float)
131
131
  assert isinstance(price.low, float)
132
132
  assert isinstance(price.close, float)
133
- assert isinstance(price.volume, int)
133
+ assert isinstance(price.volume, float)
134
134
 
135
135
  def test_get_market_cap(self, fmp_client: FMPDataClient, vcr_instance):
136
136
  """Test getting market capitalization data"""
@@ -54,7 +54,7 @@ def test_get_embeddings_openai(mock_openai):
54
54
 
55
55
  config.get_embeddings()
56
56
  mock_openai.assert_called_once_with(
57
- api_key="test-key", model="text-embedding-ada-002"
57
+ openai_api_key="test-key", model="text-embedding-ada-002"
58
58
  )
59
59
 
60
60
 
@@ -9,6 +9,9 @@ from fmp_data.alternative.models import (
9
9
  CryptoQuote,
10
10
  ForexQuote,
11
11
  )
12
+ from fmp_data.alternative.models import (
13
+ HistoricalPrice as AlternativeHistoricalPrice,
14
+ )
12
15
 
13
16
 
14
17
  @pytest.fixture
@@ -155,7 +158,36 @@ def test_crypto_historical_price_model(mock_crypto_historical):
155
158
  assert price.low == 43500.00
156
159
  assert price.close == 45000.00
157
160
  assert price.adj_close == 45000.00
158
- assert price.volume == 25000000000
161
+ assert price.volume == pytest.approx(25000000000.0)
162
+ assert isinstance(price.volume, float)
159
163
  assert price.change == 1250.00
160
164
  assert price.change_percent == 2.85
161
165
  assert price.vwap == 44500.00
166
+
167
+
168
+ def test_alternative_historical_price_accepts_float_volume(mock_crypto_historical):
169
+ """Test alternative historical price models accept float volume values."""
170
+ historical_data = dict(mock_crypto_historical["historical"][0])
171
+ historical_data["volume"] = 25000000000.75
172
+ historical_data["unadjustedVolume"] = 24999999999.25
173
+
174
+ price = AlternativeHistoricalPrice.model_validate(historical_data)
175
+
176
+ assert price.volume == pytest.approx(25000000000.75)
177
+ assert price.unadjusted_volume == pytest.approx(24999999999.25)
178
+
179
+
180
+ def test_alternative_historical_price_normalizes_integer_volume_to_float(
181
+ mock_crypto_historical,
182
+ ):
183
+ """Test integer volume payloads normalize to float for a single API shape."""
184
+ historical_data = dict(mock_crypto_historical["historical"][0])
185
+ historical_data["volume"] = 123456789
186
+ historical_data["unadjustedVolume"] = 123456700
187
+
188
+ price = AlternativeHistoricalPrice.model_validate(historical_data)
189
+
190
+ assert price.volume == pytest.approx(123456789.0)
191
+ assert isinstance(price.volume, float)
192
+ assert price.unadjusted_volume == pytest.approx(123456700.0)
193
+ assert isinstance(price.unadjusted_volume, float)
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import traceback
2
3
  from unittest.mock import MagicMock, Mock, patch
3
4
 
4
5
  import httpx
@@ -273,6 +274,47 @@ def test_handle_http_status_error_uses_retry_after_header(base_client):
273
274
  assert exc_info.value.retry_after == 12.0
274
275
 
275
276
 
277
+ @pytest.mark.parametrize(
278
+ ("status_code", "expected_exception"),
279
+ [
280
+ (429, RateLimitError),
281
+ (401, AuthenticationError),
282
+ (400, ValidationError),
283
+ (500, FMPError),
284
+ ],
285
+ )
286
+ def test_handle_http_status_error_redacts_chained_apikey_traceback(
287
+ base_client: BaseClient,
288
+ status_code: int,
289
+ expected_exception: type[FMPError],
290
+ ) -> None:
291
+ """Test HTTP error tracebacks do not expose the API key query parameter."""
292
+ marker = "TRACEBACK_REDACTION_SENTINEL"
293
+ request = httpx.Request(
294
+ "GET",
295
+ f"https://financialmodelingprep.com/stable/quote?symbol=AAPL&apikey={marker}",
296
+ )
297
+ response = httpx.Response(
298
+ status_code,
299
+ request=request,
300
+ json={"message": "Rate limit exceeded"},
301
+ )
302
+
303
+ try:
304
+ base_client.handle_response(response)
305
+ except FMPError as exc:
306
+ assert isinstance(exc, expected_exception)
307
+ formatted_traceback = traceback.format_exc()
308
+ assert "apikey=" not in formatted_traceback
309
+ assert marker not in formatted_traceback
310
+ assert "apikey=" not in str(exc)
311
+ assert marker not in str(exc)
312
+ assert exc.__cause__ is None
313
+ assert exc.__suppress_context__ is True
314
+ else:
315
+ pytest.fail(f"Expected {expected_exception.__name__}")
316
+
317
+
276
318
  @pytest.mark.parametrize(
277
319
  "payload",
278
320
  [
@@ -11,6 +11,7 @@ from fmp_data.company.models import (
11
11
  ExecutiveCompensationBenchmark,
12
12
  HistoricalData,
13
13
  HistoricalPrice,
14
+ IntradayPrice,
14
15
  MergerAcquisition,
15
16
  PriceTarget,
16
17
  PriceTargetSummary,
@@ -444,6 +445,42 @@ class TestSimpleQuoteModel:
444
445
  """Test SimpleQuote volume validator handles None."""
445
446
  assert SimpleQuote.coerce_volume_to_int(None) is None
446
447
 
448
+
449
+ class TestIntradayPriceModel:
450
+ """Tests for intraday price model validation"""
451
+
452
+ def test_intraday_price_accepts_float_volume(self):
453
+ """Test intraday prices accept float volume values from the API."""
454
+ data = {
455
+ "date": "2024-01-05T16:00:00",
456
+ "open": 149.00,
457
+ "low": 148.50,
458
+ "high": 151.00,
459
+ "close": 150.25,
460
+ "volume": 28541.004200000316,
461
+ }
462
+
463
+ price = IntradayPrice.model_validate(data)
464
+
465
+ assert price.volume == pytest.approx(28541.004200000316)
466
+ assert isinstance(price.volume, float)
467
+
468
+ def test_intraday_price_normalizes_integer_volume_to_float(self):
469
+ """Test integer intraday volume payloads normalize to float."""
470
+ data = {
471
+ "date": "2024-01-05T16:00:00",
472
+ "open": 149.00,
473
+ "low": 148.50,
474
+ "high": 151.00,
475
+ "close": 150.25,
476
+ "volume": 28541,
477
+ }
478
+
479
+ price = IntradayPrice.model_validate(data)
480
+
481
+ assert price.volume == pytest.approx(28541.0)
482
+ assert isinstance(price.volume, float)
483
+
447
484
  def test_simple_quote_volume_validator_string(self):
448
485
  """Test SimpleQuote volume validator passes non-numeric values."""
449
486
  assert SimpleQuote.coerce_volume_to_int("abc") == "abc"