python-netgear-switch-library 0.0.post325__tar.gz → 0.0.post327__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 (374) hide show
  1. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/PKG-INFO +1 -1
  2. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/_ext/support_tables.py +75 -10
  3. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/_static/ngsw.css +11 -0
  4. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/api/cli.rst +1 -1
  5. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/api/facades.rst +1 -1
  6. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/api/index.rst +1 -1
  7. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/conf.py +43 -2
  8. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/development.rst +2 -2
  9. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/fake/internals.rst +7 -5
  10. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/fake/serving.rst +1 -1
  11. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/fake/testing.rst +105 -41
  12. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/guide/concepts.rst +21 -20
  13. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/guide/configuration.rst +8 -8
  14. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/guide/installation.rst +1 -1
  15. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/guide/quickstart.rst +4 -4
  16. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/guide/reading.rst +17 -17
  17. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/guide/writing.rst +15 -15
  18. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/mcp.rst +1 -1
  19. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/models/gs105pe.rst +2 -0
  20. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/models/gs110emx.rst +3 -1
  21. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/models/gs305ep.rst +2 -0
  22. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/models/gs728tpp.rst +2 -0
  23. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/models/gsm7228ps.rst +5 -3
  24. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/models/gsm7252ps.rst +2 -0
  25. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/models/index.rst +3 -3
  26. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/models/m4300-16x.rst +3 -1
  27. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/models/m4300-24x.rst +7 -5
  28. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/models/support.rst +4 -4
  29. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/protocols/cli.rst +7 -7
  30. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/protocols/http.rst +3 -3
  31. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/protocols/nsdp.rst +4 -4
  32. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/protocols/snmp.rst +3 -3
  33. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/_version.py +2 -2
  34. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/aio_api.py +12 -6
  35. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/.github/workflows/ci.yml +0 -0
  36. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/.github/workflows/deb.yml +0 -0
  37. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/.github/workflows/publish-pypi.yml +0 -0
  38. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/.gitignore +0 -0
  39. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/.readthedocs.yaml +0 -0
  40. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/CLAUDE.md +0 -0
  41. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/LICENSE +0 -0
  42. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/README.md +0 -0
  43. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/RELEASING.md +0 -0
  44. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/debian/changelog +0 -0
  45. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/debian/control +0 -0
  46. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/debian/copyright +0 -0
  47. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/debian/rules +0 -0
  48. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/debian/source/format +0 -0
  49. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/Makefile +0 -0
  50. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/_ext/filelinks.py +0 -0
  51. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/api/core.rst +0 -0
  52. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/api/mcp.rst +0 -0
  53. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/api/operations.rst +0 -0
  54. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/api/protocols.rst +0 -0
  55. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/api/transport.rst +0 -0
  56. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/api/virtual.rst +0 -0
  57. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/cli.rst +0 -0
  58. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/fake/index.rst +0 -0
  59. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/guide/principles.rst +0 -0
  60. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/index.rst +0 -0
  61. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/protocols/index.rst +0 -0
  62. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/superpowers/plans/2026-07-15-foundation.md +0 -0
  63. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/superpowers/plans/2026-07-17-slice-02-snmp-read-core.md +0 -0
  64. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/superpowers/plans/2026-07-17-slice-03-read-apis.md +0 -0
  65. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/superpowers/plans/2026-07-18-slice-04-snmp-write.md +0 -0
  66. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/superpowers/plans/2026-07-18-slice-05-nsdp.md +0 -0
  67. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/superpowers/plans/2026-07-18-slice-06-http.md +0 -0
  68. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/superpowers/plans/2026-07-18-slice-07-cli.md +0 -0
  69. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/superpowers/plans/2026-07-18-slice-08-packaging-ci.md +0 -0
  70. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/superpowers/plans/2026-07-23-gsm7252ps-http-xe-dialect.md +0 -0
  71. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/superpowers/specs/2026-07-15-netgear-control-library-design.md +0 -0
  72. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/docs/superpowers/specs/2026-07-23-gsm7252ps-http-xe-dialect-design.md +0 -0
  73. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/packaging/apt-index.html +0 -0
  74. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/packaging/ci-build.sh +0 -0
  75. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/packaging/deb-version.py +0 -0
  76. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/pyproject.toml +0 -0
  77. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/__init__.py +0 -0
  78. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/_dispatch.py +0 -0
  79. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/capabilities.py +0 -0
  80. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/cli/__init__.py +0 -0
  81. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/cli/capture.py +0 -0
  82. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/cli/context.py +0 -0
  83. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/cli/format.py +0 -0
  84. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/cli/main.py +0 -0
  85. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/cli/resolve.py +0 -0
  86. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/cli/safety.py +0 -0
  87. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/cli_read.py +0 -0
  88. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/cli_write.py +0 -0
  89. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/config.py +0 -0
  90. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/errors.py +0 -0
  91. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/http_read.py +0 -0
  92. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/http_write.py +0 -0
  93. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/mcp/__init__.py +0 -0
  94. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/mcp/server.py +0 -0
  95. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/models.py +0 -0
  96. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/nsdp_read.py +0 -0
  97. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/nsdp_write.py +0 -0
  98. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/__init__.py +0 -0
  99. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/cli/__init__.py +0 -0
  100. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/cli/commands.py +0 -0
  101. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/cli/parse.py +0 -0
  102. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/http/__init__.py +0 -0
  103. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/http/crypt.py +0 -0
  104. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/http/endpoints.py +0 -0
  105. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/http/forms.py +0 -0
  106. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/http/parse.py +0 -0
  107. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/http/session.py +0 -0
  108. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/http/types.py +0 -0
  109. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/nsdp/__init__.py +0 -0
  110. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/nsdp/auth.py +0 -0
  111. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/nsdp/client.py +0 -0
  112. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/nsdp/parsers.py +0 -0
  113. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/nsdp/protocol.py +0 -0
  114. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/nsdp/types.py +0 -0
  115. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/nsdp/write.py +0 -0
  116. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/snmp/__init__.py +0 -0
  117. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/snmp/client.py +0 -0
  118. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/snmp/oids.py +0 -0
  119. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/snmp/parse.py +0 -0
  120. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/protocols/snmp/write.py +0 -0
  121. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/py.typed +0 -0
  122. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/registry.py +0 -0
  123. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/snmp_read.py +0 -0
  124. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/snmp_write.py +0 -0
  125. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/sync_api.py +0 -0
  126. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/__init__.py +0 -0
  127. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/aio/__init__.py +0 -0
  128. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/aio/nsdp_udp.py +0 -0
  129. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/aio/snmp_pysnmp.py +0 -0
  130. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/cli/__init__.py +0 -0
  131. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/cli/console.py +0 -0
  132. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/cli/session.py +0 -0
  133. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/cli/ssh.py +0 -0
  134. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/cli/telnet.py +0 -0
  135. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/http/__init__.py +0 -0
  136. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/http/client.py +0 -0
  137. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/sync/__init__.py +0 -0
  138. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/sync/nsdp_udp.py +0 -0
  139. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/transport/sync/snmp_netsnmp_cli.py +0 -0
  140. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/__init__.py +0 -0
  141. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/cli_fastpath.py +0 -0
  142. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/faces/__init__.py +0 -0
  143. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/faces/cli.py +0 -0
  144. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/faces/http.py +0 -0
  145. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/faces/mibview.py +0 -0
  146. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/faces/nsdp.py +0 -0
  147. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/faces/snmp.py +0 -0
  148. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/seed.py +0 -0
  149. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/server.py +0 -0
  150. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/state.py +0 -0
  151. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/web.py +0 -0
  152. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/web_fastpath_vlan.py +0 -0
  153. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/web_fastpath_xui.py +0 -0
  154. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/web_gs105pe.py +0 -0
  155. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/web_gs110emx.py +0 -0
  156. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/web_gs110emx_templates.py +0 -0
  157. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/web_gs728tpp.py +0 -0
  158. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/web_gsm7228ps.py +0 -0
  159. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/web_gsm7252ps.py +0 -0
  160. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/src/netgear_switch/virtual/web_m4300.py +0 -0
  161. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/capture_parity.py +0 -0
  162. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_capture.py +0 -0
  163. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_cli_integration.py +0 -0
  164. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_control_poe_port.py +0 -0
  165. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_control_vlan_ip.py +0 -0
  166. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_format.py +0 -0
  167. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_main_framework.py +0 -0
  168. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_new_commands.py +0 -0
  169. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_op_coverage.py +0 -0
  170. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_prompt_wiring.py +0 -0
  171. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_read_commands.py +0 -0
  172. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_resolve.py +0 -0
  173. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_safety.py +0 -0
  174. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/cli/test_serve.py +0 -0
  175. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/conftest.py +0 -0
  176. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/equivalence.py +0 -0
  177. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/captures/gsm7228ps.json +0 -0
  178. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/captures/gsm7252ps.json +0 -0
  179. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/captures/m4300-16x.json +0 -0
  180. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/captures/m4300-24x.json +0 -0
  181. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7228ps_environment.txt +0 -0
  182. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7228ps_lldp.txt +0 -0
  183. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7228ps_mac_table.txt +0 -0
  184. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7228ps_network.txt +0 -0
  185. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7228ps_poe.txt +0 -0
  186. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7228ps_port_all.txt +0 -0
  187. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7228ps_show_version.txt +0 -0
  188. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7228ps_vlan.txt +0 -0
  189. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7228ps_vlan_brief.txt +0 -0
  190. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7228ps_vlan_port_all.txt +0 -0
  191. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7252ps_show_environment.txt +0 -0
  192. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7252ps_show_interface_ethernet_1_0_1.txt +0 -0
  193. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7252ps_show_lldp_remote_device_all.txt +0 -0
  194. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7252ps_show_mac_addr_table.txt +0 -0
  195. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7252ps_show_network.txt +0 -0
  196. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7252ps_show_poe_port_info_all.txt +0 -0
  197. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7252ps_show_port_all.txt +0 -0
  198. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7252ps_show_version.txt +0 -0
  199. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7252ps_show_vlan_90.txt +0 -0
  200. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7252ps_show_vlan_brief.txt +0 -0
  201. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/gsm7252ps_show_vlan_port_all.txt +0 -0
  202. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_environment.txt +0 -0
  203. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_interface_ethernet_1_0_1.txt +0 -0
  204. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_ip_management.txt +0 -0
  205. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_lldp_remote_device_all.txt +0 -0
  206. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_mac_addr_table.txt +0 -0
  207. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_poe_port_info_all.txt +0 -0
  208. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_port_all.txt +0 -0
  209. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_version.txt +0 -0
  210. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_vlan.txt +0 -0
  211. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_vlan_1.txt +0 -0
  212. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_vlan_4.txt +0 -0
  213. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_vlan_5.txt +0 -0
  214. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_16x_show_vlan_port_all.txt +0 -0
  215. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_24x_show_environment.txt +0 -0
  216. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_24x_show_interface_ethernet_1_0_1.txt +0 -0
  217. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_24x_show_ip_management.txt +0 -0
  218. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_24x_show_lldp_remote_device_all.txt +0 -0
  219. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_24x_show_mac_addr_table.txt +0 -0
  220. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_24x_show_port_all.txt +0 -0
  221. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_24x_show_version.txt +0 -0
  222. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_24x_show_vlan.txt +0 -0
  223. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_24x_show_vlan_5.txt +0 -0
  224. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_24x_show_vlan_90.txt +0 -0
  225. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/cli/m4300_24x_show_vlan_port_all.txt +0 -0
  226. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs105pe_membership.html +0 -0
  227. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs105pe_portstats.html +0 -0
  228. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs105pe_pvid.html +0 -0
  229. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs105pe_status.html +0 -0
  230. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs105pe_switch_info.html +0 -0
  231. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs105pe_vlancfg.html +0 -0
  232. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs110emx_cf8021q.html +0 -0
  233. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs110emx_interface_stats.html +0 -0
  234. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs110emx_login.html +0 -0
  235. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs110emx_port_settings.html +0 -0
  236. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs110emx_pvid.html +0 -0
  237. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs110emx_redirect.html +0 -0
  238. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs110emx_sysinfo.html +0 -0
  239. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs110emx_vlanmembership.html +0 -0
  240. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs305ep_dashboard.html +0 -0
  241. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs305ep_login.html +0 -0
  242. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs305ep_membership.html +0 -0
  243. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs305ep_poestatus.html +0 -0
  244. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs305ep_portstats.html +0 -0
  245. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs305ep_pvid.html +0 -0
  246. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs305ep_vlancfg.html +0 -0
  247. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs728tpp_device_info_and_sensors.xml +0 -0
  248. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs728tpp_lldp.xml +0 -0
  249. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs728tpp_macs.xml +0 -0
  250. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs728tpp_mgmt_ip.xml +0 -0
  251. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs728tpp_poe.xml +0 -0
  252. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs728tpp_ports.xml +0 -0
  253. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs728tpp_pvids_membership.xml +0 -0
  254. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs728tpp_vlan_membership_per_vlan.xml +0 -0
  255. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gs728tpp_vlans.xml +0 -0
  256. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7228ps_basicAddressTable.html +0 -0
  257. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7228ps_ipConfiguration.html +0 -0
  258. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7228ps_lldpRemoteInventory.html +0 -0
  259. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7228ps_poeInterfaceConfiguration.html +0 -0
  260. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7228ps_portPvidConfiguration.html +0 -0
  261. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7228ps_portStatistics.html +0 -0
  262. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7228ps_portsConfiguration.html +0 -0
  263. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7228ps_sysInfo.html +0 -0
  264. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7228ps_vlanPortCfg_vlan5.html +0 -0
  265. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7228ps_vlanStatus.html +0 -0
  266. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7252ps_basicAddressTable.html +0 -0
  267. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7252ps_ipConfiguration.html +0 -0
  268. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7252ps_lldpRemoteInventory.html +0 -0
  269. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7252ps_login.html +0 -0
  270. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7252ps_poeInterfaceConfiguration.html +0 -0
  271. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7252ps_portPvidConfiguration.html +0 -0
  272. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7252ps_portStatistics.html +0 -0
  273. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7252ps_portsConfiguration.html +0 -0
  274. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7252ps_sysInfo.html +0 -0
  275. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7252ps_vlanPortCfg_vlan1.html +0 -0
  276. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7252ps_vlanPortCfg_vlan141.html +0 -0
  277. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/gsm7252ps_vlanStatus.html +0 -0
  278. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_16x_lldpRemoteInventory.html +0 -0
  279. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_16x_mgmtVlanIpv4Configuration.html +0 -0
  280. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_16x_poeInterfaceConfiguration.html +0 -0
  281. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_16x_portsConfiguration.html +0 -0
  282. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_16x_vlanportcfg_vlan4.html +0 -0
  283. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_24x_poeInterfaceConfiguration.html +0 -0
  284. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_addresstable.html +0 -0
  285. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_lldpRemoteInventory.html +0 -0
  286. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_mgmtVlanIpv4Configuration.html +0 -0
  287. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_ports.html +0 -0
  288. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_portstats.html +0 -0
  289. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_pvid.html +0 -0
  290. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_sysinfo.html +0 -0
  291. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_vlanportcfg_vlan1.html +0 -0
  292. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/http/m4300_vlanstatus.html +0 -0
  293. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/snmp/gsm7252ps_fans.txt +0 -0
  294. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/snmp/gsm7252ps_ifhighspeed.txt +0 -0
  295. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/snmp/gsm7252ps_ifoperstatus.txt +0 -0
  296. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/fixtures/snmp/gsm7252ps_psu.txt +0 -0
  297. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/http_specs.py +0 -0
  298. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/cli/test_cli_parse.py +0 -0
  299. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/http/test_crypt.py +0 -0
  300. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/http/test_endpoints.py +0 -0
  301. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/http/test_forms.py +0 -0
  302. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/http/test_parse.py +0 -0
  303. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/nsdp/test_auth.py +0 -0
  304. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/nsdp/test_parsers.py +0 -0
  305. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/nsdp/test_protocol.py +0 -0
  306. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/nsdp/test_write_frame.py +0 -0
  307. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/snmp/test_client.py +0 -0
  308. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/snmp/test_oids.py +0 -0
  309. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/snmp/test_parse_lldp_macs.py +0 -0
  310. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/snmp/test_parse_mgmt_ip.py +0 -0
  311. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/snmp/test_parse_poe_sensors.py +0 -0
  312. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/snmp/test_parse_ports.py +0 -0
  313. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/snmp/test_parse_system_info.py +0 -0
  314. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/snmp/test_parse_vlans.py +0 -0
  315. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/protocols/snmp/test_write_encode.py +0 -0
  316. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_aio_api.py +0 -0
  317. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_capabilities.py +0 -0
  318. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_cli_read.py +0 -0
  319. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_cli_vlan_write.py +0 -0
  320. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_cli_write.py +0 -0
  321. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_config.py +0 -0
  322. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_cross_backend_equivalence.py +0 -0
  323. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_deb_version.py +0 -0
  324. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_dispatch.py +0 -0
  325. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_errors.py +0 -0
  326. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_facade_equivalence.py +0 -0
  327. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_http_dispatch.py +0 -0
  328. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_http_equivalence.py +0 -0
  329. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_http_read.py +0 -0
  330. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_http_vlan_membership.py +0 -0
  331. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_http_write.py +0 -0
  332. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_http_xui_writes.py +0 -0
  333. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_import.py +0 -0
  334. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_mcp_server.py +0 -0
  335. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_models.py +0 -0
  336. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_models_snmp_read.py +0 -0
  337. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_nsdp_integration.py +0 -0
  338. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_nsdp_read.py +0 -0
  339. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_nsdp_write.py +0 -0
  340. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_public_api.py +0 -0
  341. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_quality_gates.py +0 -0
  342. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_registry.py +0 -0
  343. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_snmp_integration.py +0 -0
  344. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_snmp_read.py +0 -0
  345. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_snmp_write.py +0 -0
  346. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_sync_api.py +0 -0
  347. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_version.py +0 -0
  348. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/test_write_equivalence.py +0 -0
  349. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/transport/_fastpath_fake.py +0 -0
  350. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/transport/test_cli_console.py +0 -0
  351. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/transport/test_cli_scp_cert.py +0 -0
  352. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/transport/test_cli_telnet.py +0 -0
  353. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/transport/test_http_client.py +0 -0
  354. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/transport/test_nsdp_udp_sync.py +0 -0
  355. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/transport/test_set_transport.py +0 -0
  356. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/transport/test_snmp_netsnmp_cli.py +0 -0
  357. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/transport/test_snmp_pysnmp.py +0 -0
  358. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/transport/test_value_parity.py +0 -0
  359. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_cli_cross_backend.py +0 -0
  360. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_cli_gsm7228ps_parity.py +0 -0
  361. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_gsm7228ps_seed.py +0 -0
  362. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_m4300_seeds.py +0 -0
  363. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_mibview.py +0 -0
  364. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_mutable_state.py +0 -0
  365. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_nsdp_state.py +0 -0
  366. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_serve_daemon.py +0 -0
  367. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_snmp_write_face.py +0 -0
  368. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_state_seed.py +0 -0
  369. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_switchport_vlan_write.py +0 -0
  370. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_virtual_http_face.py +0 -0
  371. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_virtual_nsdp_face.py +0 -0
  372. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_virtual_snmp_face.py +0 -0
  373. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/tests/virtual/test_web_projection.py +0 -0
  374. {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post327}/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.post325
3
+ Version: 0.0.post327
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
@@ -341,9 +341,7 @@ class BackendModelTable(_GeneratedTable):
341
341
  rows = []
342
342
  for key in _models_with(backends):
343
343
  model = MODELS[key]
344
- reached = ", ".join(
345
- b.name for b in backends_for(model) if b in backends
346
- )
344
+ reached = ", ".join(b.name for b in backends_for(model) if b in backends)
347
345
  rows.append(
348
346
  [
349
347
  # Absolute doc path: this table is included from
@@ -382,9 +380,7 @@ class BackendOperationTable(_GeneratedTable):
382
380
  for op in (*READ_OPERATIONS, *WRITE_OPERATIONS):
383
381
  cells = []
384
382
  for key in keys:
385
- backend = next(
386
- (b for b in backends_for(key) if b in backends), None
387
- )
383
+ backend = next((b for b in backends_for(key) if b in backends), None)
388
384
  if backend is None: # pragma: no cover - filtered by _models_with
389
385
  cells.append(_NO)
390
386
  continue
@@ -399,7 +395,12 @@ class BackendOperationTable(_GeneratedTable):
399
395
  seen[reason] = index
400
396
  notes.append(reason)
401
397
  cells.append(f"{_NO} [{label}-{index}]_")
402
- rows.append([f":py:meth:`~netgear_switch.SyncSwitch.{op.name}`", *cells])
398
+ # The facade class is documented under its defining module, so a
399
+ # `netgear_switch.SyncSwitch.x` target does not resolve and would
400
+ # render as plain text rather than a link.
401
+ rows.append(
402
+ [f":py:meth:`~netgear_switch.sync_api.SyncSwitch.{op.name}`", *cells]
403
+ )
403
404
  table = _list_table("", ["Operation", *keys], rows)
404
405
  if not notes:
405
406
  return table
@@ -445,9 +446,7 @@ class ModelFacts(_GeneratedTable):
445
446
  ]
446
447
  )
447
448
  if aliases:
448
- rows.append(
449
- ["Aliases", ", ".join(f"``{a}``" for a in aliases)]
450
- )
449
+ rows.append(["Aliases", ", ".join(f"``{a}``" for a in aliases)])
451
450
  rows.append(
452
451
  [
453
452
  "MAC/FDB table",
@@ -492,6 +491,71 @@ class ModelPhoto(_GeneratedTable):
492
491
  MISSING_PHOTOS: set[str] = set()
493
492
 
494
493
 
494
+ class ModelDiagram(_GeneratedTable):
495
+ """A schematic port map for one model, drawn from the registry.
496
+
497
+ Not a photograph and not a faceplate: it shows the ports *as this library
498
+ addresses them*, which is the thing a caller actually needs when deciding
499
+ what to pass as ``port=``. Generated from ``port_count`` and
500
+ ``poe_port_count``, so it cannot drift from the registry -- and so it never
501
+ asserts a physical arrangement nobody measured.
502
+ """
503
+
504
+ required_arguments = 1
505
+
506
+ _COLS = 26
507
+ _BOX = 26
508
+ _GAP = 4
509
+
510
+ def body(self) -> str:
511
+ model = get_model(self.arguments[0])
512
+ total, poe = model.port_count, model.poe_port_count
513
+ step = self._BOX + self._GAP
514
+ rows = (total + self._COLS - 1) // self._COLS
515
+ width = min(total, self._COLS) * step + self._GAP
516
+ height = rows * step + self._GAP + 22
517
+
518
+ parts = [
519
+ f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {width} {height}" '
520
+ f'role="img" aria-label="Port map: {total} ports, {poe} with PoE" '
521
+ 'style="max-width:100%;height:auto">'
522
+ ]
523
+ for index in range(total):
524
+ port = index + 1
525
+ col, row = index % self._COLS, index // self._COLS
526
+ x = self._GAP + col * step
527
+ y = self._GAP + row * step
528
+ # PoE ports come first on every model in this registry; anything
529
+ # beyond that count is drawn as a plain (usually uplink) port.
530
+ fill = "#2b6cb0" if port <= poe else "#a0aec0"
531
+ parts.append(
532
+ f'<rect x="{x}" y="{y}" width="{self._BOX}" height="{self._BOX}" '
533
+ f'rx="3" fill="{fill}"/>'
534
+ f'<text x="{x + self._BOX / 2}" y="{y + self._BOX / 2 + 4}" '
535
+ 'font-size="10" text-anchor="middle" fill="#fff" '
536
+ f'font-family="monospace">{port}</text>'
537
+ )
538
+ legend_y = rows * step + self._GAP + 14
539
+ parts.append(
540
+ f'<rect x="4" y="{legend_y - 9}" width="11" height="11" rx="2" '
541
+ 'fill="#2b6cb0"/>'
542
+ f'<text x="20" y="{legend_y}" font-size="11" fill="currentColor">'
543
+ f"PoE ({poe})</text>"
544
+ f'<rect x="86" y="{legend_y - 9}" width="11" height="11" rx="2" '
545
+ 'fill="#a0aec0"/>'
546
+ f'<text x="102" y="{legend_y}" font-size="11" fill="currentColor">'
547
+ f"no PoE ({total - poe})</text>"
548
+ )
549
+ parts.append("</svg>")
550
+ svg = "".join(parts)
551
+ return (
552
+ ".. raw:: html\n\n"
553
+ f' <figure class="ngsw-port-map">{svg}'
554
+ "<figcaption>Port map as the library addresses these ports — "
555
+ "schematic, not a faceplate layout.</figcaption></figure>\n"
556
+ )
557
+
558
+
495
559
  class UnverifiedNote(_GeneratedTable):
496
560
  """Name the models the tables leave out, and say why."""
497
561
 
@@ -538,6 +602,7 @@ def setup(app: Sphinx) -> dict[str, Any]:
538
602
  app.add_directive("ngsw-model-support", ModelSupportTable)
539
603
  app.add_directive("ngsw-model-facts", ModelFacts)
540
604
  app.add_directive("ngsw-model-photo", ModelPhoto)
605
+ app.add_directive("ngsw-model-diagram", ModelDiagram)
541
606
  app.add_directive("ngsw-backend-models", BackendModelTable)
542
607
  app.add_directive("ngsw-backend-operations", BackendOperationTable)
543
608
  app.add_directive("ngsw-support-gaps", SupportGaps)
@@ -25,3 +25,14 @@ a.repofile tt {
25
25
  text-decoration: underline;
26
26
  text-decoration-style: dotted;
27
27
  }
28
+
29
+ /* Generated port maps (docs/_ext/support_tables.py's ngsw-model-diagram). */
30
+ figure.ngsw-port-map {
31
+ margin: 1rem 0 1.5rem;
32
+ text-align: center;
33
+ }
34
+ figure.ngsw-port-map figcaption {
35
+ font-size: 0.85em;
36
+ opacity: 0.75;
37
+ margin-top: 0.4rem;
38
+ }
@@ -17,7 +17,7 @@ Switch and credential resolution
17
17
  --------------------------------
18
18
 
19
19
  The shared path the CLI *and* the MCP server both use to turn arguments,
20
- environment variables and an inventory into a ready `SyncSwitch`.
20
+ environment variables and an inventory into a ready :py:obj:`~netgear_switch.sync_api.SyncSwitch`.
21
21
 
22
22
  .. automodule:: netgear_switch.cli.resolve
23
23
 
@@ -1,7 +1,7 @@
1
1
  Facades
2
2
  =======
3
3
 
4
- `SyncSwitch` and `AsyncSwitch` are the public entry points. They expose the same
4
+ :py:obj:`~netgear_switch.sync_api.SyncSwitch` and :py:obj:`~netgear_switch.aio_api.AsyncSwitch` are the public entry points. They expose the same
5
5
  operations with the same arguments, and both resolve exactly one backend per
6
6
  call — see :doc:`../guide/concepts`.
7
7
 
@@ -5,7 +5,7 @@ Complete reference for every module in the ``netgear_switch`` package,
5
5
  generated from the source.
6
6
 
7
7
  Most callers need only :doc:`core` (the data model, the registry, the
8
- capability oracle) and :doc:`facades` (`SyncSwitch` and `AsyncSwitch`).
8
+ capability oracle) and :doc:`facades` (:py:obj:`~netgear_switch.sync_api.SyncSwitch` and :py:obj:`~netgear_switch.aio_api.AsyncSwitch`).
9
9
  The rest is there for anyone reading the source, extending a backend, or
10
10
  building on the protocol layer directly.
11
11
 
@@ -75,8 +75,49 @@ exclude_patterns = [
75
75
 
76
76
  # Single backticks mean "a Python object", which is what most inline references
77
77
  # in this project are.
78
- default_role = "py:obj"
79
- nitpicky = False
78
+ # Single backticks mean "literal", not "cross-reference". The library's
79
+ # docstrings use them loosely for prose and shell fragments (`snmpget`,
80
+ # `apt-get install -y snmp`, `type: ignore`), which a py:obj default role turns
81
+ # into a flood of unresolvable references under nitpicky mode. Cross-references
82
+ # in this documentation are always written with an explicit role, so nothing is
83
+ # lost -- and filelinks still turns any literal naming a repository file into a
84
+ # link to that file.
85
+ default_role = "literal"
86
+
87
+ # Every cross-reference must resolve, or the build fails. This is what keeps the
88
+ # documentation actually hyperlinked: an unresolved `py:obj` renders as plain
89
+ # text, so without this a whole page of API names can silently stop being links
90
+ # -- which is exactly what happened when references were written as
91
+ # `netgear_switch.SyncSwitch` (autodoc documents the class under its DEFINING
92
+ # module, netgear_switch.sync_api, so the short path never resolved).
93
+ nitpicky = True
94
+ nitpick_ignore = [
95
+ # Base classes autodoc emits for our enums. They resolve through
96
+ # intersphinx, so these only matter for an offline build.
97
+ ("py:class", "enum.Enum"),
98
+ ("py:class", "enum.IntEnum"),
99
+ ]
100
+
101
+ # Napoleon splits a docstring "Returns:"/"Attributes:" type on its first comma,
102
+ # so a generic like ``tuple[NsdpPortStatus, ...]`` arrives as the fragment
103
+ # ``'tuple[NsdpPortStatus``. These are mis-parses of a real annotation, not
104
+ # broken links; the signatures autodoc renders from the actual type hints are
105
+ # correct. Ignored by shape so a genuinely missing class still fails the build.
106
+ nitpick_ignore_regex = [
107
+ ("py:class", r"^'?(?:tuple|list|dict|Mapping|Sequence|frozenset)\[.*"),
108
+ # A prose Attributes: entry whose type slot holds a sentence.
109
+ ("py:class", r"^The [A-Z].*"),
110
+ ]
111
+
112
+ if os.environ.get("NGSW_DOCS_OFFLINE"):
113
+ # Standard-library targets that only resolve when intersphinx can fetch its
114
+ # inventory. Online (CI and Read the Docs) they link properly and stay
115
+ # strict; offline they would be noise.
116
+ nitpick_ignore += [
117
+ ("py:class", "argparse.ArgumentParser"),
118
+ ("py:func", "asyncio.to_thread"),
119
+ ("py:func", "importlib.import_module"),
120
+ ]
80
121
  maximum_signature_line_length = 88
81
122
 
82
123
  # -- Autodoc ------------------------------------------------------------------
@@ -33,7 +33,7 @@ hardware, no network. Coverage is enforced at 90%.
33
33
  - That every backend of a model reports the same thing — the parity
34
34
  guarantee, checked rather than asserted in prose.
35
35
  * - ``tests/test_facade_equivalence.py``
36
- - That `SyncSwitch` and `AsyncSwitch` stay in step.
36
+ - That :py:obj:`~netgear_switch.sync_api.SyncSwitch` and :py:obj:`~netgear_switch.aio_api.AsyncSwitch` stay in step.
37
37
  * - ``tests/test_capabilities.py``
38
38
  - That the support tables in these docs match what the code actually does,
39
39
  by driving every operation for real.
@@ -96,7 +96,7 @@ The rules
96
96
 
97
97
  * **Never declare something unsupported to finish a task.** If you cannot
98
98
  implement it, say so plainly — naming the model, backend and operation — and
99
- leave behind no `UnsupportedCapabilityError` that lacks captured device output
99
+ leave behind no :py:obj:`~netgear_switch.errors.UnsupportedCapabilityError` that lacks captured device output
100
100
  as proof. An honest "not done, here's why" is wanted; a false "the hardware
101
101
  can't" is not.
102
102
  * **Implement across all backends and all models,** or state precisely which
@@ -65,7 +65,7 @@ The faces
65
65
  * - ``faces/cli.py``
66
66
  - nothing
67
67
  - In-process: implements the ``CliSession`` protocol directly, so no SSH
68
- or telnet server is needed. Reached via `VirtualSwitch.cli_session`.
68
+ or telnet server is needed. Reached via :py:obj:`~netgear_switch.virtual.server.VirtualSwitch.cli_session`.
69
69
 
70
70
  ``faces/mibview.py`` deserves a note. It builds a **sorted** OID view from the
71
71
  state so GETNEXT and GETBULK have real lexicographic-ordering semantics rather
@@ -93,8 +93,8 @@ From a real switch to a seed
93
93
 
94
94
  ngsw --switch core capture tmp/core.json
95
95
 
96
- `ngsw capture <cli.capture>` records the switch's full state via
97
- `SyncSwitch.snapshot`, and — given live access and a raw-walk callable — the
96
+ :doc:`ngsw capture <../cli>` records the switch's full state via
97
+ :py:obj:`~netgear_switch.sync_api.SyncSwitch.snapshot`, and — given live access and a raw-walk callable — the
98
98
  reference ``snmpbulkwalk`` output alongside it. The result is a JSON file used
99
99
  **for reference** when hand-authoring a seed. It is deliberately not loaded
100
100
  directly by the mock.
@@ -186,7 +186,8 @@ Where things live
186
186
  * - ``src/netgear_switch/virtual/seed.py``
187
187
  - One seed builder per model.
188
188
  * - ``src/netgear_switch/virtual/server.py``
189
- - ``VirtualSwitch``, the seed map, and ``serve_forever``.
189
+ - :py:class:`~netgear_switch.virtual.server.VirtualSwitch`, the seed map,
190
+ and :py:func:`~netgear_switch.virtual.server.serve_forever`.
190
191
  * - ``src/netgear_switch/virtual/faces/``
191
192
  - The protocol faces.
192
193
  * - ``tests/fixtures/captures/``
@@ -194,4 +195,5 @@ Where things live
194
195
  * - ``tests/virtual/``
195
196
  - Tests of the mock itself.
196
197
  * - ``tests/conftest.py``
197
- - The per-model ``VirtualSwitch`` fixtures this project uses.
198
+ - The per-model :py:class:`~netgear_switch.virtual.server.VirtualSwitch`
199
+ fixtures this project uses.
@@ -141,7 +141,7 @@ The FASTPATH CLI
141
141
  The CLI face is deliberately **in-process**: it implements the ``CliSession``
142
142
  protocol rather than binding an SSH or telnet listener, so there is no key
143
143
  exchange or terminal emulation to fight. It is reached through
144
- `VirtualSwitch.cli_session`, not over a socket, and so is not exposed by
144
+ :py:obj:`~netgear_switch.virtual.server.VirtualSwitch.cli_session`, not over a socket, and so is not exposed by
145
145
  ``ngsw serve``. See :doc:`testing`.
146
146
 
147
147
  This library against a mock
@@ -37,7 +37,7 @@ A pytest fixture
37
37
  finally:
38
38
  mock.stop()
39
39
 
40
- `VirtualSwitch` is also a context manager, which is usually enough:
40
+ :py:obj:`~netgear_switch.virtual.server.VirtualSwitch` is also a context manager, which is usually enough:
41
41
 
42
42
  .. code-block:: python
43
43
 
@@ -127,7 +127,7 @@ Every backend takes an injected client:
127
127
  async: the same arguments to ``AsyncHttpClient``.
128
128
  * - CLI
129
129
  - ``cli_client=mock.cli_session()`` — **synchronous only**. The CLI
130
- transports block, so :py:class:`~netgear_switch.AsyncSwitch` has no CLI
130
+ transports block, so :py:class:`~netgear_switch.aio_api.AsyncSwitch` has no CLI
131
131
  backend and takes no ``cli_client``.
132
132
 
133
133
  All four at once
@@ -136,31 +136,66 @@ All four at once
136
136
  One mock, one facade, three protocols — which is what makes cross-backend
137
137
  behaviour testable without hardware:
138
138
 
139
- .. code-block:: python
139
+ .. tab-set::
140
140
 
141
- from netgear_switch import Backend, SyncSwitch, get_model
142
- from netgear_switch.protocols.http.endpoints import http_spec
143
- from netgear_switch.transport.http.client import HttpClient
144
- from netgear_switch.transport.sync.snmp_netsnmp_cli import NetsnmpCliClient
145
- from netgear_switch.virtual.server import VirtualSwitch
141
+ .. tab-item:: Sync
142
+ :sync: sync
146
143
 
147
- model = get_model("gsm7252ps")
148
- with VirtualSwitch(model="gsm7252ps") as mock:
149
- switch = SyncSwitch(
150
- model,
151
- host=mock.host,
152
- snmp_client=NetsnmpCliClient(f"{mock.host}:{mock.port}", "public"),
153
- http_client=HttpClient(
154
- f"{mock.host}:{mock.http_port}", "password", http_spec(model)
155
- ),
156
- cli_client=mock.cli_session(),
157
- )
158
- snmp = switch.get_vlans(backend=Backend.SNMP)
159
- http = switch.get_vlans(backend=Backend.HTTP)
160
- cli = switch.get_vlans(backend=Backend.SSH)
144
+ .. code-block:: python
145
+
146
+ from netgear_switch import Backend, SyncSwitch, get_model
147
+ from netgear_switch.protocols.http.endpoints import http_spec
148
+ from netgear_switch.transport.http.client import HttpClient
149
+ from netgear_switch.transport.sync.snmp_netsnmp_cli import NetsnmpCliClient
150
+ from netgear_switch.virtual.server import VirtualSwitch
151
+
152
+ model = get_model("gsm7252ps")
153
+ with VirtualSwitch(model="gsm7252ps") as mock:
154
+ switch = SyncSwitch(
155
+ model,
156
+ host=mock.host,
157
+ snmp_client=NetsnmpCliClient(f"{mock.host}:{mock.port}", "public"),
158
+ http_client=HttpClient(
159
+ f"{mock.host}:{mock.http_port}", "password", http_spec(model)
160
+ ),
161
+ cli_client=mock.cli_session(),
162
+ )
163
+ snmp = switch.get_vlans(backend=Backend.SNMP)
164
+ http = switch.get_vlans(backend=Backend.HTTP)
165
+ cli = switch.get_vlans(backend=Backend.SSH)
166
+
167
+ assert {v.vlan_id for v in snmp} == {v.vlan_id for v in http} \
168
+ == {v.vlan_id for v in cli}
169
+
170
+ .. tab-item:: Async
171
+ :sync: async
172
+
173
+ .. code-block:: python
174
+
175
+ from netgear_switch import AsyncSwitch, Backend, get_model
176
+ from netgear_switch.protocols.http.endpoints import http_spec
177
+ from netgear_switch.transport.aio.snmp_pysnmp import PysnmpClient
178
+ from netgear_switch.transport.http.client import AsyncHttpClient
179
+ from netgear_switch.virtual.server import VirtualSwitch
161
180
 
162
- assert {v.vlan_id for v in snmp} == {v.vlan_id for v in http} \
163
- == {v.vlan_id for v in cli}
181
+ model = get_model("gsm7252ps")
182
+ with VirtualSwitch(model="gsm7252ps") as mock:
183
+ switch = AsyncSwitch(
184
+ model,
185
+ host=mock.host,
186
+ snmp_client=PysnmpClient(mock.host, "public", port=mock.port),
187
+ http_client=AsyncHttpClient(
188
+ f"{mock.host}:{mock.http_port}", "password", http_spec(model)
189
+ ),
190
+ # No cli_client: the async facade has no CLI backend.
191
+ )
192
+ try:
193
+ snmp = await switch.get_vlans(backend=Backend.SNMP)
194
+ http = await switch.get_vlans(backend=Backend.HTTP)
195
+
196
+ assert {v.vlan_id for v in snmp} == {v.vlan_id for v in http}
197
+ finally:
198
+ await switch.aclose()
164
199
 
165
200
  .. code-block:: text
166
201
 
@@ -197,24 +232,53 @@ Testing that your code handles refusals
197
232
  The most valuable thing a faithful mock gives you is the *failure* paths. The
198
233
  mock refuses exactly what the hardware refuses, with the same message:
199
234
 
200
- .. code-block:: python
235
+ .. tab-set::
201
236
 
202
- from netgear_switch import SyncSwitch, UnsupportedCapabilityError, get_model
203
- from netgear_switch.transport.sync.nsdp_udp import UdpNsdpClient
204
- from netgear_switch.virtual.server import VirtualSwitch
237
+ .. tab-item:: Sync
238
+ :sync: sync
205
239
 
206
- with VirtualSwitch(model="gs110emx") as mock:
207
- switch = SyncSwitch(
208
- get_model("gs110emx"),
209
- host=mock.host,
210
- nsdp_client=UdpNsdpClient(
211
- mock.host, client_port=0, server_port=mock.port, timeout=2.0
212
- ),
213
- )
214
- try:
215
- switch.get_poe()
216
- except UnsupportedCapabilityError as exc:
217
- print(exc)
240
+ .. code-block:: python
241
+
242
+ from netgear_switch import SyncSwitch, UnsupportedCapabilityError, get_model
243
+ from netgear_switch.transport.sync.nsdp_udp import UdpNsdpClient
244
+ from netgear_switch.virtual.server import VirtualSwitch
245
+
246
+ with VirtualSwitch(model="gs110emx") as mock:
247
+ switch = SyncSwitch(
248
+ get_model("gs110emx"),
249
+ host=mock.host,
250
+ nsdp_client=UdpNsdpClient(
251
+ mock.host, client_port=0, server_port=mock.port, timeout=2.0
252
+ ),
253
+ )
254
+ try:
255
+ switch.get_poe()
256
+ except UnsupportedCapabilityError as exc:
257
+ print(exc)
258
+
259
+ .. tab-item:: Async
260
+ :sync: async
261
+
262
+ .. code-block:: python
263
+
264
+ from netgear_switch import AsyncSwitch, UnsupportedCapabilityError, get_model
265
+ from netgear_switch.transport.aio.nsdp_udp import AsyncUdpNsdpClient
266
+ from netgear_switch.virtual.server import VirtualSwitch
267
+
268
+ with VirtualSwitch(model="gs110emx") as mock:
269
+ switch = AsyncSwitch(
270
+ get_model("gs110emx"),
271
+ host=mock.host,
272
+ nsdp_client=AsyncUdpNsdpClient(
273
+ mock.host, client_port=0, server_port=mock.port, timeout=2.0
274
+ ),
275
+ )
276
+ try:
277
+ await switch.get_poe()
278
+ except UnsupportedCapabilityError as exc:
279
+ print(exc)
280
+ finally:
281
+ await switch.aclose()
218
282
 
219
283
  .. code-block:: text
220
284
 
@@ -272,7 +336,7 @@ configuration:
272
336
  Crafting a scenario
273
337
  -------------------
274
338
 
275
- `VirtualSwitch.state` is an ordinary mutable dataclass. Edit it to produce the
339
+ ``VirtualSwitch.state`` is an ordinary mutable dataclass. Edit it to produce the
276
340
  condition you want to test — a dead link, a PoE fault, a full MAC table:
277
341
 
278
342
  .. code-block:: python
@@ -10,7 +10,7 @@ Models
10
10
  A switch model is a frozen `netgear_switch.registry.SwitchModel` record: its
11
11
  key, display name, class, port and PoE-port counts, the backends it exposes, its
12
12
  SNMP vendor OID subtree, and a few per-model protocol dialect flags. The whole
13
- registry lives in ``src/netgear_switch/registry.py``, and `get_model` resolves a
13
+ registry lives in ``src/netgear_switch/registry.py``, and :py:obj:`~netgear_switch.registry.get_model` resolves a
14
14
  key (or an alias, such as ``s3300`` for ``gsm7228ps``) to the record.
15
15
 
16
16
  Models fall into three classes, which is what decides the protocols available:
@@ -83,11 +83,11 @@ Dispatch: exactly one backend, every time
83
83
  await switch.get_vlans(backend=Backend.HTTP) # exactly HTTP, or an error
84
84
 
85
85
  When you **name** a backend, that backend runs. If the model does not have it,
86
- you get `UnsupportedCapabilityError` immediately. If it has it but cannot serve
87
- that operation, you get `UnsupportedCapabilityError` naming the backend you
86
+ you get :py:obj:`~netgear_switch.errors.UnsupportedCapabilityError` immediately. If it has it but cannot serve
87
+ that operation, you get :py:obj:`~netgear_switch.errors.UnsupportedCapabilityError` naming the backend you
88
88
  asked for.
89
89
 
90
- When you **do not** name one, `SyncSwitch.resolve_backend` picks the first
90
+ When you **do not** name one, :py:obj:`~netgear_switch.sync_api.SyncSwitch.resolve_backend` picks the first
91
91
  backend the model declares, in the fixed order **SNMP → NSDP → HTTP → SSH →
92
92
  TELNET → CONSOLE**. The choice depends only on the model, never on the
93
93
  operation: the facade does not probe one backend, catch its refusal, and try
@@ -105,7 +105,8 @@ names the other backends you could pass:
105
105
 
106
106
  **The library will never answer over a protocol you did not get.** This was
107
107
  not always true, and the cost of the old behaviour is why the rule is
108
- absolute. ``SyncSwitch`` used to loop over SNMP → NSDP → HTTP, silently
108
+ absolute. :py:class:`~netgear_switch.sync_api.SyncSwitch` used to loop over
109
+ SNMP → NSDP → HTTP, silently
109
110
  returning the next backend's answer when one raised. That hid a real defect
110
111
  for months — ``HttpReader.get_vlans`` returned no untagged ports at all on
111
112
  the managed switches, and nobody noticed because SNMP quietly answered
@@ -149,7 +150,7 @@ Verification status
149
150
  This project distinguishes what has been *measured* from what has been
150
151
  *assumed*, and the distinction is visible in the API.
151
152
 
152
- `SwitchModel.verified`
153
+ :py:attr:`~netgear_switch.registry.SwitchModel.verified`
153
154
  ``False`` marks a model registered from a specification sheet, with no
154
155
  device of that kind ever reachable from this project. Such a model is
155
156
  **excluded from every support table** — see :doc:`../models/index` —
@@ -167,7 +168,7 @@ This project distinguishes what has been *measured* from what has been
167
168
  Errors
168
169
  ------
169
170
 
170
- All errors derive from `NetgearSwitchError`. The distinctions that matter:
171
+ All errors derive from :py:obj:`~netgear_switch.errors.NetgearSwitchError`. The distinctions that matter:
171
172
 
172
173
  .. list-table::
173
174
  :header-rows: 1
@@ -175,36 +176,36 @@ All errors derive from `NetgearSwitchError`. The distinctions that matter:
175
176
 
176
177
  * - Error
177
178
  - Means
178
- * - `UnsupportedCapabilityError`
179
+ * - :py:obj:`~netgear_switch.errors.UnsupportedCapabilityError`
179
180
  - This backend genuinely cannot do this, for this model. Never "not
180
181
  implemented yet" — a missing implementation is a bug to fix, not a
181
182
  device limitation to document.
182
- * - `CredentialError`
183
+ * - :py:obj:`~netgear_switch.errors.CredentialError`
183
184
  - A credential is missing or wrong. Note that an SNMP agent **silently
184
185
  drops** an unauthorised request, so a wrong write community looks exactly
185
186
  like an unreachable host.
186
- * - `WriteVerificationError`
187
+ * - :py:obj:`~netgear_switch.errors.WriteVerificationError`
187
188
  - The write was sent and accepted, but reading back did not show the
188
189
  intended value.
189
- * - `ProtectedPortError`
190
+ * - :py:obj:`~netgear_switch.errors.ProtectedPortError`
190
191
  - The port is in this switch's ``protected_ports`` set. Pass ``force=True``
191
192
  to override.
192
- * - `HttpAuthError`, `HttpUnexpectedPageError`
193
+ * - :py:obj:`~netgear_switch.errors.HttpAuthError`, :py:obj:`~netgear_switch.errors.HttpUnexpectedPageError`
193
194
  - Web-UI login failed, or a page did not look like what the model's dialect
194
195
  expects (usually a session that expired).
195
- * - `CliCommandError`
196
+ * - :py:obj:`~netgear_switch.errors.CliCommandError`
196
197
  - The switch's CLI rejected a command; the message carries what it said.
197
198
 
198
199
  `NotImplementedError` appears in exactly one place — certificate upload on a
199
200
  model whose real mechanism is known but not wired to that backend. It is
200
- deliberately *not* `UnsupportedCapabilityError`, because the hardware can do it;
201
+ deliberately *not* :py:obj:`~netgear_switch.errors.UnsupportedCapabilityError`, because the hardware can do it;
201
202
  see :doc:`../models/support`.
202
203
 
203
204
  Synchronous and asynchronous
204
205
  ----------------------------
205
206
 
206
- :py:class:`~netgear_switch.SyncSwitch` and
207
- :py:class:`~netgear_switch.AsyncSwitch` expose the same operations with the same
207
+ :py:class:`~netgear_switch.sync_api.SyncSwitch` and
208
+ :py:class:`~netgear_switch.aio_api.AsyncSwitch` expose the same operations with the same
208
209
  arguments and the same semantics. They share the model registry, the parsers and
209
210
  the backend-resolution seam in ``src/netgear_switch/_dispatch.py``; only the
210
211
  transports differ. ``tests/test_facade_equivalence.py`` asserts they stay in
@@ -214,18 +215,18 @@ step.
214
215
 
215
216
  **One backend is synchronous-only: the CLI.** All three CLI transports —
216
217
  SSH, telnet and the serial console — are blocking, and none has an async
217
- twin, so :py:class:`~netgear_switch.AsyncSwitch` has no CLI backend at all.
218
+ twin, so :py:class:`~netgear_switch.aio_api.AsyncSwitch` has no CLI backend at all.
218
219
  Asking for one raises rather than quietly blocking the event loop::
219
220
 
220
221
  UnsupportedCapabilityError: model 'gsm7252ps' CLI reads are not available
221
222
  via the async facade (CLI is synchronous ...)
222
223
 
223
224
  That also rules out
224
- :py:meth:`~netgear_switch.SyncSwitch.upload_certificate_scp` on the async
225
+ :py:meth:`~netgear_switch.sync_api.SyncSwitch.upload_certificate_scp` on the async
225
226
  facade, since the operation is CLI-based by nature. Use
226
- :py:class:`~netgear_switch.SyncSwitch` for those, or wrap the call in
227
+ :py:class:`~netgear_switch.sync_api.SyncSwitch` for those, or wrap the call in
227
228
  :py:func:`asyncio.to_thread`.
228
229
 
229
230
  **The support tables in** :doc:`../models/support` **describe the
230
231
  synchronous facade.** Every SNMP, NSDP and HTTP entry holds for both; the CLI
231
- columns apply to :py:class:`~netgear_switch.SyncSwitch` only.
232
+ columns apply to :py:class:`~netgear_switch.sync_api.SyncSwitch` only.