mistapi 0.61.3__tar.gz → 0.61.4__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 (357) hide show
  1. {mistapi-0.61.3 → mistapi-0.61.4}/.gitmodules +1 -1
  2. {mistapi-0.61.3 → mistapi-0.61.4}/CHANGELOG.md +52 -0
  3. {mistapi-0.61.3 → mistapi-0.61.4}/PKG-INFO +1 -1
  4. {mistapi-0.61.3 → mistapi-0.61.4}/pyproject.toml +1 -1
  5. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/__api_session.py +65 -6
  6. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/__version.py +1 -1
  7. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/sle.py +2 -2
  8. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/websockets/__ws_client.py +25 -11
  9. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/websockets/location.py +20 -0
  10. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/websockets/orgs.py +12 -0
  11. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/websockets/session.py +4 -0
  12. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/websockets/sites.py +28 -0
  13. {mistapi-0.61.3 → mistapi-0.61.4}/tests/unit/test_api_session.py +104 -0
  14. {mistapi-0.61.3 → mistapi-0.61.4}/tests/unit/test_websocket_client.py +109 -3
  15. {mistapi-0.61.3 → mistapi-0.61.4}/uv.lock +1 -1
  16. {mistapi-0.61.3 → mistapi-0.61.4}/.claude/settings.local.json +0 -0
  17. {mistapi-0.61.3 → mistapi-0.61.4}/.dccache +0 -0
  18. {mistapi-0.61.3 → mistapi-0.61.4}/.gitattributes +0 -0
  19. {mistapi-0.61.3 → mistapi-0.61.4}/.github/workflows/test.yml +0 -0
  20. {mistapi-0.61.3 → mistapi-0.61.4}/.gitignore +0 -0
  21. {mistapi-0.61.3 → mistapi-0.61.4}/.idea/.gitignore +0 -0
  22. {mistapi-0.61.3 → mistapi-0.61.4}/.idea/modules.xml +0 -0
  23. {mistapi-0.61.3 → mistapi-0.61.4}/.idea/python_package.iml +0 -0
  24. {mistapi-0.61.3 → mistapi-0.61.4}/.idea/vcs.xml +0 -0
  25. {mistapi-0.61.3 → mistapi-0.61.4}/.pre-commit-config.yaml +0 -0
  26. {mistapi-0.61.3 → mistapi-0.61.4}/.vscode/settings.json +0 -0
  27. {mistapi-0.61.3 → mistapi-0.61.4}/LICENSE +0 -0
  28. {mistapi-0.61.3 → mistapi-0.61.4}/Makefile +0 -0
  29. {mistapi-0.61.3 → mistapi-0.61.4}/README.md +0 -0
  30. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/._readme/img/get.png +0 -0
  31. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/._readme/img/main.png +0 -0
  32. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/._readme/img/post.png +0 -0
  33. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/._readme/img/thumbnail_get.jpg +0 -0
  34. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/._readme/img/thumbnail_main.jpg +0 -0
  35. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/._readme/img/thumbnail_post.jpg +0 -0
  36. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/.git +0 -0
  37. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/.github/copilot-instructions.md +0 -0
  38. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/.gitignore +0 -0
  39. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/CHANGELOG.md +0 -0
  40. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/LICENSE +0 -0
  41. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/README.md +0 -0
  42. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/mist.openapi.json +0 -0
  43. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/mist.openapi.yaml +0 -0
  44. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/mist.postman.json +0 -0
  45. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/mist.postman.v2.json +0 -0
  46. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/mist.postman_env.json +0 -0
  47. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/tools/README.md +0 -0
  48. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/tools/api-doc-diff.sh +0 -0
  49. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/.apimaticvscodeignore +0 -0
  50. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/.idea/.gitignore +0 -0
  51. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/.idea/modules.xml +0 -0
  52. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/.idea/vcs.xml +0 -0
  53. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/.idea/workdir.iml +0 -0
  54. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/APIMATIC-META.json +0 -0
  55. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/a1_process.py +0 -0
  56. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/a2_postman_postprocess.py +0 -0
  57. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/a3_doc_xtags.py +0 -0
  58. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/a4_check_tag_description.py +0 -0
  59. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/a5_check_tag_response.py +0 -0
  60. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/a6_check_response_header.py +0 -0
  61. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/a7_additionalProperties.py +0 -0
  62. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/add_enum_desc.py +0 -0
  63. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/check_null.py +0 -0
  64. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/generate.sh +0 -0
  65. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/mist.postman_usage.json +0 -0
  66. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/openapi.yaml +0 -0
  67. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/spec_references.py +0 -0
  68. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/spec_references.yaml +0 -0
  69. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/validate.sh +0 -0
  70. {mistapi-0.61.3 → mistapi-0.61.4}/mist_openapi/workdir/websocket_samples/show_route.md +0 -0
  71. {mistapi-0.61.3 → mistapi-0.61.4}/scripts/generate.sh +0 -0
  72. {mistapi-0.61.3 → mistapi-0.61.4}/scripts/generate_from_openapi.py +0 -0
  73. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/__api_request.py +0 -0
  74. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/__api_response.py +0 -0
  75. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/__init__.py +0 -0
  76. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/__logger.py +0 -0
  77. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/__models/__init__.py +0 -0
  78. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/__models/privilege.py +0 -0
  79. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/__pagination.py +0 -0
  80. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/__init__.py +0 -0
  81. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/__init__.py +0 -0
  82. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/__init__.py +0 -0
  83. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/alarm_defs.py +0 -0
  84. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/ap_channels.py +0 -0
  85. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/ap_esl_versions.py +0 -0
  86. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/ap_led_status.py +0 -0
  87. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/app_categories.py +0 -0
  88. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/app_subcategories.py +0 -0
  89. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/applications.py +0 -0
  90. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/client_events.py +0 -0
  91. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/countries.py +0 -0
  92. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/default_gateway_config.py +0 -0
  93. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/device_events.py +0 -0
  94. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/device_models.py +0 -0
  95. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/fingerprint_types.py +0 -0
  96. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/gateway_applications.py +0 -0
  97. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/insight_metrics.py +0 -0
  98. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/languages.py +0 -0
  99. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/license_types.py +0 -0
  100. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/marvisclient_versions.py +0 -0
  101. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/mxedge_events.py +0 -0
  102. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/mxedge_models.py +0 -0
  103. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/nac_events.py +0 -0
  104. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/otherdevice_events.py +0 -0
  105. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/otherdevice_models.py +0 -0
  106. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/states.py +0 -0
  107. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/system_events.py +0 -0
  108. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/traffic_types.py +0 -0
  109. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/const/webhook_topics.py +0 -0
  110. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/installer/__init__.py +0 -0
  111. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/installer/orgs/__init__.py +0 -0
  112. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/installer/orgs/alarmtemplates.py +0 -0
  113. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/installer/orgs/deviceprofiles.py +0 -0
  114. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/installer/orgs/devices.py +0 -0
  115. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/installer/orgs/rftemplates.py +0 -0
  116. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/installer/orgs/sitegroups.py +0 -0
  117. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/installer/orgs/sites.py +0 -0
  118. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/installer/sites/__init__.py +0 -0
  119. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/installer/sites/optimize.py +0 -0
  120. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/invite/__init__.py +0 -0
  121. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/invite/verify.py +0 -0
  122. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/login/__init__.py +0 -0
  123. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/login/login.py +0 -0
  124. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/login/lookup.py +0 -0
  125. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/login/oauth.py +0 -0
  126. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/login/two_factor.py +0 -0
  127. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/logout/__init__.py +0 -0
  128. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/logout/logout.py +0 -0
  129. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/mobile/__init__.py +0 -0
  130. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/mobile/verify.py +0 -0
  131. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/__init__.py +0 -0
  132. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/admins.py +0 -0
  133. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/claim.py +0 -0
  134. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/insights.py +0 -0
  135. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/inventory.py +0 -0
  136. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/invites.py +0 -0
  137. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/licenses.py +0 -0
  138. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/logo.py +0 -0
  139. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/logs.py +0 -0
  140. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/msps.py +0 -0
  141. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/orggroups.py +0 -0
  142. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/orgs.py +0 -0
  143. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/search.py +0 -0
  144. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/ssoroles.py +0 -0
  145. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/ssos.py +0 -0
  146. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/stats.py +0 -0
  147. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/suggestion.py +0 -0
  148. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/msps/tickets.py +0 -0
  149. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/__init__.py +0 -0
  150. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/aamwprofiles.py +0 -0
  151. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/admins.py +0 -0
  152. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/alarms.py +0 -0
  153. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/alarmtemplates.py +0 -0
  154. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/aos.py +0 -0
  155. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/apitokens.py +0 -0
  156. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/aptemplates.py +0 -0
  157. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/assetfilters.py +0 -0
  158. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/assets.py +0 -0
  159. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/avprofiles.py +0 -0
  160. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/cert.py +0 -0
  161. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/claim.py +0 -0
  162. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/clients.py +0 -0
  163. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/clone.py +0 -0
  164. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/crl.py +0 -0
  165. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/deviceprofiles.py +0 -0
  166. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/devices.py +0 -0
  167. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/events.py +0 -0
  168. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/evpn_topologies.py +0 -0
  169. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/gatewaytemplates.py +0 -0
  170. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/guests.py +0 -0
  171. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/idpprofiles.py +0 -0
  172. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/insights.py +0 -0
  173. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/inventory.py +0 -0
  174. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/invites.py +0 -0
  175. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/jsi.py +0 -0
  176. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/licenses.py +0 -0
  177. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/logs.py +0 -0
  178. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/maps.py +0 -0
  179. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/marvisinvites.py +0 -0
  180. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/mist_nac.py +0 -0
  181. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/mxclusters.py +0 -0
  182. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/mxedges.py +0 -0
  183. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/mxtunnels.py +0 -0
  184. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/nac_clients.py +0 -0
  185. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/nacportals.py +0 -0
  186. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/nacrules.py +0 -0
  187. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/nactags.py +0 -0
  188. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/networks.py +0 -0
  189. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/networktemplates.py +0 -0
  190. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/ocdevices.py +0 -0
  191. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/orgs.py +0 -0
  192. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/otherdevices.py +0 -0
  193. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/pcaps.py +0 -0
  194. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/pma.py +0 -0
  195. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/pskportals.py +0 -0
  196. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/psks.py +0 -0
  197. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/rftemplates.py +0 -0
  198. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/sdkclients.py +0 -0
  199. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/sdkinvites.py +0 -0
  200. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/sdktemplates.py +0 -0
  201. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/secintelprofiles.py +0 -0
  202. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/secpolicies.py +0 -0
  203. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/servicepolicies.py +0 -0
  204. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/services.py +0 -0
  205. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/setting.py +0 -0
  206. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/sitegroups.py +0 -0
  207. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/sites.py +0 -0
  208. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/sitetemplates.py +0 -0
  209. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/ssl_proxy_cert.py +0 -0
  210. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/ssoroles.py +0 -0
  211. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/ssos.py +0 -0
  212. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/ssr.py +0 -0
  213. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/stats.py +0 -0
  214. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/subscriptions.py +0 -0
  215. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/templates.py +0 -0
  216. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/tickets.py +0 -0
  217. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/troubleshoot.py +0 -0
  218. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/uisettings.py +0 -0
  219. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/usermacs.py +0 -0
  220. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/vars.py +0 -0
  221. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/vpns.py +0 -0
  222. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/wan_client.py +0 -0
  223. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/wan_clients.py +0 -0
  224. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/webhooks.py +0 -0
  225. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/wired_clients.py +0 -0
  226. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/wlans.py +0 -0
  227. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/wxrules.py +0 -0
  228. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/wxtags.py +0 -0
  229. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/orgs/wxtunnels.py +0 -0
  230. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/recover/__init__.py +0 -0
  231. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/recover/recover.py +0 -0
  232. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/recover/verify.py +0 -0
  233. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/register/__init__.py +0 -0
  234. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/register/recaptcha.py +0 -0
  235. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/register/register.py +0 -0
  236. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/register/verify.py +0 -0
  237. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/self/__init__.py +0 -0
  238. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/self/apitokens.py +0 -0
  239. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/self/login_failures.py +0 -0
  240. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/self/logs.py +0 -0
  241. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/self/oauth.py +0 -0
  242. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/self/self.py +0 -0
  243. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/self/subscriptions.py +0 -0
  244. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/self/two_factor.py +0 -0
  245. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/self/update.py +0 -0
  246. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/self/usage.py +0 -0
  247. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/__init__.py +0 -0
  248. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/aamwprofiles.py +0 -0
  249. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/alarms.py +0 -0
  250. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/analyze_spectrum.py +0 -0
  251. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/anomaly.py +0 -0
  252. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/apps.py +0 -0
  253. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/aptemplates.py +0 -0
  254. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/assetfilters.py +0 -0
  255. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/assets.py +0 -0
  256. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/avprofiles.py +0 -0
  257. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/beacons.py +0 -0
  258. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/clients.py +0 -0
  259. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/count.py +0 -0
  260. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/deviceprofiles.py +0 -0
  261. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/devices.py +0 -0
  262. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/events.py +0 -0
  263. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/evpn_topologies.py +0 -0
  264. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/gatewaytemplates.py +0 -0
  265. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/guests.py +0 -0
  266. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/idpprofiles.py +0 -0
  267. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/insights.py +0 -0
  268. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/licenses.py +0 -0
  269. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/location.py +0 -0
  270. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/maps.py +0 -0
  271. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/mapstacks.py +0 -0
  272. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/mxedges.py +0 -0
  273. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/mxtunnels.py +0 -0
  274. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/nac_clients.py +0 -0
  275. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/networks.py +0 -0
  276. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/networktemplates.py +0 -0
  277. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/otherdevices.py +0 -0
  278. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/pcaps.py +0 -0
  279. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/psks.py +0 -0
  280. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/rfdiags.py +0 -0
  281. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/rftemplates.py +0 -0
  282. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/rogues.py +0 -0
  283. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/rrm.py +0 -0
  284. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/rssizones.py +0 -0
  285. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/secintelprofiles.py +0 -0
  286. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/servicepolicies.py +0 -0
  287. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/services.py +0 -0
  288. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/setting.py +0 -0
  289. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/sites.py +0 -0
  290. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/sitetemplates.py +0 -0
  291. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/skyatp.py +0 -0
  292. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/ssr.py +0 -0
  293. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/stats.py +0 -0
  294. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/subscriptions.py +0 -0
  295. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/synthetic_test.py +0 -0
  296. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/uisettings.py +0 -0
  297. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/vbeacons.py +0 -0
  298. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/visits.py +0 -0
  299. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/vpns.py +0 -0
  300. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/wan_client.py +0 -0
  301. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/wan_clients.py +0 -0
  302. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/wan_usages.py +0 -0
  303. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/webhooks.py +0 -0
  304. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/wired_clients.py +0 -0
  305. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/wlans.py +0 -0
  306. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/wxrules.py +0 -0
  307. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/wxtags.py +0 -0
  308. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/wxtunnels.py +0 -0
  309. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/sites/zones.py +0 -0
  310. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/utils/__init__.py +0 -0
  311. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/utils/test_smsglobal.py +0 -0
  312. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/utils/test_telstra.py +0 -0
  313. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/api/v1/utils/test_twilio.py +0 -0
  314. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/cli.py +0 -0
  315. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__init__.py +0 -0
  316. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/__common.py +0 -0
  317. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/__init__.py +0 -0
  318. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/__ws_wrapper.py +0 -0
  319. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/arp.py +0 -0
  320. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/bgp.py +0 -0
  321. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/bpdu.py +0 -0
  322. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/dhcp.py +0 -0
  323. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/dns.py +0 -0
  324. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/dot1x.py +0 -0
  325. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/mac.py +0 -0
  326. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/miscellaneous.py +0 -0
  327. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/ospf.py +0 -0
  328. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/policy.py +0 -0
  329. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/port.py +0 -0
  330. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/remote_capture.py +0 -0
  331. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/routes.py +0 -0
  332. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/service_path.py +0 -0
  333. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/sessions.py +0 -0
  334. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/__tools/shell.py +0 -0
  335. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/ap.py +0 -0
  336. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/ex.py +0 -0
  337. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/srx.py +0 -0
  338. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/device_utils/ssr.py +0 -0
  339. {mistapi-0.61.3 → mistapi-0.61.4}/src/mistapi/websockets/__init__.py +0 -0
  340. {mistapi-0.61.3 → mistapi-0.61.4}/tests/__init__.py +0 -0
  341. {mistapi-0.61.3 → mistapi-0.61.4}/tests/conftest.py +0 -0
  342. {mistapi-0.61.3 → mistapi-0.61.4}/tests/fixtures/__init__.py +0 -0
  343. {mistapi-0.61.3 → mistapi-0.61.4}/tests/fixtures/mock_responses.py +0 -0
  344. {mistapi-0.61.3 → mistapi-0.61.4}/tests/fixtures/test_data.py +0 -0
  345. {mistapi-0.61.3 → mistapi-0.61.4}/tests/integration/__init__.py +0 -0
  346. {mistapi-0.61.3 → mistapi-0.61.4}/tests/integration/test_api_endpoints.py +0 -0
  347. {mistapi-0.61.3 → mistapi-0.61.4}/tests/integration/test_authentication_flow.py +0 -0
  348. {mistapi-0.61.3 → mistapi-0.61.4}/tests/unit/__init__.py +0 -0
  349. {mistapi-0.61.3 → mistapi-0.61.4}/tests/unit/test_api_request.py +0 -0
  350. {mistapi-0.61.3 → mistapi-0.61.4}/tests/unit/test_api_response.py +0 -0
  351. {mistapi-0.61.3 → mistapi-0.61.4}/tests/unit/test_cli.py +0 -0
  352. {mistapi-0.61.3 → mistapi-0.61.4}/tests/unit/test_init.py +0 -0
  353. {mistapi-0.61.3 → mistapi-0.61.4}/tests/unit/test_logger.py +0 -0
  354. {mistapi-0.61.3 → mistapi-0.61.4}/tests/unit/test_models.py +0 -0
  355. {mistapi-0.61.3 → mistapi-0.61.4}/tests/unit/test_pagination.py +0 -0
  356. {mistapi-0.61.3 → mistapi-0.61.4}/tests/unit/test_shell.py +0 -0
  357. {mistapi-0.61.3 → mistapi-0.61.4}/tests/unit/test_ws_wrapper.py +0 -0
@@ -1,4 +1,4 @@
1
1
  [submodule "mist_openapi"]
2
2
  path = mist_openapi
3
3
  url = https://github.com/mistsys/mist_openapi.git
4
- branch = 2602.1.8
4
+ branch = master
@@ -1,4 +1,56 @@
1
1
  # CHANGELOG
2
+ ## Version 0.61.4 (April 2026)
3
+
4
+ **Released**: April 1, 2026
5
+
6
+ This release improves WebSocket reconnection, hardens credential handling, and fixes the two-factor authentication flow.
7
+
8
+ ---
9
+
10
+ ### 1. NEW FEATURES
11
+
12
+ #### **Capped Reconnect Backoff (`max_reconnect_backoff`)**
13
+ The `_MistWebsocket` client now supports a `max_reconnect_backoff` parameter to cap the exponential backoff delay during reconnection attempts:
14
+
15
+ ```python
16
+ ws = mistapi.websockets.sites.DeviceStatsEvents(
17
+ apisession,
18
+ site_ids=["<site_id>"],
19
+ auto_reconnect=True,
20
+ max_reconnect_backoff=60.0 # Cap backoff at 60 seconds
21
+ )
22
+ ```
23
+
24
+ #### **Unlimited Reconnect Attempts**
25
+ Setting `max_reconnect_attempts=0` now enables unlimited reconnection attempts:
26
+
27
+ ```python
28
+ ws = mistapi.websockets.sites.DeviceStatsEvents(
29
+ apisession,
30
+ site_ids=["<site_id>"],
31
+ auto_reconnect=True,
32
+ max_reconnect_attempts=0 # Reconnect indefinitely
33
+ )
34
+ ```
35
+
36
+ ---
37
+
38
+ ### 2. IMPROVEMENTS
39
+
40
+ #### **Credential Override Logging**
41
+ `APISession` now logs INFO-level messages when credentials (host, email, password, API token) are overridden by:
42
+ - Constructor parameters overriding environment variables
43
+ - Vault secrets overriding previously loaded values
44
+ - Keyring credentials overriding previously loaded values
45
+
46
+ #### **Security: Password Cleared After Login**
47
+ The stored password is now cleared from memory immediately after successful login authentication.
48
+
49
+ #### **User Attribute Handling**
50
+ `APISession._getself()` now only sets a fixed set of known user-related attributes instead of setting every response key as an object attribute.
51
+
52
+ ---
53
+
2
54
  ## Version 0.61.3 (March 2026)
3
55
 
4
56
  **Released**: March 18, 2026
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mistapi
3
- Version: 0.61.3
3
+ Version: 0.61.4
4
4
  Summary: Python package to simplify the Mist System APIs usage
5
5
  Project-URL: Source, https://github.com/tmunzer/mistapi_python
6
6
  Project-URL: Bug Tracker, https://github.com/tmunzer/mistapi_python/issues
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "mistapi"
7
- version = "0.61.3"
7
+ version = "0.61.4"
8
8
  authors = [{ name = "Thomas Munzer", email = "tmunzer@juniper.net" }]
9
9
  description = "Python package to simplify the Mist System APIs usage"
10
10
  keywords = ["Mist", "Juniper", "API"]
@@ -157,12 +157,28 @@ class APISession(APIRequest):
157
157
  self._session.proxies.update(filtered_proxies)
158
158
 
159
159
  if host:
160
+ if self._cloud_uri:
161
+ LOGGER.info(
162
+ "apisession:__init__: overriding previously loaded MIST_HOST with constructor parameter"
163
+ )
160
164
  self.set_cloud(host)
161
165
  if email:
166
+ if self.email:
167
+ LOGGER.info(
168
+ "apisession:__init__: overriding previously loaded MIST_USER with constructor parameter"
169
+ )
162
170
  self.set_email(email)
163
171
  if password:
172
+ if self._password:
173
+ LOGGER.info(
174
+ "apisession:__init__: overriding previously loaded MIST_PASSWORD with constructor parameter"
175
+ )
164
176
  self.set_password(password)
165
177
  if apitoken:
178
+ if self._apitoken:
179
+ LOGGER.info(
180
+ "apisession:__init__: overriding previously loaded MIST_APITOKEN with constructor parameter"
181
+ )
166
182
  self.set_api_token(apitoken)
167
183
  self.first_name: str = ""
168
184
  self.last_name: str = ""
@@ -244,10 +260,18 @@ class APISession(APIRequest):
244
260
  mist_host = read_response["data"]["data"].get("MIST_HOST", None)
245
261
  LOGGER.info("apisession:_load_vault: MIST_HOST=%s", mist_host)
246
262
  if mist_host:
263
+ if self._cloud_uri:
264
+ LOGGER.info(
265
+ "apisession:_load_vault: overriding previously loaded MIST_HOST"
266
+ )
247
267
  self.set_cloud(mist_host)
248
268
 
249
269
  mist_apitoken = read_response["data"]["data"].get("MIST_APITOKEN", None)
250
270
  if mist_apitoken:
271
+ if self._apitoken:
272
+ LOGGER.info(
273
+ "apisession:_load_vault: overriding previously loaded MIST_APITOKEN"
274
+ )
251
275
  self.set_api_token(mist_apitoken)
252
276
  except (KeyError, TypeError, AttributeError):
253
277
  LOGGER.error("apisession:_load_vault: Failed to retrieve secret")
@@ -270,10 +294,18 @@ class APISession(APIRequest):
270
294
  try:
271
295
  mist_host = keyring.get_password(keyring_service, "MIST_HOST")
272
296
  if mist_host:
297
+ if self._cloud_uri:
298
+ LOGGER.info(
299
+ "apisession:_load_keyring: overriding previously loaded MIST_HOST"
300
+ )
273
301
  LOGGER.info("apisession:_load_keyring: MIST_HOST=%s", mist_host)
274
302
  self.set_cloud(mist_host)
275
303
  mist_apitoken = keyring.get_password(keyring_service, "MIST_APITOKEN")
276
304
  if mist_apitoken:
305
+ if self._apitoken:
306
+ LOGGER.info(
307
+ "apisession:_load_keyring: overriding previously loaded MIST_APITOKEN"
308
+ )
277
309
  if isinstance(mist_apitoken, str):
278
310
  for token in mist_apitoken.split(","):
279
311
  token = token.strip()
@@ -285,10 +317,18 @@ class APISession(APIRequest):
285
317
  self.set_api_token(mist_apitoken)
286
318
  mist_user = keyring.get_password(keyring_service, "MIST_USER")
287
319
  if mist_user:
320
+ if self.email:
321
+ LOGGER.info(
322
+ "apisession:_load_keyring: overriding previously loaded MIST_USER"
323
+ )
288
324
  LOGGER.info("apisession:_load_keyring: MIST_USER retrieved")
289
325
  self.set_email(mist_user)
290
326
  mist_password = keyring.get_password(keyring_service, "MIST_PASSWORD")
291
327
  if mist_password:
328
+ if self._password:
329
+ LOGGER.info(
330
+ "apisession:_load_keyring: overriding previously loaded MIST_PASSWORD"
331
+ )
292
332
  LOGGER.info("apisession:_load_keyring: MIST_PASSWORD retrieved")
293
333
  self.set_password(mist_password)
294
334
  except Exception as e:
@@ -701,6 +741,7 @@ class APISession(APIRequest):
701
741
  if resp.status_code == 200:
702
742
  LOGGER.info("apisession:_process_login:authentication successful!")
703
743
  CONSOLE.info("Authentication successful!")
744
+ self._password = None
704
745
  self._set_authenticated(True)
705
746
  else:
706
747
  error = resp.json().get("detail")
@@ -818,14 +859,22 @@ class APISession(APIRequest):
818
859
  elif self.email and self._password:
819
860
  if two_factor:
820
861
  LOGGER.debug("apisession:login_with_return:login/pwd provided with 2FA")
821
- if self._two_factor_authentication(two_factor):
862
+ error_login = self._process_login(retry=False)
863
+ if error_login:
864
+ LOGGER.error(
865
+ "apisession:login_with_return:login/pwd auth failed: %s",
866
+ error_login,
867
+ )
868
+ return {"authenticated": False, "error": error_login}
869
+ if not self._two_factor_authentication(two_factor):
822
870
  LOGGER.error(
823
- "apisession:login_with_return:login/pwd auth failed: 2FA authentication failed"
871
+ "apisession:login_with_return:2FA authentication failed"
824
872
  )
825
873
  return {
826
874
  "authenticated": False,
827
875
  "error": "2FA authentication failed",
828
876
  }
877
+ LOGGER.info("apisession:login_with_return:authenticated with 2FA")
829
878
  else:
830
879
  LOGGER.debug("apisession:login_with_return:login/pwd provided w/o 2FA")
831
880
  error_login = self._process_login(retry=False)
@@ -1044,10 +1093,8 @@ class APISession(APIRequest):
1044
1093
  True if authentication succeed, False otherwise
1045
1094
  """
1046
1095
  LOGGER.debug("apisession:_two_factor_authentication")
1047
- uri = "/api/v1/login"
1096
+ uri = "/api/v1/login/two_factor"
1048
1097
  body = {
1049
- "email": self.email,
1050
- "password": self._password,
1051
1098
  "two_factor": two_factor,
1052
1099
  }
1053
1100
  resp = self._session.post(self._url(uri), json=body)
@@ -1102,7 +1149,19 @@ class APISession(APIRequest):
1102
1149
  elif key == "tags":
1103
1150
  for tag in resp.data["tags"]:
1104
1151
  self.tags.append(tag)
1105
- else:
1152
+ elif key in [
1153
+ "first_name",
1154
+ "last_name",
1155
+ "email",
1156
+ "phone",
1157
+ "enable_two_factor",
1158
+ "two_factor_verified",
1159
+ "no_tracking",
1160
+ "oauth_google",
1161
+ "password_expiry",
1162
+ "password_modified_time",
1163
+ "via_sso",
1164
+ ]:
1106
1165
  setattr(self, key, val)
1107
1166
  if self._show_cli_notif:
1108
1167
  print()
@@ -1,2 +1,2 @@
1
- __version__ = "0.61.3"
1
+ __version__ = "0.61.4"
2
2
  __author__ = "Thomas Munzer <tmunzer@juniper.net>"
@@ -18,7 +18,7 @@ import deprecation
18
18
  @deprecation.deprecated(
19
19
  deprecated_in="0.59.2",
20
20
  removed_in="0.65.0",
21
- current_version="0.61.3",
21
+ current_version="0.61.4",
22
22
  details="function replaced with getSiteSleClassifierSummaryTrend",
23
23
  )
24
24
  def getSiteSleClassifierDetails(
@@ -690,7 +690,7 @@ def listSiteSleImpactedWirelessClients(
690
690
  @deprecation.deprecated(
691
691
  deprecated_in="0.59.2",
692
692
  removed_in="0.65.0",
693
- current_version="0.61.3",
693
+ current_version="0.61.4",
694
694
  details="function replaced with getSiteSleSummaryTrend",
695
695
  )
696
696
  def getSiteSleSummary(
@@ -69,12 +69,15 @@ class _MistWebsocket:
69
69
  auto_reconnect: bool = False,
70
70
  max_reconnect_attempts: int = 5,
71
71
  reconnect_backoff: float = 2.0,
72
+ max_reconnect_backoff: float | None = None,
72
73
  queue_maxsize: int = 0,
73
74
  ) -> None:
74
75
  if max_reconnect_attempts < 0:
75
- raise ValueError("max_reconnect_attempts must be >= 0")
76
+ raise ValueError("max_reconnect_attempts must be >= 0 (0 = unlimited)")
76
77
  if reconnect_backoff <= 0:
77
78
  raise ValueError("reconnect_backoff must be > 0")
79
+ if max_reconnect_backoff is not None and max_reconnect_backoff <= 0:
80
+ raise ValueError("max_reconnect_backoff must be > 0")
78
81
  if queue_maxsize < 0:
79
82
  raise ValueError("queue_maxsize must be >= 0")
80
83
 
@@ -85,6 +88,7 @@ class _MistWebsocket:
85
88
  self._auto_reconnect = auto_reconnect
86
89
  self._max_reconnect_attempts = max_reconnect_attempts
87
90
  self._reconnect_backoff = reconnect_backoff
91
+ self._max_reconnect_backoff = max_reconnect_backoff
88
92
  self._lock = threading.Lock()
89
93
  self._ws: websocket.WebSocketApp | None = None
90
94
  self._thread: threading.Thread | None = None
@@ -305,22 +309,32 @@ class _MistWebsocket:
305
309
  break
306
310
 
307
311
  self._reconnect_attempts += 1
308
- if self._reconnect_attempts > self._max_reconnect_attempts:
312
+ if (
313
+ self._max_reconnect_attempts > 0
314
+ and self._reconnect_attempts > self._max_reconnect_attempts
315
+ ):
309
316
  logger.warning(
310
317
  "Max reconnect attempts (%d) reached, giving up",
311
318
  self._max_reconnect_attempts,
312
319
  )
313
320
  break
314
321
 
315
- delay = self._reconnect_backoff * (
316
- 2 ** (self._reconnect_attempts - 1)
317
- )
318
- logger.info(
319
- "Reconnecting in %.1fs (attempt %d/%d)",
320
- delay,
321
- self._reconnect_attempts,
322
- self._max_reconnect_attempts,
323
- )
322
+ delay = self._reconnect_backoff * (2 ** (self._reconnect_attempts - 1))
323
+ if self._max_reconnect_backoff is not None:
324
+ delay = min(delay, self._max_reconnect_backoff)
325
+ if self._max_reconnect_attempts > 0:
326
+ logger.info(
327
+ "Reconnecting in %.1fs (attempt %d/%d)",
328
+ delay,
329
+ self._reconnect_attempts,
330
+ self._max_reconnect_attempts,
331
+ )
332
+ else:
333
+ logger.info(
334
+ "Reconnecting in %.1fs (attempt %d, unlimited)",
335
+ delay,
336
+ self._reconnect_attempts,
337
+ )
324
338
  if self._user_disconnect.wait(timeout=delay):
325
339
  break # disconnect() called during backoff
326
340
 
@@ -39,6 +39,8 @@ class BleAssetsEvents(_MistWebsocket):
39
39
  Maximum number of reconnect attempts before giving up.
40
40
  reconnect_backoff : float, default 2.0
41
41
  Base backoff delay in seconds. Doubles after each failed attempt.
42
+ max_reconnect_backoff : float | None, default None
43
+ Maximum backoff delay in seconds. If None, backoff grows indefinitely.
42
44
  queue_maxsize : int, default 0
43
45
  Maximum number of messages buffered in the internal queue for the
44
46
  ``receive()`` generator. ``0`` means unbounded. When set,
@@ -80,6 +82,7 @@ class BleAssetsEvents(_MistWebsocket):
80
82
  auto_reconnect: bool = False,
81
83
  max_reconnect_attempts: int = 5,
82
84
  reconnect_backoff: float = 2.0,
85
+ max_reconnect_backoff: float | None = None,
83
86
  queue_maxsize: int = 0,
84
87
  ) -> None:
85
88
  channels = [f"/sites/{site_id}/stats/maps/{mid}/assets" for mid in map_ids]
@@ -91,6 +94,7 @@ class BleAssetsEvents(_MistWebsocket):
91
94
  auto_reconnect=auto_reconnect,
92
95
  max_reconnect_attempts=max_reconnect_attempts,
93
96
  reconnect_backoff=reconnect_backoff,
97
+ max_reconnect_backoff=max_reconnect_backoff,
94
98
  queue_maxsize=queue_maxsize,
95
99
  )
96
100
 
@@ -119,6 +123,8 @@ class ConnectedClientsEvents(_MistWebsocket):
119
123
  Maximum number of reconnect attempts before giving up.
120
124
  reconnect_backoff : float, default 2.0
121
125
  Base backoff delay in seconds. Doubles after each failed attempt.
126
+ max_reconnect_backoff : float | None, default None
127
+ Maximum backoff delay in seconds. If None, backoff grows indefinitely.
122
128
  queue_maxsize : int, default 0
123
129
  Maximum number of messages buffered in the internal queue for the
124
130
  ``receive()`` generator. ``0`` means unbounded. When set,
@@ -160,6 +166,7 @@ class ConnectedClientsEvents(_MistWebsocket):
160
166
  auto_reconnect: bool = False,
161
167
  max_reconnect_attempts: int = 5,
162
168
  reconnect_backoff: float = 2.0,
169
+ max_reconnect_backoff: float | None = None,
163
170
  queue_maxsize: int = 0,
164
171
  ) -> None:
165
172
  channels = [f"/sites/{site_id}/stats/maps/{mid}/clients" for mid in map_ids]
@@ -171,6 +178,7 @@ class ConnectedClientsEvents(_MistWebsocket):
171
178
  auto_reconnect=auto_reconnect,
172
179
  max_reconnect_attempts=max_reconnect_attempts,
173
180
  reconnect_backoff=reconnect_backoff,
181
+ max_reconnect_backoff=max_reconnect_backoff,
174
182
  queue_maxsize=queue_maxsize,
175
183
  )
176
184
 
@@ -199,6 +207,8 @@ class SdkClientsEvents(_MistWebsocket):
199
207
  Maximum number of reconnect attempts before giving up.
200
208
  reconnect_backoff : float, default 2.0
201
209
  Base backoff delay in seconds. Doubles after each failed attempt.
210
+ max_reconnect_backoff : float | None, default None
211
+ Maximum backoff delay in seconds. If None, backoff grows indefinitely.
202
212
  queue_maxsize : int, default 0
203
213
  Maximum number of messages buffered in the internal queue for the
204
214
  ``receive()`` generator. ``0`` means unbounded. When set,
@@ -240,6 +250,7 @@ class SdkClientsEvents(_MistWebsocket):
240
250
  auto_reconnect: bool = False,
241
251
  max_reconnect_attempts: int = 5,
242
252
  reconnect_backoff: float = 2.0,
253
+ max_reconnect_backoff: float | None = None,
243
254
  queue_maxsize: int = 0,
244
255
  ) -> None:
245
256
  channels = [f"/sites/{site_id}/stats/maps/{mid}/sdkclients" for mid in map_ids]
@@ -251,6 +262,7 @@ class SdkClientsEvents(_MistWebsocket):
251
262
  auto_reconnect=auto_reconnect,
252
263
  max_reconnect_attempts=max_reconnect_attempts,
253
264
  reconnect_backoff=reconnect_backoff,
265
+ max_reconnect_backoff=max_reconnect_backoff,
254
266
  queue_maxsize=queue_maxsize,
255
267
  )
256
268
 
@@ -279,6 +291,8 @@ class UnconnectedClientsEvents(_MistWebsocket):
279
291
  Maximum number of reconnect attempts before giving up.
280
292
  reconnect_backoff : float, default 2.0
281
293
  Base backoff delay in seconds. Doubles after each failed attempt.
294
+ max_reconnect_backoff : float | None, default None
295
+ Maximum backoff delay in seconds. If None, backoff grows indefinitely.
282
296
  queue_maxsize : int, default 0
283
297
  Maximum number of messages buffered in the internal queue for the
284
298
  ``receive()`` generator. ``0`` means unbounded. When set,
@@ -320,6 +334,7 @@ class UnconnectedClientsEvents(_MistWebsocket):
320
334
  auto_reconnect: bool = False,
321
335
  max_reconnect_attempts: int = 5,
322
336
  reconnect_backoff: float = 2.0,
337
+ max_reconnect_backoff: float | None = None,
323
338
  queue_maxsize: int = 0,
324
339
  ) -> None:
325
340
  channels = [
@@ -333,6 +348,7 @@ class UnconnectedClientsEvents(_MistWebsocket):
333
348
  auto_reconnect=auto_reconnect,
334
349
  max_reconnect_attempts=max_reconnect_attempts,
335
350
  reconnect_backoff=reconnect_backoff,
351
+ max_reconnect_backoff=max_reconnect_backoff,
336
352
  queue_maxsize=queue_maxsize,
337
353
  )
338
354
 
@@ -361,6 +377,8 @@ class DiscoveredBleAssetsEvents(_MistWebsocket):
361
377
  Maximum number of reconnect attempts before giving up.
362
378
  reconnect_backoff : float, default 2.0
363
379
  Base backoff delay in seconds. Doubles after each failed attempt.
380
+ max_reconnect_backoff : float | None, default None
381
+ Maximum backoff delay in seconds. If None, backoff grows indefinitely.
364
382
  queue_maxsize : int, default 0
365
383
  Maximum number of messages buffered in the internal queue for the
366
384
  ``receive()`` generator. ``0`` means unbounded. When set,
@@ -402,6 +420,7 @@ class DiscoveredBleAssetsEvents(_MistWebsocket):
402
420
  auto_reconnect: bool = False,
403
421
  max_reconnect_attempts: int = 5,
404
422
  reconnect_backoff: float = 2.0,
423
+ max_reconnect_backoff: float | None = None,
405
424
  queue_maxsize: int = 0,
406
425
  ) -> None:
407
426
  channels = [
@@ -415,5 +434,6 @@ class DiscoveredBleAssetsEvents(_MistWebsocket):
415
434
  auto_reconnect=auto_reconnect,
416
435
  max_reconnect_attempts=max_reconnect_attempts,
417
436
  reconnect_backoff=reconnect_backoff,
437
+ max_reconnect_backoff=max_reconnect_backoff,
418
438
  queue_maxsize=queue_maxsize,
419
439
  )
@@ -37,6 +37,8 @@ class InsightsEvents(_MistWebsocket):
37
37
  Maximum number of reconnect attempts before giving up.
38
38
  reconnect_backoff : float, default 2.0
39
39
  Base backoff delay in seconds. Doubles after each failed attempt.
40
+ max_reconnect_backoff : float | None, default None
41
+ Maximum backoff delay in seconds. If None, backoff grows indefinitely.
40
42
  queue_maxsize : int, default 0
41
43
  Maximum number of messages buffered in the internal queue for the
42
44
  ``receive()`` generator. ``0`` means unbounded. When set,
@@ -77,6 +79,7 @@ class InsightsEvents(_MistWebsocket):
77
79
  auto_reconnect: bool = False,
78
80
  max_reconnect_attempts: int = 5,
79
81
  reconnect_backoff: float = 2.0,
82
+ max_reconnect_backoff: float | None = None,
80
83
  queue_maxsize: int = 0,
81
84
  ) -> None:
82
85
  super().__init__(
@@ -87,6 +90,7 @@ class InsightsEvents(_MistWebsocket):
87
90
  auto_reconnect=auto_reconnect,
88
91
  max_reconnect_attempts=max_reconnect_attempts,
89
92
  reconnect_backoff=reconnect_backoff,
93
+ max_reconnect_backoff=max_reconnect_backoff,
90
94
  queue_maxsize=queue_maxsize,
91
95
  )
92
96
 
@@ -113,6 +117,8 @@ class MxEdgesStatsEvents(_MistWebsocket):
113
117
  Maximum number of reconnect attempts before giving up.
114
118
  reconnect_backoff : float, default 2.0
115
119
  Base backoff delay in seconds. Doubles after each failed attempt.
120
+ max_reconnect_backoff : float | None, default None
121
+ Maximum backoff delay in seconds. If None, backoff grows indefinitely.
116
122
  queue_maxsize : int, default 0
117
123
  Maximum number of messages buffered in the internal queue for the
118
124
  ``receive()`` generator. ``0`` means unbounded. When set,
@@ -153,6 +159,7 @@ class MxEdgesStatsEvents(_MistWebsocket):
153
159
  auto_reconnect: bool = False,
154
160
  max_reconnect_attempts: int = 5,
155
161
  reconnect_backoff: float = 2.0,
162
+ max_reconnect_backoff: float | None = None,
156
163
  queue_maxsize: int = 0,
157
164
  ) -> None:
158
165
  super().__init__(
@@ -163,6 +170,7 @@ class MxEdgesStatsEvents(_MistWebsocket):
163
170
  auto_reconnect=auto_reconnect,
164
171
  max_reconnect_attempts=max_reconnect_attempts,
165
172
  reconnect_backoff=reconnect_backoff,
173
+ max_reconnect_backoff=max_reconnect_backoff,
166
174
  queue_maxsize=queue_maxsize,
167
175
  )
168
176
 
@@ -189,6 +197,8 @@ class MxEdgesEvents(_MistWebsocket):
189
197
  Maximum number of reconnect attempts before giving up.
190
198
  reconnect_backoff : float, default 2.0
191
199
  Base backoff delay in seconds. Doubles after each failed attempt.
200
+ max_reconnect_backoff : float | None, default None
201
+ Maximum backoff delay in seconds. If None, backoff grows indefinitely.
192
202
  queue_maxsize : int, default 0
193
203
  Maximum number of messages buffered in the internal queue for the
194
204
  ``receive()`` generator. ``0`` means unbounded. When set,
@@ -229,6 +239,7 @@ class MxEdgesEvents(_MistWebsocket):
229
239
  auto_reconnect: bool = False,
230
240
  max_reconnect_attempts: int = 5,
231
241
  reconnect_backoff: float = 2.0,
242
+ max_reconnect_backoff: float | None = None,
232
243
  queue_maxsize: int = 0,
233
244
  ) -> None:
234
245
  super().__init__(
@@ -239,5 +250,6 @@ class MxEdgesEvents(_MistWebsocket):
239
250
  auto_reconnect=auto_reconnect,
240
251
  max_reconnect_attempts=max_reconnect_attempts,
241
252
  reconnect_backoff=reconnect_backoff,
253
+ max_reconnect_backoff=max_reconnect_backoff,
242
254
  queue_maxsize=queue_maxsize,
243
255
  )
@@ -46,6 +46,8 @@ class SessionWithUrl(_MistWebsocket):
46
46
  Maximum number of reconnect attempts before giving up.
47
47
  reconnect_backoff : float, default 2.0
48
48
  Base backoff delay in seconds. Doubles after each failed attempt.
49
+ max_reconnect_backoff : float | None, default None
50
+ Maximum backoff delay in seconds. If None, backoff grows indefinitely.
49
51
  queue_maxsize : int, default 0
50
52
  Maximum number of messages buffered in the internal queue for the
51
53
  ``receive()`` generator. ``0`` means unbounded. When set,
@@ -86,6 +88,7 @@ class SessionWithUrl(_MistWebsocket):
86
88
  auto_reconnect: bool = False,
87
89
  max_reconnect_attempts: int = 5,
88
90
  reconnect_backoff: float = 2.0,
91
+ max_reconnect_backoff: float | None = None,
89
92
  queue_maxsize: int = 0,
90
93
  ) -> None:
91
94
  parsed = urlparse(url)
@@ -100,6 +103,7 @@ class SessionWithUrl(_MistWebsocket):
100
103
  auto_reconnect=auto_reconnect,
101
104
  max_reconnect_attempts=max_reconnect_attempts,
102
105
  reconnect_backoff=reconnect_backoff,
106
+ max_reconnect_backoff=max_reconnect_backoff,
103
107
  queue_maxsize=queue_maxsize,
104
108
  )
105
109