settfex 0.22.2__tar.gz → 0.24.0__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 (279) hide show
  1. {settfex-0.22.2 → settfex-0.24.0}/.github/workflows/dependency-drift.yml +24 -1
  2. {settfex-0.22.2 → settfex-0.24.0}/.github/workflows/release.yml +29 -4
  3. {settfex-0.22.2 → settfex-0.24.0}/AGENTS.md +106 -16
  4. {settfex-0.22.2 → settfex-0.24.0}/CHANGELOG.md +401 -0
  5. {settfex-0.22.2 → settfex-0.24.0}/CLAUDE.md +72 -2
  6. {settfex-0.22.2 → settfex-0.24.0}/PKG-INFO +22 -1
  7. {settfex-0.22.2 → settfex-0.24.0}/README.md +21 -0
  8. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/sec/financial_report.md +82 -9
  9. {settfex-0.22.2 → settfex-0.24.0}/examples/sec/01_financial_report.ipynb +39 -8
  10. {settfex-0.22.2 → settfex-0.24.0}/pyproject.toml +1 -1
  11. {settfex-0.22.2 → settfex-0.24.0}/settfex/__init__.py +21 -1
  12. {settfex-0.22.2 → settfex-0.24.0}/settfex/exceptions.py +92 -3
  13. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/sec/__init__.py +2 -0
  14. settfex-0.24.0/settfex/services/sec/company.py +211 -0
  15. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/sec/download.py +99 -39
  16. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/sec/financial_report.py +420 -68
  17. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/sec/sec.py +27 -6
  18. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/holiday.py +16 -1
  19. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/info.py +4 -1
  20. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/list.py +16 -4
  21. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/analyst_consensus.py +13 -11
  22. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/corporate_action.py +3 -3
  23. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/financial/financial.py +2 -2
  24. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/info.py +11 -2
  25. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/price_performance.py +4 -4
  26. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/trading_stat.py +3 -3
  27. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/availability.py +50 -1
  28. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/history.py +60 -3
  29. {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/data_fetcher.py +17 -1
  30. {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/parsing.py +45 -14
  31. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/api_surface.json +378 -73
  32. settfex-0.24.0/tests/services/sec/test_code_isolation.py +281 -0
  33. settfex-0.24.0/tests/services/sec/test_company.py +346 -0
  34. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_download_result.py +21 -5
  35. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_financial_report.py +34 -10
  36. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_financial_report_accounting.py +51 -1
  37. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_financial_report_th.py +2 -2
  38. settfex-0.24.0/tests/services/sec/test_sec.py +121 -0
  39. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_holiday.py +74 -5
  40. settfex-0.24.0/tests/services/test_fault_matrix.py +407 -0
  41. {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/test_list.py +4 -2
  42. {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/test_trading_statistics.py +4 -2
  43. {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/test_underlying_price.py +7 -2
  44. {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/test_availability.py +89 -0
  45. {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/test_history.py +121 -0
  46. settfex-0.24.0/tests/test_documented_exceptions.py +153 -0
  47. settfex-0.24.0/tests/test_readme_links.py +133 -0
  48. settfex-0.24.0/tests/test_typing_surface.py +135 -0
  49. {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_parsing.py +22 -7
  50. {settfex-0.22.2 → settfex-0.24.0}/uv.lock +1 -1
  51. settfex-0.22.2/settfex/services/sec/company.py +0 -96
  52. settfex-0.22.2/tests/services/sec/test_company.py +0 -80
  53. settfex-0.22.2/tests/services/sec/test_sec.py +0 -68
  54. {settfex-0.22.2 → settfex-0.24.0}/.editorconfig +0 -0
  55. {settfex-0.22.2 → settfex-0.24.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  56. {settfex-0.22.2 → settfex-0.24.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  57. {settfex-0.22.2 → settfex-0.24.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  58. {settfex-0.22.2 → settfex-0.24.0}/.github/dependabot.yml +0 -0
  59. {settfex-0.22.2 → settfex-0.24.0}/.github/instructions/core-architectrual-principles.instructions.md +0 -0
  60. {settfex-0.22.2 → settfex-0.24.0}/.github/instructions/documentation-standards.instructions.md +0 -0
  61. {settfex-0.22.2 → settfex-0.24.0}/.github/instructions/file-organization.instructions.md +0 -0
  62. {settfex-0.22.2 → settfex-0.24.0}/.github/instructions/git-commit.instructions.md +0 -0
  63. {settfex-0.22.2 → settfex-0.24.0}/.github/instructions/python-dependency-management.instructions.md +0 -0
  64. {settfex-0.22.2 → settfex-0.24.0}/.github/prompts/Coding.prompt.md +0 -0
  65. {settfex-0.22.2 → settfex-0.24.0}/.github/prompts/Git-Commit-Reviewer.prompt.md +0 -0
  66. {settfex-0.22.2 → settfex-0.24.0}/.github/prompts/Prompt-Engineer.prompt.md +0 -0
  67. {settfex-0.22.2 → settfex-0.24.0}/.github/prompts/Python-Architect.prompt.md +0 -0
  68. {settfex-0.22.2 → settfex-0.24.0}/.github/workflows/ci.yml +0 -0
  69. {settfex-0.22.2 → settfex-0.24.0}/.github/workflows/pre-commit.yml +0 -0
  70. {settfex-0.22.2 → settfex-0.24.0}/.github/workflows/security.yml +0 -0
  71. {settfex-0.22.2 → settfex-0.24.0}/.gitignore +0 -0
  72. {settfex-0.22.2 → settfex-0.24.0}/.pre-commit-config.yaml +0 -0
  73. {settfex-0.22.2 → settfex-0.24.0}/.python-version +0 -0
  74. {settfex-0.22.2 → settfex-0.24.0}/CODE_OF_CONDUCT.md +0 -0
  75. {settfex-0.22.2 → settfex-0.24.0}/COMPREHENSIVE_AUDIT.md +0 -0
  76. {settfex-0.22.2 → settfex-0.24.0}/CONTRIBUTING.md +0 -0
  77. {settfex-0.22.2 → settfex-0.24.0}/LICENSE +0 -0
  78. {settfex-0.22.2 → settfex-0.24.0}/RELEASING.md +0 -0
  79. {settfex-0.22.2 → settfex-0.24.0}/SECURITY.md +0 -0
  80. {settfex-0.22.2 → settfex-0.24.0}/docs/guide/PYTHON_LIBRARY_BEST_PRACTICES.md +0 -0
  81. {settfex-0.22.2 → settfex-0.24.0}/docs/index.md +0 -0
  82. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/API_PROTECTION_NOTE.md +0 -0
  83. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/analyst_consensus.md +0 -0
  84. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/board_of_director.md +0 -0
  85. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/chart_quotation.md +0 -0
  86. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/corporate_action.md +0 -0
  87. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/dr_indicative_price.md +0 -0
  88. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/earnings_call.md +0 -0
  89. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/financial.md +0 -0
  90. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/highlight_data.md +0 -0
  91. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/holiday.md +0 -0
  92. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/index.md +0 -0
  93. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/info.md +0 -0
  94. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/latest_historical_trading.md +0 -0
  95. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/list.md +0 -0
  96. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/news.md +0 -0
  97. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/nvdr_holder.md +0 -0
  98. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/price_performance.md +0 -0
  99. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/profile_company.md +0 -0
  100. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/profile_dr.md +0 -0
  101. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/profile_stock.md +0 -0
  102. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/shareholder.md +0 -0
  103. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/set/trading_stat.md +0 -0
  104. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/tfex/list.md +0 -0
  105. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/tfex/trading_statistics.md +0 -0
  106. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/services/thaibma/yield_curve.md +0 -0
  107. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/utils/data_fetcher.md +0 -0
  108. {settfex-0.22.2 → settfex-0.24.0}/docs/settfex/utils/session_caching.md +0 -0
  109. {settfex-0.22.2 → settfex-0.24.0}/docs/solution/FINDINGS.md +0 -0
  110. {settfex-0.22.2 → settfex-0.24.0}/docs/solution/Performance Boost Session Caching Implementation.md +0 -0
  111. {settfex-0.22.2 → settfex-0.24.0}/docs/solution/SESSION_CACHE_SUMMARY.md +0 -0
  112. {settfex-0.22.2 → settfex-0.24.0}/docs/solution/SOLUTION_100_PERCENT.md +0 -0
  113. {settfex-0.22.2 → settfex-0.24.0}/examples/README.md +0 -0
  114. {settfex-0.22.2 → settfex-0.24.0}/examples/set/01_stock_list.ipynb +0 -0
  115. {settfex-0.22.2 → settfex-0.24.0}/examples/set/02_highlight_data.ipynb +0 -0
  116. {settfex-0.22.2 → settfex-0.24.0}/examples/set/03_stock_profile.ipynb +0 -0
  117. {settfex-0.22.2 → settfex-0.24.0}/examples/set/04_company_profile.ipynb +0 -0
  118. {settfex-0.22.2 → settfex-0.24.0}/examples/set/05_corporate_action.ipynb +0 -0
  119. {settfex-0.22.2 → settfex-0.24.0}/examples/set/06_shareholder.ipynb +0 -0
  120. {settfex-0.22.2 → settfex-0.24.0}/examples/set/07_nvdr_holder.ipynb +0 -0
  121. {settfex-0.22.2 → settfex-0.24.0}/examples/set/08_board_of_director.ipynb +0 -0
  122. {settfex-0.22.2 → settfex-0.24.0}/examples/set/09_trading_statistics.ipynb +0 -0
  123. {settfex-0.22.2 → settfex-0.24.0}/examples/set/10_price_performance.ipynb +0 -0
  124. {settfex-0.22.2 → settfex-0.24.0}/examples/set/11_financial.ipynb +0 -0
  125. {settfex-0.22.2 → settfex-0.24.0}/examples/set/12_earnings_call.ipynb +0 -0
  126. {settfex-0.22.2 → settfex-0.24.0}/examples/set/13_chart_quotation.ipynb +0 -0
  127. {settfex-0.22.2 → settfex-0.24.0}/examples/set/14_latest_historical_trading.ipynb +0 -0
  128. {settfex-0.22.2 → settfex-0.24.0}/examples/set/15_market_index.ipynb +0 -0
  129. {settfex-0.22.2 → settfex-0.24.0}/examples/set/16_news.ipynb +0 -0
  130. {settfex-0.22.2 → settfex-0.24.0}/examples/set/17_holiday.ipynb +0 -0
  131. {settfex-0.22.2 → settfex-0.24.0}/examples/set/18_dr_and_asset_type.ipynb +0 -0
  132. {settfex-0.22.2 → settfex-0.24.0}/examples/set/19_analyst_consensus.ipynb +0 -0
  133. {settfex-0.22.2 → settfex-0.24.0}/examples/set/20_stock_info.ipynb +0 -0
  134. {settfex-0.22.2 → settfex-0.24.0}/examples/set/README.md +0 -0
  135. {settfex-0.22.2 → settfex-0.24.0}/examples/set/cpall_balance_sheet.csv +0 -0
  136. {settfex-0.22.2 → settfex-0.24.0}/examples/set/market_dashboard_20251005_173221.csv +0 -0
  137. {settfex-0.22.2 → settfex-0.24.0}/examples/set/market_dashboard_20251005_210737.csv +0 -0
  138. {settfex-0.22.2 → settfex-0.24.0}/examples/set/market_dashboard_20251006_091440.csv +0 -0
  139. {settfex-0.22.2 → settfex-0.24.0}/examples/set/thailand_banking_stocks.csv +0 -0
  140. {settfex-0.22.2 → settfex-0.24.0}/examples/set/thailand_set_main_board.csv +0 -0
  141. {settfex-0.22.2 → settfex-0.24.0}/examples/set/thailand_stock_universe.csv +0 -0
  142. {settfex-0.22.2 → settfex-0.24.0}/examples/tfex/01_series_list.ipynb +0 -0
  143. {settfex-0.22.2 → settfex-0.24.0}/examples/tfex/02_trading_statistics.ipynb +0 -0
  144. {settfex-0.22.2 → settfex-0.24.0}/examples/tfex/03_underlying_price.ipynb +0 -0
  145. {settfex-0.22.2 → settfex-0.24.0}/examples/thaibma/01_government_yield_curve.ipynb +0 -0
  146. {settfex-0.22.2 → settfex-0.24.0}/settfex/py.typed +0 -0
  147. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/__init__.py +0 -0
  148. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/sec/constants.py +0 -0
  149. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/sec/utils.py +0 -0
  150. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/__init__.py +0 -0
  151. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/asset_type.py +0 -0
  152. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/constants.py +0 -0
  153. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/earnings_call.py +0 -0
  154. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/__init__.py +0 -0
  155. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/chart_quotation.py +0 -0
  156. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/composition.py +0 -0
  157. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/index.py +0 -0
  158. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/index/utils.py +0 -0
  159. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/list.py +0 -0
  160. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/news.py +0 -0
  161. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/__init__.py +0 -0
  162. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/board_of_director.py +0 -0
  163. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/chart_quotation.py +0 -0
  164. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/dr_indicative_price.py +0 -0
  165. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/financial/__init__.py +0 -0
  166. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/highlight_data.py +0 -0
  167. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/latest_historical_trading.py +0 -0
  168. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/nvdr_holder.py +0 -0
  169. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/profile_company.py +0 -0
  170. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/profile_dr.py +0 -0
  171. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/profile_stock.py +0 -0
  172. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/shareholder.py +0 -0
  173. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/stock.py +0 -0
  174. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/set/stock/utils.py +0 -0
  175. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/tfex/__init__.py +0 -0
  176. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/tfex/constants.py +0 -0
  177. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/tfex/list.py +0 -0
  178. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/tfex/trading_statistics.py +0 -0
  179. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/tfex/underlying_price.py +0 -0
  180. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/__init__.py +0 -0
  181. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/constants.py +0 -0
  182. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/thaibma.py +0 -0
  183. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/utils.py +0 -0
  184. {settfex-0.22.2 → settfex-0.24.0}/settfex/services/thaibma/yield_curve.py +0 -0
  185. {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/__init__.py +0 -0
  186. {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/http.py +0 -0
  187. {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/logging.py +0 -0
  188. {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/session_cache.py +0 -0
  189. {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/session_manager.py +0 -0
  190. {settfex-0.22.2 → settfex-0.24.0}/settfex/utils/youtube_transcript.py +0 -0
  191. {settfex-0.22.2 → settfex-0.24.0}/tests/__init__.py +0 -0
  192. {settfex-0.22.2 → settfex-0.24.0}/tests/conftest.py +0 -0
  193. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/analyst_consensus.json +0 -0
  194. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/dr_profile.json +0 -0
  195. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/earnings_call_item.json +0 -0
  196. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/highlight_data.json +0 -0
  197. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/holiday_calendar.json +0 -0
  198. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/index_list_response.json +0 -0
  199. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/news_search_response.json +0 -0
  200. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/sec_company_match.json +0 -0
  201. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/stock_info.json +0 -0
  202. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/stock_list_response.json +0 -0
  203. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/tfex_series_list_response.json +0 -0
  204. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/tfex_trading_statistics.json +0 -0
  205. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/tfex_underlying_price.json +0 -0
  206. {settfex-0.22.2 → settfex-0.24.0}/tests/golden/model_contract/yield_curve.json +0 -0
  207. {settfex-0.22.2 → settfex-0.24.0}/tests/integration/__init__.py +0 -0
  208. {settfex-0.22.2 → settfex-0.24.0}/tests/integration/test_live_endpoints.py +0 -0
  209. {settfex-0.22.2 → settfex-0.24.0}/tests/services/__init__.py +0 -0
  210. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/__init__.py +0 -0
  211. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/derive_th_fixtures.py +0 -0
  212. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures.py +0 -0
  213. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/README.md +0 -0
  214. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/capital_indirection_en.html +0 -0
  215. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/en_mother_fs_h1_2025.html +0 -0
  216. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/en_ptt_56_1.html +0 -0
  217. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/en_ptt_56_2.html +0 -0
  218. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/en_ptt_fs_h1_2025.html +0 -0
  219. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/en_ptt_viewmore_56_2.html +0 -0
  220. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/idisc_505_error_page.html +0 -0
  221. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/th_cpall_viewmore_56_1.html +0 -0
  222. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/th_mother_fs_h1_2025.html +0 -0
  223. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/th_ptt_56_1.html +0 -0
  224. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/th_ptt_56_2.html +0 -0
  225. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/fixtures_sec/th_ptt_fs_h1_2025.html +0 -0
  226. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_download.py +0 -0
  227. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_download_indirection.py +0 -0
  228. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_listing_transport.py +0 -0
  229. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_utils.py +0 -0
  230. {settfex-0.22.2 → settfex-0.24.0}/tests/services/sec/test_view_more_slugs.py +0 -0
  231. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/__init__.py +0 -0
  232. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/index/__init__.py +0 -0
  233. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/index/test_chart_quotation.py +0 -0
  234. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/index/test_composition.py +0 -0
  235. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/index/test_index.py +0 -0
  236. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/index/test_info.py +0 -0
  237. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/index/test_list.py +0 -0
  238. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/__init__.py +0 -0
  239. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/financial/__init__.py +0 -0
  240. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/financial/test_financial.py +0 -0
  241. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/test_analyst_consensus.py +0 -0
  242. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/test_chart_quotation.py +0 -0
  243. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/test_dr_indicative_price.py +0 -0
  244. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/test_info.py +0 -0
  245. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/test_latest_historical_trading.py +0 -0
  246. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/stock/test_profile_dr.py +0 -0
  247. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_asset_type.py +0 -0
  248. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_board_of_director.py +0 -0
  249. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_client.py +0 -0
  250. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_corporate_action.py +0 -0
  251. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_earnings_call.py +0 -0
  252. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_historical.py +0 -0
  253. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_list.py +0 -0
  254. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_news.py +0 -0
  255. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_profile_company.py +0 -0
  256. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_realtime.py +0 -0
  257. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_shareholder.py +0 -0
  258. {settfex-0.22.2 → settfex-0.24.0}/tests/services/set/test_symbol_suggestion.py +0 -0
  259. {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/__init__.py +0 -0
  260. {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/test_client.py +0 -0
  261. {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/test_historical.py +0 -0
  262. {settfex-0.22.2 → settfex-0.24.0}/tests/services/tfex/test_realtime.py +0 -0
  263. {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/__init__.py +0 -0
  264. {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/fixtures.py +0 -0
  265. {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/test_thaibma.py +0 -0
  266. {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/test_utils.py +0 -0
  267. {settfex-0.22.2 → settfex-0.24.0}/tests/services/thaibma/test_yield_curve.py +0 -0
  268. {settfex-0.22.2 → settfex-0.24.0}/tests/test_impersonate_target.py +0 -0
  269. {settfex-0.22.2 → settfex-0.24.0}/tests/test_model_contract.py +0 -0
  270. {settfex-0.22.2 → settfex-0.24.0}/tests/test_public_api_surface.py +0 -0
  271. {settfex-0.22.2 → settfex-0.24.0}/tests/utils/__init__.py +0 -0
  272. {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_data_fetcher.py +0 -0
  273. {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_formatting.py +0 -0
  274. {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_http.py +0 -0
  275. {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_logging.py +0 -0
  276. {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_session_cache.py +0 -0
  277. {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_session_manager.py +0 -0
  278. {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_validation.py +0 -0
  279. {settfex-0.22.2 → settfex-0.24.0}/tests/utils/test_youtube_transcript.py +0 -0
@@ -21,6 +21,17 @@ permissions:
21
21
  contents: read
22
22
  issues: write
23
23
 
24
+ # Serialise runs. This does NOT stop a double *refresh* -- the two runs on 2026-09-19 were separate
25
+ # manual dispatches 20 minutes apart, each lasting ~16 s, so they never overlapped and a group would
26
+ # have changed nothing. What it does guard is the read-modify-write below: two OVERLAPPING runs
27
+ # could both find no open issue, both pass the `-z "$NUMBER"` check, and CREATE TWO standing issues
28
+ # -- which then permanently breaks the "exactly one" invariant this workflow depends on.
29
+ # `cancel-in-progress: false` on purpose: cancelling mid-write could leave the issue body replaced
30
+ # and its comment missing.
31
+ concurrency:
32
+ group: dependency-drift
33
+ cancel-in-progress: false
34
+
24
35
  jobs:
25
36
  report:
26
37
  name: Outdated report
@@ -157,5 +168,17 @@ jobs:
157
168
  --body-file body.md
158
169
  else
159
170
  gh issue edit "$NUMBER" --body-file body.md
160
- gh issue comment "$NUMBER" --body "Refreshed $(date -u +%F) by the dependency-drift workflow."
171
+ # Comment at most ONCE per day. The body edit above is idempotent -- it is replaced
172
+ # wholesale and carries its own date header -- but the comment is append-only, so a
173
+ # second dispatch on the same day left #109 with two identical "Refreshed" comments
174
+ # (observed 2026-09-19, 20 minutes apart). The comment exists to raise a notification,
175
+ # and a second notification for an unchanged report is noise.
176
+ TODAY=$(date -u +%F)
177
+ ALREADY=$(gh issue view "$NUMBER" --json comments \
178
+ --jq "[.comments[] | select(.body | contains(\"Refreshed ${TODAY}\"))] | length")
179
+ if [ "${ALREADY:-0}" -eq 0 ]; then
180
+ gh issue comment "$NUMBER" --body "Refreshed ${TODAY} by the dependency-drift workflow."
181
+ else
182
+ echo "Already refreshed today (${ALREADY} comment(s)); body updated, comment skipped."
183
+ fi
161
184
  fi
@@ -12,6 +12,11 @@ on:
12
12
  tags:
13
13
  - 'v[0-9]+.[0-9]+.[0-9]+'
14
14
  - 'v[0-9]+.[0-9]+.[0-9]+-*'
15
+ # PEP 440 spells a pre-release with NO hyphen (0.24.0rc1); SemVer uses one (0.24.0-rc1).
16
+ # The tag mirrors the pyproject version, which must be PEP 440, so both spellings are
17
+ # accepted. Without this line `v0.24.0rc1` matched neither pattern and the workflow simply
18
+ # never ran -- a tag push that looks successful and publishes nothing.
19
+ - 'v[0-9]+.[0-9]+.[0-9]+[a-z]+[0-9]+'
15
20
 
16
21
  permissions:
17
22
  contents: write # create GitHub Release + upload assets
@@ -36,7 +41,10 @@ jobs:
36
41
  VERSION="${TAG#v}"
37
42
  echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
38
43
 
39
- if [[ "$TAG" =~ -(alpha|beta|rc) ]]; then
44
+ # The hyphen is OPTIONAL: PEP 440 writes `0.24.0rc1`, so requiring `-rc` would have
45
+ # classified the first PEP 440 pre-release this repo ever tagged as a FULL release and
46
+ # marked it "Latest" on GitHub -- the opposite of the intent.
47
+ if [[ "$TAG" =~ -?(alpha|beta|rc)[0-9]*$ ]]; then
40
48
  echo "is_prerelease=true" >> "$GITHUB_OUTPUT"
41
49
  else
42
50
  echo "is_prerelease=false" >> "$GITHUB_OUTPUT"
@@ -177,9 +185,26 @@ jobs:
177
185
  import re, sys
178
186
  version = sys.argv[1]
179
187
  content = open("CHANGELOG.md").read()
180
- pattern = rf"(?m)^## \[{re.escape(version)}\][^\n]*\n(.*?)(?=^## \[|\Z)"
181
- match = re.search(pattern, content, re.DOTALL)
182
- notes = match.group(1).strip() if match else f"Release v{version}"
188
+
189
+ def section(heading: str) -> str | None:
190
+ pattern = rf"(?m)^## \[{re.escape(heading)}\][^\n]*\n(.*?)(?=^## \[|\Z)"
191
+ found = re.search(pattern, content, re.DOTALL)
192
+ return found.group(1).strip() if found else None
193
+
194
+ # A pre-release documents the version it is a candidate FOR: `0.24.0rc1` is described by
195
+ # the `## [0.24.0]` section, and duplicating that section under an rc heading would mean
196
+ # maintaining two copies of the same notes. So fall back to the base version.
197
+ # Without this the body silently became the stub "Release v0.24.0rc1" -- a release that
198
+ # looks fine and carries none of its own notes.
199
+ base = re.match(r"^(\d+\.\d+\.\d+)", version)
200
+ notes = section(version)
201
+ if notes is None and base is not None and base.group(1) != version:
202
+ notes = section(base.group(1))
203
+ if notes is not None:
204
+ notes = f"> Pre-release of **{base.group(1)}**.\n\n{notes}"
205
+ if notes is None:
206
+ print(f"::error::No CHANGELOG section for {version} or its base version")
207
+ sys.exit(1)
183
208
  with open("release_notes.txt", "w") as f:
184
209
  f.write(notes + "\n")
185
210
  PYEOF
@@ -107,12 +107,37 @@ Indices: `get_index_list(lang)`, `get_index_info(symbol, lang)`,
107
107
 
108
108
  | I want… | Call |
109
109
  |---|---|
110
- | resolve a company to its SEC id | `resolve_company(query, lang)` |
110
+ | resolve a company to its SEC id | `resolve_company(query, lang, allow_name_match=False)` |
111
111
  | list filings (financial statements, 56-1, 56-2, ratios, MD&A) | `get_sec_documents(query, types=..., from_date=..., to_date=...)` |
112
112
  | download the actual file(s) | `download_sec_document(target)` / `download_sec_documents(targets)` |
113
113
 
114
114
  Dates here are **dd/mm/yyyy**. Pass a wide window to see full year history.
115
115
 
116
+ ⚠️ **Not every SET symbol is an SEC issuer.** ETFs, warrants, DWs and `-F` foreign lines do not
117
+ file, so resolving one of them raises rather than guessing (0.24.0):
118
+
119
+ | outcome | exception | what to do |
120
+ |---|---|---|
121
+ | nothing matched | `CompanyNotFoundError` | report that no issuer exists; do not retry |
122
+ | several matched, none flagged | `AmbiguousCompanyError` | read `exc.candidates` (each a `CompanyMatch`) and ask which one, or pass an exact symbol |
123
+ | **exactly one matched, not flagged** | `AmbiguousCompanyError` | the site did not recognise your query as an *identifier*, so that row is a substring hit on a company **name**. If you meant a name, pass `allow_name_match=True`; if you meant a symbol, it is not an SEC issuer |
124
+
125
+ **Searching by company name?** Pass `allow_name_match=True` — a name never flags, so a name lookup
126
+ always lands in that third row:
127
+
128
+ ```python
129
+ await get_sec_documents("CP ALL PUBLIC COMPANY LIMITED", allow_name_match=True)
130
+ await resolve_company("ปตท", allow_name_match=True) # still raises: 17 candidates, none flagged
131
+ ```
132
+
133
+ It only ever affects the **single**-candidate case. Several unflagged candidates stay ambiguous
134
+ whatever you intended.
135
+
136
+ Both are **`ValueError`s, not `FetchError`s**, because the request succeeded — retrying returns the
137
+ same answer forever, so `except FetchError: retry` must not be what catches them. Before 0.24.0 the
138
+ second case returned an arbitrary alphabetically-first company: `CHINA` (an ETF) resolved to
139
+ `ASEAN CHINA INVESTMENT FUND L.P.` and every filing listed under it was the wrong company's.
140
+
116
141
  `lang="th"` works and returns the **Thai-language filing documents** — different files from the
117
142
  English ones, not a translated index. Years and dates come back as **C.E.** in the model even
118
143
  though the Thai page states them in the Buddhist era (`2568` → `2025`). Free-text cells
@@ -130,16 +155,35 @@ listing where **every** usable row was lost raises `IncompleteListingError` rath
130
155
  transport: a failed request raises `FetchError`, and a body that is not a listing page raises
131
156
  `ParseError`, instead of parsing to zero rows and looking like "this issuer filed nothing".
132
157
 
133
- One thing deliberately does **not** raise: a broken "display all results" page. That section keeps
134
- its truncated inline rows and the shortfall shows in `completeness()` — so check that before
135
- treating a section as complete. As of 2026-09-20 SEC's Thai `fs-kf` page answers HTTP 500, which is
136
- an upstream bug, not a settfex one.
158
+ Two things deliberately do **not** raise. A broken "display all results" page: that section keeps
159
+ its truncated inline rows and the shortfall shows in `completeness()`. And **one failing report
160
+ code**: the others keep their documents, and the failure is recorded on
161
+ `docs.accounting.failed_codes` (with a WARNING). So after a call that returned normally, check
162
+ `docs.accounting.has_losses` before treating the result as complete — an exception is no longer how
163
+ a partial failure announces itself. `repr(docs)` states it too.
164
+
165
+ As of 2026-09-20 SEC's Thai `fs-kf` page answers HTTP 500, which is an upstream bug, not a settfex
166
+ one; it shows up as a `key_financial_ratio` shortfall on Thai listings.
167
+
168
+ As of 0.24.0 `SecDocumentList` is a **Pydantic model** `{documents, accounting, reported_counts}`
169
+ that still iterates, indexes and slices like the list it used to be — and a **slice keeps the
170
+ accounting** (of the whole call, not of the slice). So `model_dump()` and JSON carry the
171
+ completeness signal, which matters here more than anywhere: what you receive from a tool call is
172
+ JSON, so a signal that does not serialize does not reach you at all.
173
+
174
+ ⚠️ `isinstance(docs, list)` is now `False` — it fails *silently*, by taking the other branch. Use
175
+ `docs.documents` where a real list is needed. `sorted(docs)` and `list(docs)` still give plain
176
+ lists, so sort `docs.documents`.
177
+
178
+ ⚠️ A section whose "display all results" page failed lands on `accounting.degraded_sections` and
179
+ sets `has_losses` — that is how the live Thai `fs-kf` HTTP 500 above surfaces.
137
180
 
138
181
  `download_sec_documents(...)` returns a `DownloadResult` — a list of the files that downloaded,
139
182
  which also carries `.failed` (each with its target and reason) and `.is_complete`. Check it before
140
183
  reporting a batch as done; dead links on the SEC host arrive as HTML under HTTP 200, not as errors.
141
- ⚠️ Read `.failed` off **that** object: it is a `list` subclass, so slicing, `sorted()`, `list()` and
142
- comprehensions all return a plain `list` and drop the failure report without warning.
184
+ Also a Pydantic model since 0.24.0 (`{files, failed, requested}` + computed `is_complete`), so the
185
+ failure report survives `model_dump()` and slicing. ⚠️ `isinstance(files, list)` is `False`; use
186
+ `files.files`.
143
187
 
144
188
  ### ThaiBMA bonds — `from settfex.services.thaibma import ...`
145
189
 
@@ -225,23 +269,62 @@ being wrong, so none of them will announce itself.
225
269
 
226
270
  ## Errors you should expect
227
271
 
272
+ Everything is importable from one place:
273
+
228
274
  ```python
229
275
  from settfex.exceptions import (
230
- FetchError, # HTTP/transport failure; carries .status_code and .symbol
231
- SymbolNotFoundError, # subclass of FetchError; HTTP 404, may carry .suggestion
232
- StaleDataError, # ThaiBMA rolled back and you asked it to raise
233
- InvalidSymbolError, # empty symbol — raised before any request
234
- InvalidLanguageError, # unrecognized lang
235
- InvalidDateError, # malformed date string — raised before any request
276
+ # --- the FETCH family: `except FetchError` catches all of these ---
277
+ FetchError, # HTTP/transport failure; carries .status_code and .symbol
278
+ HTTPStatusError, # a non-2xx, with .url and .report_code as data
279
+ SymbolNotFoundError, # HTTP 404 on a SET endpoint; may carry .suggestion
280
+ StaleDataError, # ThaiBMA rolled back and you asked it to raise
281
+ ParseError, # a response arrived intact and could not be mapped
282
+ IncompleteListingError, # a ParseError: rows classified, then every one was lost
283
+ # --- INPUT errors: ValueErrors, NOT caught by `except FetchError` ---
284
+ CompanyNotFoundError, # SEC: the search ran and matched no issuer
285
+ AmbiguousCompanyError, # SEC: several matched, none flagged; carries .candidates
286
+ InvalidSymbolError, # empty symbol — raised before any request
287
+ InvalidLanguageError, # unrecognized lang
288
+ InvalidDateError, # malformed date string — raised before any request
236
289
  )
237
- from settfex.utils.parsing import ResponseParseError
290
+ from settfex.utils.parsing import ResponseParseError # also a ParseError since 0.24.0
238
291
  ```
239
292
 
240
- `InvalidSymbolError`, `InvalidLanguageError` and `InvalidDateError` are raised **before** any
241
- network call, so they always mean your arguments are wrong, never that the API is down.
293
+ **The split is the thing to internalise: a `FetchError` may be worth retrying; a `ValueError`
294
+ never is.** An input error means the request *succeeded* and your argument was wrong, so a retry
295
+ loop on one spins forever. `InvalidSymbolError`, `InvalidLanguageError` and `InvalidDateError` are
296
+ raised before any network call at all.
297
+
298
+ ⚠️ Two "not found" taxonomies coexist today: a SET 404 is a `SymbolNotFoundError` (a `FetchError`),
299
+ while the SEC equivalent is a `CompanyNotFoundError` (a `ValueError`). Catch both if you handle
300
+ both hosts. Unifying them is tracked on #135.
301
+
302
+ ⚠️ `ResponseParseError` is also what a **WAF block page** currently surfaces as — right family,
303
+ wrong diagnosis. If you see it repeatedly from one host, **stop and back off**; do not retry.
242
304
 
243
305
  ---
244
306
 
307
+ ## Timed instructions
308
+
309
+ If you are told to do something at a particular time, that instruction needs **a date, a clock time
310
+ and a timezone** — `2026-09-21 17:00 ICT`. Relative words (*today*, *tonight*, *after close*) are
311
+ ambiguous the moment a conversation spans midnight or is resumed later, and they give no signal
312
+ that they have gone stale.
313
+
314
+ **Check the current time before acting on one.** If the window has passed, say so and ask rather
315
+ than substituting the nearest equivalent — the reason a window was chosen (avoiding market hours,
316
+ avoiding another system's traffic) usually does not survive being moved by a day.
317
+
318
+ ## Communication language
319
+
320
+ - All prose you write is in English: reports and chat replies to the operator, commit messages,
321
+ PR descriptions, GitHub issues and comments, docs, ADRs, and code comments.
322
+ - Thai appears only as verbatim source data: document titles, labels (e.g. `สอบทาน`), company
323
+ names, URLs, quoted page text, and fixture contents. Keep it exactly as the source has it —
324
+ never translate or transliterate the data itself.
325
+ - When a Thai value's meaning matters to the reader, add an English gloss next to it:
326
+ `สอบทาน` (reviewed).
327
+
245
328
  ## Working on the repo itself
246
329
 
247
330
  ```bash
@@ -271,3 +354,10 @@ settfex is **not officially affiliated** with SET or TFEX. It reads **public** m
271
354
  Browser impersonation and session caching exist to access that public data reliably and to
272
355
  *reduce* request volume (~25× fewer requests) — not to evade rate limits or terms of service.
273
356
  Respect both.
357
+
358
+ **If you are sweeping many symbols, budget it.** These are other people's servers, and they push
359
+ back: a 929-symbol sweep at concurrency 8 drew connection resets and then a WAF block page — an
360
+ **HTTP 200 whose body reads `Request Rejected`** — for every request for about an hour
361
+ (2026-09-20). Use concurrency 1 with jittered pauses, decide a request budget before you start,
362
+ prefer a stratified sample over a census, and **stop at the first block signal** rather than
363
+ retrying into it.