vlrdevapi 2.2.0__tar.gz → 2.3.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 (213) hide show
  1. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/CHANGELOG.md +52 -0
  2. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/PKG-INFO +13 -2
  3. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/README.md +12 -1
  4. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/pyproject.toml +1 -1
  5. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/scripts/check_mdx_examples.py +1 -1
  6. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/scripts/download_fixtures.py +10 -0
  7. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/__init__.py +17 -7
  8. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/__init__.pyi +15 -0
  9. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_client.py +2 -0
  10. vlrdevapi-2.3.0/src/vlrdevapi/_news/__init__.py +5 -0
  11. vlrdevapi-2.3.0/src/vlrdevapi/_news/article/__init__.py +4 -0
  12. vlrdevapi-2.3.0/src/vlrdevapi/_news/article/models.py +41 -0
  13. vlrdevapi-2.3.0/src/vlrdevapi/_news/article/namespace.py +86 -0
  14. vlrdevapi-2.3.0/src/vlrdevapi/_news/article/namespace.pyi +19 -0
  15. vlrdevapi-2.3.0/src/vlrdevapi/_news/article/parser.py +457 -0
  16. vlrdevapi-2.3.0/src/vlrdevapi/_news/common.py +48 -0
  17. vlrdevapi-2.3.0/src/vlrdevapi/_news/list/__init__.py +4 -0
  18. vlrdevapi-2.3.0/src/vlrdevapi/_news/list/models.py +55 -0
  19. vlrdevapi-2.3.0/src/vlrdevapi/_news/list/namespace.py +85 -0
  20. vlrdevapi-2.3.0/src/vlrdevapi/_news/list/namespace.pyi +19 -0
  21. vlrdevapi-2.3.0/src/vlrdevapi/_news/list/parser.py +109 -0
  22. vlrdevapi-2.3.0/src/vlrdevapi/_news/namespace.py +127 -0
  23. vlrdevapi-2.3.0/src/vlrdevapi/_news/namespace.pyi +21 -0
  24. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_utils/paths.py +13 -0
  25. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/commons/__init__.py +9 -1
  26. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/commons/datetime.py +32 -0
  27. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/validators.py +1 -1
  28. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/uv.lock +1 -1
  29. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/.gitattributes +0 -0
  30. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  31. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  32. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/.github/workflows/cleanup-caches.yml +0 -0
  33. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/.github/workflows/docs-check.yml +0 -0
  34. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/.github/workflows/publish.yml +0 -0
  35. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/.github/workflows/test.yml +0 -0
  36. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/.gitignore +0 -0
  37. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/.python-version +0 -0
  38. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/.readthedocs.yaml +0 -0
  39. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/CODE_OF_CONDUCT.md +0 -0
  40. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/CONTRIBUTING.md +0 -0
  41. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/LICENCE +0 -0
  42. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/SECURITY.md +0 -0
  43. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/SUPPORT.md +0 -0
  44. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_base.py +0 -0
  45. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_cache.py +0 -0
  46. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/__init__.py +0 -0
  47. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/_common.py +0 -0
  48. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/info/__init__.py +0 -0
  49. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/info/models.py +0 -0
  50. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/info/namespace.py +0 -0
  51. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/info/namespace.pyi +0 -0
  52. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/info/parser.py +0 -0
  53. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/list/__init__.py +0 -0
  54. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/list/models.py +0 -0
  55. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/list/namespace.py +0 -0
  56. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/list/namespace.pyi +0 -0
  57. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/list/parser.py +0 -0
  58. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/matches/__init__.py +0 -0
  59. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/matches/models.py +0 -0
  60. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/matches/namespace.py +0 -0
  61. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/matches/namespace.pyi +0 -0
  62. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/matches/parser.py +0 -0
  63. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/namespace.py +0 -0
  64. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/namespace.pyi +0 -0
  65. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/stages/__init__.py +0 -0
  66. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/stages/models.py +0 -0
  67. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/stages/namespace.py +0 -0
  68. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/stages/namespace.pyi +0 -0
  69. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/stages/parser.py +0 -0
  70. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/standings/__init__.py +0 -0
  71. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/standings/models.py +0 -0
  72. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/standings/namespace.py +0 -0
  73. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/standings/namespace.pyi +0 -0
  74. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/standings/parser.py +0 -0
  75. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/teams/__init__.py +0 -0
  76. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/teams/models.py +0 -0
  77. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/teams/namespace.py +0 -0
  78. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/teams/namespace.pyi +0 -0
  79. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_event/teams/parser.py +0 -0
  80. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/__init__.py +0 -0
  81. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/common.py +0 -0
  82. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/completed/__init__.py +0 -0
  83. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/completed/models.py +0 -0
  84. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/completed/namespace.py +0 -0
  85. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/completed/namespace.pyi +0 -0
  86. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/completed/parser.py +0 -0
  87. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/live/__init__.py +0 -0
  88. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/live/models.py +0 -0
  89. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/live/namespace.py +0 -0
  90. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/live/namespace.pyi +0 -0
  91. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/live/parser.py +0 -0
  92. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/namespace.py +0 -0
  93. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/namespace.pyi +0 -0
  94. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/upcoming/__init__.py +0 -0
  95. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/upcoming/models.py +0 -0
  96. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/upcoming/namespace.py +0 -0
  97. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/upcoming/namespace.pyi +0 -0
  98. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_matches/upcoming/parser.py +0 -0
  99. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/__init__.py +0 -0
  100. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/_common_parsing.py +0 -0
  101. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/agents/__init__.py +0 -0
  102. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/agents/models.py +0 -0
  103. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/agents/namespace.py +0 -0
  104. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/agents/namespace.pyi +0 -0
  105. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/agents/parser.py +0 -0
  106. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/info/__init__.py +0 -0
  107. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/info/models.py +0 -0
  108. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/info/namespace.py +0 -0
  109. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/info/namespace.pyi +0 -0
  110. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/info/parser.py +0 -0
  111. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/matches/__init__.py +0 -0
  112. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/matches/models.py +0 -0
  113. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/matches/namespace.py +0 -0
  114. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/matches/namespace.pyi +0 -0
  115. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/matches/parser.py +0 -0
  116. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/namespace.py +0 -0
  117. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/namespace.pyi +0 -0
  118. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/profile/__init__.py +0 -0
  119. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/profile/models.py +0 -0
  120. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/profile/namespace.py +0 -0
  121. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/profile/namespace.pyi +0 -0
  122. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/profile/parser.py +0 -0
  123. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/teams/__init__.py +0 -0
  124. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/teams/models.py +0 -0
  125. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/teams/namespace.py +0 -0
  126. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/teams/namespace.pyi +0 -0
  127. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_player/teams/parser.py +0 -0
  128. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/__init__.py +0 -0
  129. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/_utils.py +0 -0
  130. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/economy/__init__.py +0 -0
  131. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/economy/models.py +0 -0
  132. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/economy/namespace.py +0 -0
  133. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/economy/namespace.pyi +0 -0
  134. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/economy/parser.py +0 -0
  135. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/info/__init__.py +0 -0
  136. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/info/models.py +0 -0
  137. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/info/namespace.py +0 -0
  138. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/info/namespace.pyi +0 -0
  139. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/info/parser.py +0 -0
  140. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/match_namespace.py +0 -0
  141. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/match_namespace.pyi +0 -0
  142. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/namespace.py +0 -0
  143. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/namespace.pyi +0 -0
  144. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/performance/__init__.py +0 -0
  145. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/performance/models.py +0 -0
  146. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/performance/namespace.py +0 -0
  147. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/performance/namespace.pyi +0 -0
  148. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/performance/parser.py +0 -0
  149. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/players/__init__.py +0 -0
  150. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/players/models.py +0 -0
  151. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/players/namespace.py +0 -0
  152. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/players/namespace.pyi +0 -0
  153. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/players/parser.py +0 -0
  154. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/rounds/__init__.py +0 -0
  155. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/rounds/models.py +0 -0
  156. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/rounds/namespace.py +0 -0
  157. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/rounds/namespace.pyi +0 -0
  158. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/rounds/parser.py +0 -0
  159. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/vods/__init__.py +0 -0
  160. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/vods/models.py +0 -0
  161. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/vods/namespace.py +0 -0
  162. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/vods/namespace.pyi +0 -0
  163. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_series/vods/parser.py +0 -0
  164. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/__init__.py +0 -0
  165. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/completed_matches/__init__.py +0 -0
  166. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/completed_matches/models.py +0 -0
  167. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/completed_matches/namespace.py +0 -0
  168. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/completed_matches/namespace.pyi +0 -0
  169. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/completed_matches/parser.py +0 -0
  170. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/info/__init__.py +0 -0
  171. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/info/models.py +0 -0
  172. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/info/namespace.py +0 -0
  173. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/info/namespace.pyi +0 -0
  174. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/info/parser.py +0 -0
  175. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/namespace.py +0 -0
  176. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/namespace.pyi +0 -0
  177. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/placements/__init__.py +0 -0
  178. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/placements/models.py +0 -0
  179. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/placements/namespace.py +0 -0
  180. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/placements/namespace.pyi +0 -0
  181. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/placements/parser.py +0 -0
  182. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/roster/__init__.py +0 -0
  183. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/roster/models.py +0 -0
  184. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/roster/namespace.py +0 -0
  185. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/roster/namespace.pyi +0 -0
  186. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/roster/parser.py +0 -0
  187. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/stats/__init__.py +0 -0
  188. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/stats/models.py +0 -0
  189. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/stats/namespace.py +0 -0
  190. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/stats/namespace.pyi +0 -0
  191. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/stats/parser.py +0 -0
  192. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/transactions/__init__.py +0 -0
  193. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/transactions/models.py +0 -0
  194. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/transactions/namespace.py +0 -0
  195. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/transactions/namespace.pyi +0 -0
  196. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/transactions/parser.py +0 -0
  197. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/upcoming_matches/__init__.py +0 -0
  198. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/upcoming_matches/models.py +0 -0
  199. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/upcoming_matches/namespace.py +0 -0
  200. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/upcoming_matches/namespace.pyi +0 -0
  201. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_team/upcoming_matches/parser.py +0 -0
  202. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_utils/__init__.py +0 -0
  203. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_utils/pagination.py +0 -0
  204. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_utils/team_enrichment.py +0 -0
  205. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/_utils/team_parsing.py +0 -0
  206. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/commons/countries.py +0 -0
  207. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/commons/mappings.py +0 -0
  208. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/commons/prizes.py +0 -0
  209. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/commons/timezone.py +0 -0
  210. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/exceptions.py +0 -0
  211. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/fetcher.py +0 -0
  212. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/src/vlrdevapi/py.typed +0 -0
  213. {vlrdevapi-2.2.0 → vlrdevapi-2.3.0}/wrangler.jsonc +0 -0
@@ -5,6 +5,57 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [2.3.0] - 2026-08-11
9
+
10
+ ### Added
11
+
12
+ - **News namespace** — `vlrdevapi.news(page=1)` lists news items from
13
+ vlr.gg/news, each with `title`, `subtitle`, `link`, `country_name`,
14
+ `date`, and `author`, plus `has_next_page` and `page_number` on the
15
+ returned page.
16
+ - **News article content** — `vlrdevapi.news.article(article_id)` fetches
17
+ a single news article with its `title`, `author`, `date`, associated
18
+ `event_name`/`event_link`, and the full `content` body text. The body
19
+ is also available as Markdown via `content_md`, preserving headings,
20
+ lists, links, emphasis, and clip embeds.
21
+ - **News out-of-range pages** — requesting a news page beyond the last
22
+ available page (e.g. `page=176`) now raises `NotFoundError` instead of
23
+ silently returning an empty result.
24
+
25
+ ### Changed
26
+
27
+ - **News article Markdown links are absolute** — links in `content_md` are
28
+ prefixed with `https://www.vlr.gg` when they were relative (e.g.
29
+ `/player/5132/mada` → `https://www.vlr.gg/player/5132/mada`). Absolute
30
+ and `www.`-prefixed URLs are left untouched. `NewsArticle.event_link` is
31
+ now an absolute URL as well.
32
+
33
+ ### Fixed
34
+
35
+ - **News article clip embeds** — `content_md` clip embeds now link to the
36
+ directly openable watch URL (e.g. `https://clips.twitch.tv/<slug>`) for
37
+ Twitch clips, Twitch VODs, YouTube, and Soop embeds, instead of the embed
38
+ URL which could not be opened in a new tab.
39
+ - **News article Markdown whitespace/emphasis** — inline emphasis and bold
40
+ render correctly around links: source indentation whitespace no longer
41
+ produces double spaces, and `*`/`**` markers no longer wrap whitespace.
42
+ - **News article dates are timezone-aware** — the article date is parsed
43
+ through the shared `commons.parse_vlr_iso_datetime` helper. Offset-aware
44
+ `datetime` attributes are converted to UTC as-is; naive values are
45
+ localised to the client's `source_tz` (or UTC) instead of the local
46
+ machine timezone.
47
+ - **Unknown article IDs raise `NotFoundError`** — vlr.gg returns a generic
48
+ HTTP 200 page for non-existent article IDs; `news.article()` now detects
49
+ the missing article card and raises `NotFoundError` instead of returning
50
+ an empty article.
51
+ - **News article Markdown fidelity** — `content_md` now renders nested
52
+ lists, tables (as pipe tables), and inline `code` verbatim (whitespace
53
+ preserved). Links whose href is `www.`-prefixed are upgraded to
54
+ `https://`, fixing broken relative links in Markdown.
55
+ - **Documentation** — news reference pages updated (article, list, index),
56
+ plus the getting-started guide, main docs index, and README now cover the
57
+ news namespace; model/parser docstrings describe the current behaviour.
58
+
8
59
  ## [2.2.0] - 2026-08-11
9
60
 
10
61
  ### Changed
@@ -142,6 +193,7 @@ The API surface, module structure, and type system are all new.
142
193
  - `aiohttp` and `asyncio` dependencies.
143
194
  - v1.x match/event/team parsing modules.
144
195
 
196
+ [2.3.0]: https://github.com/Vanshbordia/vlrdevapi/compare/v2.2.0...v2.3.0
145
197
  [2.2.0]: https://github.com/Vanshbordia/vlrdevapi/compare/v2.1.0...v2.2.0
146
198
  [2.1.0]: https://github.com/Vanshbordia/vlrdevapi/compare/v2.0.1...v2.1.0
147
199
  [2.0.1]: https://github.com/Vanshbordia/vlrdevapi/compare/v2.0.0...v2.0.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vlrdevapi
3
- Version: 2.2.0
3
+ Version: 2.3.0
4
4
  Summary: A Python library to scrape data from vlr.gg
5
5
  Project-URL: Homepage, https://vlrdevapi.pages.dev/
6
6
  Project-URL: Repository, https://github.com/Vanshbordia/vlrdevapi
@@ -68,7 +68,7 @@ Access Valorant esports data from VLR.gg with a clean, type-safe Python API. Get
68
68
 
69
69
  ## Features
70
70
 
71
- - **Complete Data Access** - Events, matches, players, teams, and series
71
+ - **Complete Data Access** - Events, matches, players, teams, series, and news
72
72
  - **Type-Safe** - Pydantic models with rich type hints and field descriptions
73
73
  - **Production-Ready** - Retry logic, rate limiting, and LRU-cached enrichment
74
74
  - **Curried Access** - Bind a player/team/series ID once, then call sub-methods without re-passing
@@ -181,6 +181,17 @@ performance = s.performance() # Advanced performance stats
181
181
  economy = s.economy(game_id=1) # Economy data
182
182
  ```
183
183
 
184
+ ### News
185
+
186
+ ```python
187
+ page = client.news(page=1) # Browse the news listing
188
+ for item in page.news[:5]:
189
+ print(item.title)
190
+
191
+ article = client.news.article(734100) # Fetch a full article
192
+ print(article.content_md) # Article body as Markdown
193
+ ```
194
+
184
195
  ## Documentation
185
196
 
186
197
  - **Official Docs** - [vlrdevapi.pages.dev/docs](https://vlrdevapi.pages.dev/docs)
@@ -20,7 +20,7 @@ Access Valorant esports data from VLR.gg with a clean, type-safe Python API. Get
20
20
 
21
21
  ## Features
22
22
 
23
- - **Complete Data Access** - Events, matches, players, teams, and series
23
+ - **Complete Data Access** - Events, matches, players, teams, series, and news
24
24
  - **Type-Safe** - Pydantic models with rich type hints and field descriptions
25
25
  - **Production-Ready** - Retry logic, rate limiting, and LRU-cached enrichment
26
26
  - **Curried Access** - Bind a player/team/series ID once, then call sub-methods without re-passing
@@ -133,6 +133,17 @@ performance = s.performance() # Advanced performance stats
133
133
  economy = s.economy(game_id=1) # Economy data
134
134
  ```
135
135
 
136
+ ### News
137
+
138
+ ```python
139
+ page = client.news(page=1) # Browse the news listing
140
+ for item in page.news[:5]:
141
+ print(item.title)
142
+
143
+ article = client.news.article(734100) # Fetch a full article
144
+ print(article.content_md) # Article body as Markdown
145
+ ```
146
+
136
147
  ## Documentation
137
148
 
138
149
  - **Official Docs** - [vlrdevapi.pages.dev/docs](https://vlrdevapi.pages.dev/docs)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "vlrdevapi"
7
- version = "2.2.0"
7
+ version = "2.3.0"
8
8
  description = "A Python library to scrape data from vlr.gg"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -39,7 +39,7 @@ REPO_ROOT = Path(__file__).resolve().parent.parent
39
39
  DOCS_DIR = REPO_ROOT / "official-docs" / "content"
40
40
  DEFAULT_FIXTURES_DIR = REPO_ROOT / ".cache" / "mdx-html"
41
41
 
42
- DYNAMIC_PATHS = frozenset({"/matches", "/matches/results", "/events"})
42
+ DYNAMIC_PATHS = frozenset({"/matches", "/matches/results", "/events", "/news"})
43
43
 
44
44
 
45
45
  class Result(NamedTuple):
@@ -29,6 +29,16 @@ ROUTES += [
29
29
  ("/matches/results/?page=2", "matches/results_page2.html", {}),
30
30
  ]
31
31
 
32
+ # ── News ───────────────────────────────────────────────────────
33
+ ROUTES += [
34
+ ("/news", "news/news.html", {}),
35
+ ("/news/?page=2", "news/news_page2.html", {}),
36
+ ("/news/?page=126", "news/news_page126.html", {}),
37
+ ("/news/?page=176", "news/news_page176.html", {}),
38
+ ("/734100", "news/article_734100.html", {}),
39
+ ("/720033/americas-recent-victors-start-strong-in-week-1", "news/article_720033.html", {}),
40
+ ]
41
+
32
42
  # ── Events ─────────────────────────────────────────────────────
33
43
  ROUTES += [
34
44
  ("/events", "events/events.html", {}),
@@ -1,8 +1,8 @@
1
1
  """vlrdevapi — A Python library to scrape data from vlr.gg.
2
2
 
3
3
  Provides a synchronous, typed interface for accessing match listings,
4
- event data, tournament info, team/player profiles, and statistics
5
- from vlr.gg.
4
+ event data, tournament info, team/player profiles, statistics, and
5
+ news from vlr.gg.
6
6
 
7
7
  Examples:
8
8
  Module-level access (using a default client):
@@ -23,17 +23,25 @@ Examples:
23
23
  >>> matches.matches[0].score
24
24
  '2-1'
25
25
 
26
+ News listing and articles:
27
+
28
+ >>> page = vlrdevapi.news(page=1)
29
+ >>> article = vlrdevapi.news.article(page.news[0].id)
30
+ >>> article.title != ''
31
+ True
32
+
26
33
  """
27
34
 
28
35
  import atexit as _atexit
36
+ import contextlib
29
37
  from typing import TYPE_CHECKING
30
38
 
31
39
  from vlrdevapi._client import VLRClient
32
- import contextlib
33
40
 
34
41
  if TYPE_CHECKING:
35
42
  from vlrdevapi._event.namespace import EventNamespace
36
43
  from vlrdevapi._matches.namespace import MatchesNamespace
44
+ from vlrdevapi._news.namespace import NewsNamespace
37
45
  from vlrdevapi._player.namespace import PlayerNamespace
38
46
  from vlrdevapi._series.namespace import SeriesNamespace
39
47
  from vlrdevapi._team.namespace import TeamNamespace
@@ -43,22 +51,23 @@ if TYPE_CHECKING:
43
51
  player: PlayerNamespace
44
52
  team: TeamNamespace
45
53
  matches: MatchesNamespace
54
+ news: NewsNamespace
46
55
  client: type[VLRClient]
47
56
 
48
- __version__ = "2.2.0"
57
+ __version__ = "2.3.0"
49
58
 
50
59
  _default_client: "VLRClient | None" = None
51
60
 
52
61
 
53
62
  def _get_default_client() -> "VLRClient":
54
- global _default_client # noqa: PLW0603
63
+ global _default_client
55
64
  if _default_client is None:
56
65
  _default_client = VLRClient()
57
66
  return _default_client
58
67
 
59
68
 
60
69
  def _cleanup_default_client() -> None:
61
- global _default_client # noqa: PLW0603
70
+ global _default_client
62
71
  if _default_client is not None:
63
72
  with contextlib.suppress(OSError):
64
73
  _default_client.close()
@@ -67,7 +76,7 @@ def _cleanup_default_client() -> None:
67
76
 
68
77
  _atexit.register(_cleanup_default_client)
69
78
 
70
- _BOUND_NAMES = frozenset({"event", "series", "player", "team", "matches"})
79
+ _BOUND_NAMES = frozenset({"event", "series", "player", "team", "matches", "news"})
71
80
 
72
81
 
73
82
  def __getattr__(name: str) -> object:
@@ -89,6 +98,7 @@ __all__ = [
89
98
  "client",
90
99
  "event",
91
100
  "matches",
101
+ "news",
92
102
  "player",
93
103
  "series",
94
104
  "team",
@@ -1,6 +1,7 @@
1
1
  from vlrdevapi._client import VLRClient
2
2
  from vlrdevapi._event.namespace import EventNamespace
3
3
  from vlrdevapi._matches.namespace import MatchesNamespace
4
+ from vlrdevapi._news.namespace import NewsNamespace
4
5
  from vlrdevapi._player.namespace import PlayerNamespace
5
6
  from vlrdevapi._series.namespace import SeriesNamespace
6
7
  from vlrdevapi._team.namespace import TeamNamespace
@@ -69,6 +70,20 @@ Examples:
69
70
  >>> completed = vlrdevapi.matches.completed()
70
71
  """
71
72
 
73
+ news: NewsNamespace
74
+ """Access news from vlr.gg: news listings and full article content.
75
+
76
+ Returns:
77
+ NewsNamespace instance bound to the default client. Call it with a
78
+ ``page`` number to browse the news listing, or use ``.article()`` to
79
+ fetch a single article (plain text and Markdown).
80
+
81
+ Examples:
82
+ >>> page = vlrdevapi.news(page=1)
83
+ >>> article = vlrdevapi.news.article(734100)
84
+ >>> print(article.content_md)
85
+ """
86
+
72
87
  client: type[VLRClient]
73
88
  """Create an explicit VLRClient for connection management.
74
89
 
@@ -12,6 +12,7 @@ import httpx
12
12
  from vlrdevapi.commons.timezone import REFERENCE_MATCH_PATH, detect_vlr_timezone
13
13
  from vlrdevapi._event.namespace import EventNamespace
14
14
  from vlrdevapi._matches.namespace import MatchesNamespace
15
+ from vlrdevapi._news.namespace import NewsNamespace
15
16
  from vlrdevapi._player.namespace import PlayerNamespace
16
17
  from vlrdevapi._series.namespace import SeriesNamespace
17
18
  from vlrdevapi._team.namespace import TeamNamespace
@@ -111,6 +112,7 @@ class VLRClient:
111
112
  self.matches = MatchesNamespace(self._client, self.timeout, self.retry_config, self._rate_limiter, merged_headers, self._source_tz)
112
113
  self.team = TeamNamespace(self._client, self.timeout, self.retry_config, self._rate_limiter, merged_headers, self._source_tz)
113
114
  self.event = EventNamespace(self._client, self.timeout, self.retry_config, self._rate_limiter, merged_headers, self._source_tz)
115
+ self.news = NewsNamespace(self._client, self.timeout, self.retry_config, self._rate_limiter, merged_headers, self._source_tz)
114
116
 
115
117
  def _detect_timezone(self) -> ZoneInfo | tzinfo | None:
116
118
  """Detect the viewer timezone VLR.gg renders for this client session."""
@@ -0,0 +1,5 @@
1
+ from vlrdevapi._news.article.models import NewsArticle
2
+ from vlrdevapi._news.list.models import News, NewsPage
3
+ from vlrdevapi._news.namespace import NewsNamespace
4
+
5
+ __all__ = ["News", "NewsArticle", "NewsNamespace", "NewsPage"]
@@ -0,0 +1,4 @@
1
+ from vlrdevapi._news.article.models import NewsArticle
2
+ from vlrdevapi._news.article.namespace import NewsArticleNamespace
3
+
4
+ __all__ = ["NewsArticle", "NewsArticleNamespace"]
@@ -0,0 +1,41 @@
1
+ from datetime import datetime as datetime_
2
+
3
+ from pydantic import BaseModel, ConfigDict, Field
4
+
5
+
6
+ class NewsArticle(BaseModel):
7
+ """A full news article from vlr.gg.
8
+
9
+ Attributes:
10
+ id: Unique identifier for the news article.
11
+ title: Title of the news article.
12
+ author: Author of the news article.
13
+ date: Publication date as a timezone-aware UTC datetime.
14
+ event_name: Event the article is associated with.
15
+ event_link: Link to the associated event page.
16
+ content: Full body text of the article as plain text.
17
+ content_md: Full body of the article converted to Markdown, with
18
+ headings, nested lists, tables, links, verbatim code, emphasis,
19
+ and Twitch clip embeds preserved.
20
+ """
21
+
22
+ model_config = ConfigDict(
23
+ json_schema_extra={"description": "A full news article from vlr.gg."}
24
+ )
25
+
26
+ id: int = Field(default=0, description="Unique identifier for the news article")
27
+ title: str = Field(default="", description="Title of the news article")
28
+ author: str = Field(default="", description="Author of the news article")
29
+ date: datetime_ | None = Field(
30
+ default=None, description="Publication date as a timezone-aware UTC datetime"
31
+ )
32
+ event_name: str = Field(
33
+ default="", description="Event the article is associated with"
34
+ )
35
+ event_link: str = Field(default="", description="Link to the associated event page")
36
+ content: str = Field(
37
+ default="", description="Full text content of the news article"
38
+ )
39
+ content_md: str = Field(
40
+ default="", description="Full content of the news article converted to Markdown"
41
+ )
@@ -0,0 +1,86 @@
1
+ """News article namespace."""
2
+
3
+ from datetime import tzinfo
4
+ from zoneinfo import ZoneInfo
5
+
6
+ import httpx
7
+
8
+ from vlrdevapi._base import SyncNamespace
9
+ from vlrdevapi._news.article.models import NewsArticle
10
+ from vlrdevapi._news.article.parser import parse_news_article
11
+ from vlrdevapi._utils.paths import news_article
12
+ from vlrdevapi.exceptions import NotFoundError
13
+ from vlrdevapi.fetcher import (
14
+ DEFAULT_RETRY_CONFIG,
15
+ DEFAULT_TIMEOUT,
16
+ RateLimiter,
17
+ RetryConfig,
18
+ )
19
+ from vlrdevapi.validators import sanitize_and_validate
20
+
21
+
22
+ class NewsArticleNamespace:
23
+ """Access individual news articles from vlr.gg.
24
+
25
+ Call the instance with an article ID to fetch the full article::
26
+
27
+ article = vlrdevapi.news.article(734100)
28
+ print(article.title)
29
+
30
+ The namespace is reachable via ``vlrdevapi.news.article``. There is
31
+ no need to instantiate it directly.
32
+ """
33
+
34
+ __slots__ = ("_source_tz", "_sync")
35
+
36
+ def __init__(
37
+ self,
38
+ client: httpx.Client,
39
+ timeout: int = DEFAULT_TIMEOUT,
40
+ retry_config: RetryConfig = DEFAULT_RETRY_CONFIG,
41
+ rate_limiter: RateLimiter | None = None,
42
+ extra_headers: dict[str, str] | None = None,
43
+ source_tz: ZoneInfo | tzinfo | None = None,
44
+ ):
45
+ self._source_tz = source_tz
46
+ self._sync = SyncNamespace(
47
+ client, timeout, retry_config, rate_limiter, extra_headers
48
+ )
49
+
50
+ @sanitize_and_validate
51
+ def __call__(self, article_id: int) -> NewsArticle:
52
+ """Get a single news article from vlr.gg.
53
+
54
+ Args:
55
+ article_id: The news article ID. Use the ``id`` field of a
56
+ ``News`` item from a listing, or the numeric prefix of
57
+ its ``link``.
58
+
59
+ Returns:
60
+ NewsArticle: The article with ``title``, ``author``, ``date``,
61
+ ``event_name``, ``event_link``, ``content`` (plain text),
62
+ and ``content_md`` (Markdown).
63
+
64
+ Raises:
65
+ ValidationError: If ``article_id`` is not a valid positive integer.
66
+ NotFoundError: If the article does not exist. vlr.gg returns a
67
+ generic page (HTTP 200) for unknown article IDs, so this
68
+ is detected from the page content.
69
+ RequestError: If the HTTP request fails.
70
+ RateLimitError: If the rate limit is exceeded.
71
+
72
+ Examples:
73
+ >>> article = vlrdevapi.news.article(734100)
74
+ >>> article.title
75
+ 'Gen.G, Global, VARREL, PRX bypass Pacific Stage 2 Play-Ins'
76
+ >>> article.content_md.startswith('The [Pacific Stage 2]')
77
+ True
78
+
79
+ """
80
+ html = self._sync._fetch(news_article(article_id))
81
+ article = parse_news_article(html, source_tz=self._source_tz)
82
+ if article.id == 0:
83
+ raise NotFoundError(
84
+ f"News article {article_id} not found (page contains no article content)."
85
+ )
86
+ return article
@@ -0,0 +1,19 @@
1
+ from datetime import tzinfo
2
+ from zoneinfo import ZoneInfo
3
+
4
+ import httpx
5
+
6
+ from vlrdevapi._news.article.models import NewsArticle
7
+ from vlrdevapi.fetcher import RateLimiter, RetryConfig
8
+
9
+ class NewsArticleNamespace:
10
+ def __init__(
11
+ self,
12
+ client: httpx.Client,
13
+ timeout: int = ...,
14
+ retry_config: RetryConfig = ...,
15
+ rate_limiter: RateLimiter | None = None,
16
+ extra_headers: dict[str, str] | None = None,
17
+ source_tz: ZoneInfo | tzinfo | None = None,
18
+ ) -> None: ...
19
+ def __call__(self, article_id: int) -> NewsArticle: ...