python-netgear-switch-library 0.0.post290__tar.gz → 0.0.post294__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 (306) hide show
  1. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/PKG-INFO +1 -1
  2. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/_version.py +2 -2
  3. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/snmp_write.py +42 -8
  4. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/seed.py +9 -0
  5. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/state.py +31 -3
  6. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_snmp_write.py +94 -0
  7. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_state_seed.py +43 -0
  8. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_virtual_snmp_face.py +12 -3
  9. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/.github/workflows/ci.yml +0 -0
  10. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/.github/workflows/deb.yml +0 -0
  11. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/.github/workflows/publish-pypi.yml +0 -0
  12. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/.gitignore +0 -0
  13. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/LICENSE +0 -0
  14. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/README.md +0 -0
  15. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/RELEASING.md +0 -0
  16. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/debian/changelog +0 -0
  17. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/debian/control +0 -0
  18. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/debian/copyright +0 -0
  19. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/debian/rules +0 -0
  20. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/debian/source/format +0 -0
  21. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/docs/superpowers/plans/2026-07-15-foundation.md +0 -0
  22. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/docs/superpowers/plans/2026-07-17-slice-02-snmp-read-core.md +0 -0
  23. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/docs/superpowers/plans/2026-07-17-slice-03-read-apis.md +0 -0
  24. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/docs/superpowers/plans/2026-07-18-slice-04-snmp-write.md +0 -0
  25. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/docs/superpowers/plans/2026-07-18-slice-05-nsdp.md +0 -0
  26. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/docs/superpowers/plans/2026-07-18-slice-06-http.md +0 -0
  27. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/docs/superpowers/plans/2026-07-18-slice-07-cli.md +0 -0
  28. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/docs/superpowers/plans/2026-07-18-slice-08-packaging-ci.md +0 -0
  29. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/docs/superpowers/plans/2026-07-23-gsm7252ps-http-xe-dialect.md +0 -0
  30. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/docs/superpowers/specs/2026-07-15-netgear-control-library-design.md +0 -0
  31. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/docs/superpowers/specs/2026-07-23-gsm7252ps-http-xe-dialect-design.md +0 -0
  32. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/packaging/apt-index.html +0 -0
  33. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/packaging/ci-build.sh +0 -0
  34. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/packaging/deb-version.py +0 -0
  35. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/pyproject.toml +0 -0
  36. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/__init__.py +0 -0
  37. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/_dispatch.py +0 -0
  38. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/aio_api.py +0 -0
  39. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/cli/__init__.py +0 -0
  40. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/cli/capture.py +0 -0
  41. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/cli/context.py +0 -0
  42. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/cli/format.py +0 -0
  43. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/cli/main.py +0 -0
  44. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/cli/resolve.py +0 -0
  45. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/cli/safety.py +0 -0
  46. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/cli_read.py +0 -0
  47. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/cli_write.py +0 -0
  48. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/config.py +0 -0
  49. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/errors.py +0 -0
  50. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/http_read.py +0 -0
  51. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/http_write.py +0 -0
  52. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/mcp/__init__.py +0 -0
  53. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/mcp/server.py +0 -0
  54. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/models.py +0 -0
  55. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/nsdp_read.py +0 -0
  56. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/nsdp_write.py +0 -0
  57. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/__init__.py +0 -0
  58. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/cli/__init__.py +0 -0
  59. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/cli/commands.py +0 -0
  60. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/cli/parse.py +0 -0
  61. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/http/__init__.py +0 -0
  62. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/http/crypt.py +0 -0
  63. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/http/endpoints.py +0 -0
  64. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/http/forms.py +0 -0
  65. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/http/parse.py +0 -0
  66. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/http/session.py +0 -0
  67. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/http/types.py +0 -0
  68. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/nsdp/__init__.py +0 -0
  69. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/nsdp/auth.py +0 -0
  70. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/nsdp/client.py +0 -0
  71. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/nsdp/parsers.py +0 -0
  72. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/nsdp/protocol.py +0 -0
  73. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/nsdp/types.py +0 -0
  74. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/nsdp/write.py +0 -0
  75. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/snmp/__init__.py +0 -0
  76. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/snmp/client.py +0 -0
  77. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/snmp/oids.py +0 -0
  78. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/snmp/parse.py +0 -0
  79. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/protocols/snmp/write.py +0 -0
  80. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/py.typed +0 -0
  81. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/registry.py +0 -0
  82. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/snmp_read.py +0 -0
  83. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/sync_api.py +0 -0
  84. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/__init__.py +0 -0
  85. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/aio/__init__.py +0 -0
  86. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/aio/nsdp_udp.py +0 -0
  87. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/aio/snmp_pysnmp.py +0 -0
  88. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/cli/__init__.py +0 -0
  89. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/cli/console.py +0 -0
  90. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/cli/session.py +0 -0
  91. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/cli/ssh.py +0 -0
  92. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/cli/telnet.py +0 -0
  93. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/http/__init__.py +0 -0
  94. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/http/client.py +0 -0
  95. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/sync/__init__.py +0 -0
  96. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/sync/nsdp_udp.py +0 -0
  97. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/transport/sync/snmp_netsnmp_cli.py +0 -0
  98. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/__init__.py +0 -0
  99. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/cli_fastpath.py +0 -0
  100. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/faces/__init__.py +0 -0
  101. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/faces/cli.py +0 -0
  102. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/faces/http.py +0 -0
  103. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/faces/mibview.py +0 -0
  104. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/faces/nsdp.py +0 -0
  105. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/faces/snmp.py +0 -0
  106. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/server.py +0 -0
  107. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/web.py +0 -0
  108. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/web_gs105pe.py +0 -0
  109. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/web_gs110emx.py +0 -0
  110. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/web_gs110emx_templates.py +0 -0
  111. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/web_gs728tpp.py +0 -0
  112. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/web_gsm7228ps.py +0 -0
  113. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/web_gsm7252ps.py +0 -0
  114. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/src/netgear_switch/virtual/web_m4300.py +0 -0
  115. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/capture_parity.py +0 -0
  116. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_capture.py +0 -0
  117. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_cli_integration.py +0 -0
  118. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_control_poe_port.py +0 -0
  119. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_control_vlan_ip.py +0 -0
  120. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_format.py +0 -0
  121. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_main_framework.py +0 -0
  122. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_new_commands.py +0 -0
  123. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_op_coverage.py +0 -0
  124. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_prompt_wiring.py +0 -0
  125. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_read_commands.py +0 -0
  126. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_resolve.py +0 -0
  127. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_safety.py +0 -0
  128. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/cli/test_serve.py +0 -0
  129. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/conftest.py +0 -0
  130. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/equivalence.py +0 -0
  131. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/captures/gsm7228ps.json +0 -0
  132. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/captures/gsm7252ps.json +0 -0
  133. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/captures/m4300-16x.json +0 -0
  134. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/captures/m4300-24x.json +0 -0
  135. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7228ps_environment.txt +0 -0
  136. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7228ps_lldp.txt +0 -0
  137. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7228ps_mac_table.txt +0 -0
  138. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7228ps_network.txt +0 -0
  139. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7228ps_poe.txt +0 -0
  140. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7228ps_port_all.txt +0 -0
  141. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7228ps_show_version.txt +0 -0
  142. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7228ps_vlan.txt +0 -0
  143. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7228ps_vlan_brief.txt +0 -0
  144. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7228ps_vlan_port_all.txt +0 -0
  145. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7252ps_show_environment.txt +0 -0
  146. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7252ps_show_interface_ethernet_1_0_1.txt +0 -0
  147. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7252ps_show_lldp_remote_device_all.txt +0 -0
  148. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7252ps_show_mac_addr_table.txt +0 -0
  149. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7252ps_show_network.txt +0 -0
  150. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7252ps_show_poe_port_info_all.txt +0 -0
  151. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7252ps_show_port_all.txt +0 -0
  152. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7252ps_show_version.txt +0 -0
  153. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7252ps_show_vlan_90.txt +0 -0
  154. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7252ps_show_vlan_brief.txt +0 -0
  155. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/gsm7252ps_show_vlan_port_all.txt +0 -0
  156. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_environment.txt +0 -0
  157. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_interface_ethernet_1_0_1.txt +0 -0
  158. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_ip_management.txt +0 -0
  159. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_lldp_remote_device_all.txt +0 -0
  160. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_mac_addr_table.txt +0 -0
  161. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_poe_port_info_all.txt +0 -0
  162. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_port_all.txt +0 -0
  163. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_version.txt +0 -0
  164. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_vlan.txt +0 -0
  165. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_vlan_1.txt +0 -0
  166. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_vlan_4.txt +0 -0
  167. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_vlan_5.txt +0 -0
  168. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_16x_show_vlan_port_all.txt +0 -0
  169. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_24x_show_environment.txt +0 -0
  170. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_24x_show_interface_ethernet_1_0_1.txt +0 -0
  171. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_24x_show_ip_management.txt +0 -0
  172. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_24x_show_lldp_remote_device_all.txt +0 -0
  173. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_24x_show_mac_addr_table.txt +0 -0
  174. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_24x_show_port_all.txt +0 -0
  175. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_24x_show_version.txt +0 -0
  176. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_24x_show_vlan.txt +0 -0
  177. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_24x_show_vlan_5.txt +0 -0
  178. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_24x_show_vlan_90.txt +0 -0
  179. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/cli/m4300_24x_show_vlan_port_all.txt +0 -0
  180. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs105pe_membership.html +0 -0
  181. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs105pe_portstats.html +0 -0
  182. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs105pe_pvid.html +0 -0
  183. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs105pe_status.html +0 -0
  184. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs105pe_switch_info.html +0 -0
  185. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs105pe_vlancfg.html +0 -0
  186. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs110emx_cf8021q.html +0 -0
  187. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs110emx_interface_stats.html +0 -0
  188. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs110emx_login.html +0 -0
  189. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs110emx_port_settings.html +0 -0
  190. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs110emx_pvid.html +0 -0
  191. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs110emx_redirect.html +0 -0
  192. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs110emx_sysinfo.html +0 -0
  193. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs110emx_vlanmembership.html +0 -0
  194. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs305ep_dashboard.html +0 -0
  195. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs305ep_login.html +0 -0
  196. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs305ep_membership.html +0 -0
  197. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs305ep_poestatus.html +0 -0
  198. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs305ep_portstats.html +0 -0
  199. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs305ep_pvid.html +0 -0
  200. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs305ep_vlancfg.html +0 -0
  201. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs728tpp_device_info_and_sensors.xml +0 -0
  202. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs728tpp_lldp.xml +0 -0
  203. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs728tpp_macs.xml +0 -0
  204. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs728tpp_mgmt_ip.xml +0 -0
  205. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs728tpp_poe.xml +0 -0
  206. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs728tpp_ports.xml +0 -0
  207. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs728tpp_pvids_membership.xml +0 -0
  208. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs728tpp_vlan_membership_per_vlan.xml +0 -0
  209. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gs728tpp_vlans.xml +0 -0
  210. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7228ps_basicAddressTable.html +0 -0
  211. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7228ps_lldpRemoteInventory.html +0 -0
  212. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7228ps_poeInterfaceConfiguration.html +0 -0
  213. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7228ps_portPvidConfiguration.html +0 -0
  214. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7228ps_portStatistics.html +0 -0
  215. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7228ps_portsConfiguration.html +0 -0
  216. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7228ps_sysInfo.html +0 -0
  217. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7228ps_vlanStatus.html +0 -0
  218. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7252ps_basicAddressTable.html +0 -0
  219. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7252ps_lldpRemoteInventory.html +0 -0
  220. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7252ps_login.html +0 -0
  221. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7252ps_poeInterfaceConfiguration.html +0 -0
  222. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7252ps_portPvidConfiguration.html +0 -0
  223. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7252ps_portStatistics.html +0 -0
  224. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7252ps_portsConfiguration.html +0 -0
  225. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7252ps_sysInfo.html +0 -0
  226. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/gsm7252ps_vlanStatus.html +0 -0
  227. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/m4300_addresstable.html +0 -0
  228. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/m4300_ports.html +0 -0
  229. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/m4300_portstats.html +0 -0
  230. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/m4300_pvid.html +0 -0
  231. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/m4300_sysinfo.html +0 -0
  232. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/http/m4300_vlanstatus.html +0 -0
  233. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/snmp/gsm7252ps_fans.txt +0 -0
  234. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/snmp/gsm7252ps_ifhighspeed.txt +0 -0
  235. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/snmp/gsm7252ps_ifoperstatus.txt +0 -0
  236. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/fixtures/snmp/gsm7252ps_psu.txt +0 -0
  237. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/http_specs.py +0 -0
  238. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/cli/test_cli_parse.py +0 -0
  239. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/http/test_crypt.py +0 -0
  240. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/http/test_endpoints.py +0 -0
  241. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/http/test_forms.py +0 -0
  242. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/http/test_parse.py +0 -0
  243. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/nsdp/test_auth.py +0 -0
  244. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/nsdp/test_parsers.py +0 -0
  245. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/nsdp/test_protocol.py +0 -0
  246. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/nsdp/test_write_frame.py +0 -0
  247. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/snmp/test_client.py +0 -0
  248. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/snmp/test_oids.py +0 -0
  249. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/snmp/test_parse_lldp_macs.py +0 -0
  250. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/snmp/test_parse_mgmt_ip.py +0 -0
  251. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/snmp/test_parse_poe_sensors.py +0 -0
  252. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/snmp/test_parse_ports.py +0 -0
  253. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/snmp/test_parse_system_info.py +0 -0
  254. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/snmp/test_parse_vlans.py +0 -0
  255. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/protocols/snmp/test_write_encode.py +0 -0
  256. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_aio_api.py +0 -0
  257. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_cli_read.py +0 -0
  258. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_cli_write.py +0 -0
  259. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_config.py +0 -0
  260. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_cross_backend_equivalence.py +0 -0
  261. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_deb_version.py +0 -0
  262. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_dispatch.py +0 -0
  263. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_errors.py +0 -0
  264. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_facade_equivalence.py +0 -0
  265. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_http_dispatch.py +0 -0
  266. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_http_equivalence.py +0 -0
  267. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_http_read.py +0 -0
  268. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_http_write.py +0 -0
  269. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_import.py +0 -0
  270. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_mcp_server.py +0 -0
  271. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_models.py +0 -0
  272. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_models_snmp_read.py +0 -0
  273. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_nsdp_integration.py +0 -0
  274. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_nsdp_read.py +0 -0
  275. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_nsdp_write.py +0 -0
  276. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_public_api.py +0 -0
  277. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_quality_gates.py +0 -0
  278. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_registry.py +0 -0
  279. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_snmp_integration.py +0 -0
  280. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_snmp_read.py +0 -0
  281. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_sync_api.py +0 -0
  282. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_version.py +0 -0
  283. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/test_write_equivalence.py +0 -0
  284. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/transport/_fastpath_fake.py +0 -0
  285. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/transport/test_cli_console.py +0 -0
  286. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/transport/test_cli_scp_cert.py +0 -0
  287. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/transport/test_cli_telnet.py +0 -0
  288. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/transport/test_http_client.py +0 -0
  289. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/transport/test_nsdp_udp_sync.py +0 -0
  290. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/transport/test_set_transport.py +0 -0
  291. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/transport/test_snmp_netsnmp_cli.py +0 -0
  292. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/transport/test_snmp_pysnmp.py +0 -0
  293. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/transport/test_value_parity.py +0 -0
  294. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_cli_cross_backend.py +0 -0
  295. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_cli_gsm7228ps_parity.py +0 -0
  296. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_gsm7228ps_seed.py +0 -0
  297. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_m4300_seeds.py +0 -0
  298. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_mibview.py +0 -0
  299. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_mutable_state.py +0 -0
  300. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_nsdp_state.py +0 -0
  301. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_serve_daemon.py +0 -0
  302. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_snmp_write_face.py +0 -0
  303. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_virtual_http_face.py +0 -0
  304. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_virtual_nsdp_face.py +0 -0
  305. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/tests/virtual/test_web_projection.py +0 -0
  306. {python_netgear_switch_library-0.0.post290 → python_netgear_switch_library-0.0.post294}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-netgear-switch-library
3
- Version: 0.0.post290
3
+ Version: 0.0.post294
4
4
  Summary: Python library and CLI to query and control Netgear switches over SNMP, NSDP and HTTP.
5
5
  Author-email: Tim Ansell <me@mith.ro>
6
6
  License-Expression: Apache-2.0
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.0.post290'
22
- __version_tuple__ = version_tuple = (0, 0, 'post290')
21
+ __version__ = version = '0.0.post294'
22
+ __version_tuple__ = version_tuple = (0, 0, 'post294')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -109,6 +109,22 @@ class SnmpWriter:
109
109
  def _vlan(self, vlan: int) -> VLANInfo | None:
110
110
  return next((v for v in self._reader.get_vlans() if v.vlan_id == vlan), None)
111
111
 
112
+ def _raw_bitmap(self, base_oid: str, vlan: int) -> bytes | None:
113
+ """The device's own PortList octets for ``vlan``, width intact.
114
+
115
+ VLANInfo carries decoded port sets, so re-encoding from it would size
116
+ the bitmap to the highest port in use rather than to the width the
117
+ device actually uses. Netgear switches report a PortList covering LAG
118
+ and CPU pseudo-ports: measured live, 131 bytes on a 28-port M4300-24X
119
+ and 79 bytes on a GSM7252PS. Returns None if the device did not report
120
+ this VLAN as octets, so callers can fall back.
121
+ """
122
+ suffix = f".{vlan}"
123
+ for row in self.client.walk(base_oid):
124
+ if row.oid.endswith(suffix) and isinstance(row.value, bytes):
125
+ return row.value
126
+ return None
127
+
112
128
  def set_poe(self, port: int, on: bool, *, force: bool = False) -> None:
113
129
  if not on:
114
130
  self._guard(port, force) # turning PoE off is disruptive
@@ -253,11 +269,17 @@ class SnmpWriter:
253
269
  # Precondition failure: no SET has been attempted, so this is NOT a
254
270
  # verification divergence (review item 9).
255
271
  raise SnmpError(f"VLAN {vlan} does not exist")
272
+ # Feed set_port_bit the device's OWN bitmaps so it preserves their exact
273
+ # wire width (that is what it is for); fall back to a re-encode of the
274
+ # decoded sets only if the device did not report octets.
275
+ raw_egress = self._raw_bitmap(oids.DOT1Q_VLAN_STATIC_EGRESS, vlan)
276
+ raw_untagged = self._raw_bitmap(oids.DOT1Q_VLAN_STATIC_UNTAGGED, vlan)
256
277
  new_egress, new_untagged = membership_bitmaps(
257
- mode=mode,
258
- port=port,
259
- egress=encode_port_bitmap(before.member_ports),
260
- untagged=encode_port_bitmap(before.untagged_ports),
278
+ mode=mode, port=port,
279
+ egress=(raw_egress if raw_egress is not None
280
+ else encode_port_bitmap(before.member_ports)),
281
+ untagged=(raw_untagged if raw_untagged is not None
282
+ else encode_port_bitmap(before.untagged_ports)),
261
283
  width_bytes=vlan_bitmap_width(self.model),
262
284
  )
263
285
  self.client.set_many(
@@ -426,6 +448,14 @@ class AsyncSnmpWriter:
426
448
  vlans = await self._reader.get_vlans()
427
449
  return next((v for v in vlans if v.vlan_id == vlan), None)
428
450
 
451
+ async def _raw_bitmap(self, base_oid: str, vlan: int) -> bytes | None:
452
+ """Async twin of ``SnmpWriter._raw_bitmap`` -- see it for why."""
453
+ suffix = f".{vlan}"
454
+ for row in await self.client.walk(base_oid):
455
+ if row.oid.endswith(suffix) and isinstance(row.value, bytes):
456
+ return row.value
457
+ return None
458
+
429
459
  async def set_poe(self, port: int, on: bool, *, force: bool = False) -> None:
430
460
  if not on:
431
461
  self._guard(port, force)
@@ -564,11 +594,15 @@ class AsyncSnmpWriter:
564
594
  if before is None:
565
595
  # Precondition failure (review item 9): no SET attempted.
566
596
  raise SnmpError(f"VLAN {vlan} does not exist")
597
+ # Preserve the device's own bitmap width -- see SnmpWriter._raw_bitmap.
598
+ raw_egress = await self._raw_bitmap(oids.DOT1Q_VLAN_STATIC_EGRESS, vlan)
599
+ raw_untagged = await self._raw_bitmap(oids.DOT1Q_VLAN_STATIC_UNTAGGED, vlan)
567
600
  new_egress, new_untagged = membership_bitmaps(
568
- mode=mode,
569
- port=port,
570
- egress=encode_port_bitmap(before.member_ports),
571
- untagged=encode_port_bitmap(before.untagged_ports),
601
+ mode=mode, port=port,
602
+ egress=(raw_egress if raw_egress is not None
603
+ else encode_port_bitmap(before.member_ports)),
604
+ untagged=(raw_untagged if raw_untagged is not None
605
+ else encode_port_bitmap(before.untagged_ports)),
572
606
  width_bytes=vlan_bitmap_width(self.model),
573
607
  )
574
608
  await self.client.set_many(
@@ -1187,6 +1187,9 @@ def seed_gsm7252ps() -> VirtualSwitchState:
1187
1187
  vlans=vlans,
1188
1188
  pvids=pvids,
1189
1189
  poe=poe,
1190
+ # Real fixed Q-BRIDGE PortList width, measured LIVE (read-only) on this
1191
+ # switch @10.1.5.22: dot1qVlanStaticEgressPorts is 79 bytes wide.
1192
+ vlan_portlist_width=79,
1190
1193
  sensors=sensors,
1191
1194
  http_sensors=http_sensors,
1192
1195
  macs=macs,
@@ -2170,6 +2173,9 @@ def seed_m4300_24x() -> VirtualSwitchState:
2170
2173
  ports=ports,
2171
2174
  vlans=vlans,
2172
2175
  pvids=pvids,
2176
+ # Real fixed Q-BRIDGE PortList width, measured LIVE (read-only) on the
2177
+ # M4300 @10.1.5.13: dot1qVlanStaticEgressPorts is 131 bytes wide.
2178
+ vlan_portlist_width=131,
2173
2179
  poe={}, # VERIFIED: real capture's poe=[] -- this model has NO PoE.
2174
2180
  sensors=sensors,
2175
2181
  macs=macs,
@@ -2339,6 +2345,9 @@ def seed_m4300_16x() -> VirtualSwitchState:
2339
2345
  ports=ports,
2340
2346
  vlans=vlans,
2341
2347
  pvids=pvids,
2348
+ # Real fixed Q-BRIDGE PortList width, measured LIVE (read-only) on this
2349
+ # switch @10.1.5.20: dot1qVlanStaticEgressPorts is 131 bytes wide.
2350
+ vlan_portlist_width=131,
2342
2351
  poe=poe, # VERIFIED: real capture -- all 16 ports PoE-capable.
2343
2352
  sensors=sensors,
2344
2353
  macs=macs,
@@ -263,6 +263,20 @@ class VirtualSwitchState:
263
263
  # 6-byte encoding; only a seed with hardware evidence of this quirk
264
264
  # should set it True.
265
265
  dot1d_base_mac_ascii: bool = False
266
+ # Fixed Q-BRIDGE PortList byte-width the SNMP agent reports for
267
+ # dot1qVlanStaticEgressPorts / dot1qVlanStaticUntaggedPorts. A real switch
268
+ # emits a CONSTANT-width bitmap covering every port it knows -- physical
269
+ # ports PLUS the LAG/CPU pseudo-ports far above the physical count -- so the
270
+ # width does NOT track the highest member. Measured LIVE (read-only,
271
+ # community "public"): GSM7252PS @10.1.5.22 = 79 bytes (highest set byte 60
272
+ # => LAG ~port 481); M4300 @10.1.5.13 = 131 bytes (highest set byte 112 =>
273
+ # ~port 897). None = unmeasured: oid_map() falls back to
274
+ # vlan_bitmap_width(model), the physical-port-only width. Seeding the REAL
275
+ # width is what lets the mock catch the historical writer bug (issue #3):
276
+ # the buggy writer re-encoded the decoded member set at max(8, port_count/8)
277
+ # rather than preserving the device width, so it sent a SET narrower than
278
+ # this -- which a stricter Q-BRIDGE agent rejects outright.
279
+ vlan_portlist_width: int | None = None
266
280
 
267
281
  @property
268
282
  def sysinfo_sensors(self) -> list[SensorSim]:
@@ -290,7 +304,13 @@ class VirtualSwitchState:
290
304
  # vendor-column projections below are skipped, matching a real agent
291
305
  # that answers noSuchObject for the whole 4526 tree.
292
306
  v = oids.vendor_oids(model) if oids.has_vendor_oids(model) else None
293
- vlan_width = vlan_bitmap_width(model)
307
+ # Prefer the device's REAL fixed PortList width (live-measured, seeded on
308
+ # vlan_portlist_width) so the mock is an INDEPENDENT source of truth for
309
+ # the wire width -- not a re-derivation of the same vlan_bitmap_width()
310
+ # formula the writer uses (that shared assumption is exactly why the mock
311
+ # never caught issue #3). Falls back to the physical-port-only width when
312
+ # a model's real width hasn't been measured.
313
+ vlan_width = self.vlan_portlist_width or vlan_bitmap_width(model)
294
314
  m: dict[str, tuple[str, str]] = {}
295
315
 
296
316
  # dot1dBaseBridgeAddress (BRIDGE-MIB scalar): the switch's own base
@@ -514,7 +534,15 @@ class VirtualSwitchState:
514
534
  self.pvids[port] = int(value)
515
535
  return
516
536
 
517
- # dot1qVlanStaticEgressPorts.<vid>
537
+ # dot1qVlanStaticEgressPorts.<vid> -- decode the incoming PortList and
538
+ # REPLACE the member set, exactly as a real Q-BRIDGE agent does. A
539
+ # too-narrow PortList (the historical writer bug) is faithfully
540
+ # truncating here: every member beyond the incoming byte width is
541
+ # silently dropped -- the exact silent VLAN corruption the GSM7252PS
542
+ # exhibits on hardware for an 8-byte SET against its 79-byte PortList.
543
+ # tests/virtual/test_snmp_write_face.py proves both the corruption (a
544
+ # narrow SET drops the LAG/CPU members) and that the width-preserving
545
+ # writer keeps them.
518
546
  vid = _tail(oids.DOT1Q_VLAN_STATIC_EGRESS)
519
547
  if vid is not None and vid in self.vlans:
520
548
  from ..protocols.snmp.parse import decode_port_bitmap
@@ -522,7 +550,7 @@ class VirtualSwitchState:
522
550
  self.vlans[vid].member = set(decode_port_bitmap(_as_bytes(value)))
523
551
  return
524
552
 
525
- # dot1qVlanStaticUntaggedPorts.<vid>
553
+ # dot1qVlanStaticUntaggedPorts.<vid> (same truncation semantics)
526
554
  vid = _tail(oids.DOT1Q_VLAN_STATIC_UNTAGGED)
527
555
  if vid is not None and vid in self.vlans:
528
556
  from ..protocols.snmp.parse import decode_port_bitmap
@@ -295,6 +295,100 @@ def test_set_vlan_membership_catches_dropped_untagged_write():
295
295
  assert "untagged" in str(exc.value)
296
296
 
297
297
 
298
+ def test_set_vlan_membership_preserves_device_bitmap_width():
299
+ """A SET must be as wide as the PortList the device actually reports.
300
+
301
+ Netgear switches report a PortList far wider than the model's physical
302
+ port count -- it covers LAG and CPU pseudo-ports too. Measured live:
303
+ 131 bytes on an M4300-24X (port_count 28) and on an M4300-16X, 79 bytes
304
+ on a GSM7252PS. Re-deriving the width from the decoded port set instead of
305
+ the device's own bitmap makes the SET a different wire length than the
306
+ device uses.
307
+ """
308
+ wide = bytes(131) # the device's PortList width, no ports set yet
309
+ tables = _vlan_tables()
310
+ tables[oids.DOT1Q_VLAN_STATIC_EGRESS] = [
311
+ SnmpRow(f"{oids.DOT1Q_VLAN_STATIC_EGRESS}.90", wide, "Hex-STRING")
312
+ ]
313
+ tables[oids.DOT1Q_VLAN_STATIC_UNTAGGED] = [
314
+ SnmpRow(f"{oids.DOT1Q_VLAN_STATIC_UNTAGGED}.90", wide, "Hex-STRING")
315
+ ]
316
+ client = ApplyingVlanClient(tables)
317
+ w = SnmpWriter(client, get_model("m4300-24x"))
318
+ w.set_vlan_membership(90, 7, VlanMode.UNTAGGED, force=True)
319
+
320
+ egress_set = next(
321
+ vb for vb in client.sets
322
+ if vb.oid.startswith(oids.DOT1Q_VLAN_STATIC_EGRESS)
323
+ )
324
+ untagged_set = next(
325
+ vb for vb in client.sets
326
+ if vb.oid.startswith(oids.DOT1Q_VLAN_STATIC_UNTAGGED)
327
+ )
328
+ assert len(egress_set.value) == len(wide)
329
+ assert len(untagged_set.value) == len(wide)
330
+ assert 7 in decode_port_bitmap(egress_set.value)
331
+ assert 7 in decode_port_bitmap(untagged_set.value)
332
+
333
+
334
+ def _bitmap_bytes(value: object) -> bytes:
335
+ """Coerce an oid_map() PortList value (bytes or latin-1 wire str) to bytes."""
336
+ if isinstance(value, (bytes, bytearray)):
337
+ return bytes(value)
338
+ return str(value).encode("latin-1")
339
+
340
+
341
+ def test_set_vlan_membership_preserves_mock_emitted_portlist_width():
342
+ """End-to-end with the VIRTUAL MOCK as the device -- the regression that
343
+ ties the mock's independent width to the writer preserving it (issue #3).
344
+
345
+ The seeded gsm7252ps mock now emits the device's REAL fixed PortList width
346
+ (79 bytes, live-measured @10.1.5.22), not the physical-port-only
347
+ vlan_bitmap_width() the writer historically re-derived. A SET must go out at
348
+ that full 79-byte width. The OLD writer -- which re-encoded the decoded
349
+ member set at max(8, port_count/8), growing only to cover the highest
350
+ member -- would emit at most ceil(highest_member/8) bytes (<= 61 here),
351
+ NEVER 79, so this test fails against it. It is green now precisely because
352
+ _raw_bitmap() preserves the device's own bitmap width.
353
+ """
354
+ from netgear_switch.virtual.seed import seed_gsm7252ps
355
+
356
+ state = seed_gsm7252ps()
357
+ m = state.oid_map()
358
+ vid = min(state.vlans) # a real seeded VLAN (VLAN 1)
359
+ egress = _bitmap_bytes(m[f"{oids.DOT1Q_VLAN_STATIC_EGRESS}.{vid}"][1])
360
+ untagged = _bitmap_bytes(m[f"{oids.DOT1Q_VLAN_STATIC_UNTAGGED}.{vid}"][1])
361
+ # The mock is faithful to the live measurement: a fixed 79-byte PortList.
362
+ assert len(egress) == 79
363
+
364
+ members = set(decode_port_bitmap(egress))
365
+ unused = next(p for p in range(1, 49) if p not in members) # a free phys port
366
+
367
+ tables = {
368
+ oids.DOT1Q_VLAN_STATIC_NAME: [
369
+ SnmpRow(f"{oids.DOT1Q_VLAN_STATIC_NAME}.{vid}", "seeded", "STRING")
370
+ ],
371
+ oids.DOT1Q_VLAN_STATIC_EGRESS: [
372
+ SnmpRow(f"{oids.DOT1Q_VLAN_STATIC_EGRESS}.{vid}", egress, "Hex-STRING")
373
+ ],
374
+ oids.DOT1Q_VLAN_STATIC_UNTAGGED: [
375
+ SnmpRow(f"{oids.DOT1Q_VLAN_STATIC_UNTAGGED}.{vid}", untagged, "Hex-STRING")
376
+ ],
377
+ }
378
+ client = ApplyingVlanClient(tables)
379
+ w = SnmpWriter(client, get_model("gsm7252ps"))
380
+ w.set_vlan_membership(vid, unused, VlanMode.TAGGED, force=True)
381
+
382
+ egress_set = next(
383
+ vb for vb in client.sets if vb.oid.startswith(oids.DOT1Q_VLAN_STATIC_EGRESS)
384
+ )
385
+ # Width preserved end-to-end, and no member lost while adding the new port.
386
+ assert len(egress_set.value) == 79
387
+ got = set(decode_port_bitmap(egress_set.value))
388
+ assert unused in got
389
+ assert members <= got
390
+
391
+
298
392
  def test_set_vlan_membership_missing_vlan_is_precondition_not_verify_error():
299
393
  client = ApplyingVlanClient({}) # no VLAN 90 present
300
394
  w = SnmpWriter(client, get_model("gsm7252ps"))
@@ -230,3 +230,46 @@ def test_seed_gsm7252ps_iot_vlan_90_matches_capture():
230
230
  assert port in state.vlans[90].untagged
231
231
  assert dict(capture["pvids"])[1] == state.pvids[1] == 90
232
232
  assert dict(capture["pvids"])[2] == state.pvids[2] == 90
233
+
234
+
235
+ def test_seed_emits_real_fixed_vlan_portlist_width():
236
+ """Every VLAN's egress/untagged PortList is the device's REAL fixed byte
237
+ width, LIVE-measured read-only on each switch, NOT the physical-port-only
238
+ vlan_bitmap_width(). This is what makes the mock an independent source of
239
+ truth for the wire width (github issue #3): the historical writer bug --
240
+ re-encoding the decoded member set at max(8, port_count/8) -- sent a SET
241
+ narrower than this, which the mock now models faithfully so a round-trip
242
+ test can catch it.
243
+
244
+ Widths: gsm7252ps=79B @10.1.5.22, m4300-24x=131B @10.1.5.13,
245
+ m4300-16x=131B @10.1.5.20 (dot1qVlanStaticEgressPorts, community public).
246
+ """
247
+ from netgear_switch.virtual.seed import (
248
+ seed_gsm7252ps,
249
+ seed_m4300_16x,
250
+ seed_m4300_24x,
251
+ )
252
+
253
+ for seed, expected in (
254
+ (seed_gsm7252ps, 79),
255
+ (seed_m4300_24x, 131),
256
+ (seed_m4300_16x, 131),
257
+ ):
258
+ state = seed()
259
+ m = state.oid_map()
260
+ egress = [
261
+ v for k, v in m.items() if k.startswith(oids.DOT1Q_VLAN_STATIC_EGRESS + ".")
262
+ ]
263
+ untagged = [
264
+ v
265
+ for k, v in m.items()
266
+ if k.startswith(oids.DOT1Q_VLAN_STATIC_UNTAGGED + ".")
267
+ ]
268
+ assert egress, f"{seed.__name__}: no VLAN egress rows emitted"
269
+ for _typ, value in egress + untagged:
270
+ raw = value if isinstance(value, (bytes, bytearray)) else value.encode(
271
+ "latin-1"
272
+ )
273
+ assert len(raw) == expected, (
274
+ f"{seed.__name__}: PortList {len(raw)}B, expected fixed {expected}B"
275
+ )
@@ -241,9 +241,13 @@ def test_type_token_round_trips_through_pysnmp_client():
241
241
  rows = asyncio.run(client.get([oid]))
242
242
  assert rows == [SnmpRow(oid, sw.state.mgmt.address, "IpAddress")]
243
243
 
244
- # OCTETSTR-as-bytes bitmap: dot1qVlanStaticEgressPorts.90
244
+ # OCTETSTR-as-bytes bitmap: dot1qVlanStaticEgressPorts.90 -- the mock
245
+ # emits the device's REAL fixed PortList width (79 B, live-measured), so
246
+ # derive the expected at that seeded width, still straight from the seed.
245
247
  oid = f"{oids.DOT1Q_VLAN_STATIC_EGRESS}.90"
246
- expected_bitmap = encode_port_bitmap(vlan90.member).encode("latin-1")
248
+ expected_bitmap = encode_port_bitmap(
249
+ vlan90.member, width_bytes=sw.state.vlan_portlist_width
250
+ ).encode("latin-1")
247
251
  rows = asyncio.run(client.get([oid]))
248
252
  assert rows == [SnmpRow(oid, expected_bitmap, "Hex-STRING")]
249
253
 
@@ -401,7 +405,12 @@ def test_ip_address_and_bitmap_round_trip_through_netsnmp_cli_client():
401
405
  assert rows == [SnmpRow(oid, sw.state.mgmt.address, "IpAddress")]
402
406
 
403
407
  oid = f"{oids.DOT1Q_VLAN_STATIC_EGRESS}.90"
404
- expected_bitmap = encode_port_bitmap(vlan90.member).encode("latin-1")
408
+ # The mock emits the device's REAL fixed PortList width (79 B on the
409
+ # gsm7252ps, live-measured), so derive the expected bitmap at that same
410
+ # seeded width -- still straight from the seed, never hardcoded.
411
+ expected_bitmap = encode_port_bitmap(
412
+ vlan90.member, width_bytes=sw.state.vlan_portlist_width
413
+ ).encode("latin-1")
405
414
  rows = client.get([oid])
406
415
  assert rows == [SnmpRow(oid, expected_bitmap, "Hex-STRING")]
407
416
  finally: