python-netgear-switch-library 0.0.post404__tar.gz → 0.1.post2__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 (428) hide show
  1. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/.github/workflows/ci.yml +4 -1
  2. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/.github/workflows/deb.yml +23 -8
  3. python_netgear_switch_library-0.1.post2/.github/workflows/publish-pypi.yml +71 -0
  4. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/PKG-INFO +4 -4
  5. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/README.md +3 -3
  6. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/RELEASING.md +29 -9
  7. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/guide/installation.rst +8 -7
  8. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/packaging/apt-index.html +4 -4
  9. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/pyproject.toml +10 -5
  10. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/_version.py +2 -2
  11. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/http_write.py +3 -3
  12. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/http/goahead.py +6 -2
  13. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/http/parse.py +1 -1
  14. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_deb_version.py +40 -11
  15. python_netgear_switch_library-0.0.post404/.github/workflows/publish-pypi.yml +0 -52
  16. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/.gitignore +0 -0
  17. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/.readthedocs.yaml +0 -0
  18. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/CLAUDE.md +0 -0
  19. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/LICENSE +0 -0
  20. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/debian/changelog +0 -0
  21. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/debian/control +0 -0
  22. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/debian/copyright +0 -0
  23. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/debian/rules +0 -0
  24. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/debian/source/format +0 -0
  25. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/Makefile +0 -0
  26. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/_ext/filelinks.py +0 -0
  27. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/_ext/support_tables.py +0 -0
  28. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/_static/models/gs105pe.png +0 -0
  29. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/_static/models/gs110emx.png +0 -0
  30. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/_static/models/gs305ep.png +0 -0
  31. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/_static/models/gs728tpp.png +0 -0
  32. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/_static/models/gsm7228ps.jpg +0 -0
  33. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/_static/models/gsm7252ps.jpg +0 -0
  34. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/_static/models/m4300-16x.png +0 -0
  35. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/_static/models/m4300-24x.png +0 -0
  36. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/_static/ngsw.css +0 -0
  37. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/api/cli.rst +0 -0
  38. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/api/core.rst +0 -0
  39. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/api/facades.rst +0 -0
  40. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/api/index.rst +0 -0
  41. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/api/mcp.rst +0 -0
  42. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/api/operations.rst +0 -0
  43. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/api/protocols.rst +0 -0
  44. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/api/transport.rst +0 -0
  45. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/api/virtual.rst +0 -0
  46. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/cli.rst +0 -0
  47. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/conf.py +0 -0
  48. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/development.rst +0 -0
  49. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/fake/index.rst +0 -0
  50. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/fake/internals.rst +0 -0
  51. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/fake/serving.rst +0 -0
  52. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/fake/testing.rst +0 -0
  53. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/guide/concepts.rst +0 -0
  54. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/guide/configuration.rst +0 -0
  55. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/guide/principles.rst +0 -0
  56. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/guide/quickstart.rst +0 -0
  57. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/guide/reading.rst +0 -0
  58. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/guide/writing.rst +0 -0
  59. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/index.rst +0 -0
  60. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/mcp.rst +0 -0
  61. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/models/gs105pe.rst +0 -0
  62. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/models/gs110emx.rst +0 -0
  63. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/models/gs305ep.rst +0 -0
  64. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/models/gs728tpp.rst +0 -0
  65. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/models/gsm7228ps.rst +0 -0
  66. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/models/gsm7252ps.rst +0 -0
  67. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/models/index.rst +0 -0
  68. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/models/m4300-16x.rst +0 -0
  69. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/models/m4300-24x.rst +0 -0
  70. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/models/support.rst +0 -0
  71. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/protocols/cli.rst +0 -0
  72. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/protocols/http/cheetah-form.rst +0 -0
  73. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/protocols/http/cheetah-v1.rst +0 -0
  74. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/protocols/http/gambit.rst +0 -0
  75. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/protocols/http/merge-hash-cgi.rst +0 -0
  76. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/protocols/http/xml-api.rst +0 -0
  77. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/protocols/http.rst +0 -0
  78. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/protocols/index.rst +0 -0
  79. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/protocols/nsdp.rst +0 -0
  80. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/protocols/snmp.rst +0 -0
  81. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/plans/2026-07-15-foundation.md +0 -0
  82. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/plans/2026-07-17-slice-02-snmp-read-core.md +0 -0
  83. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/plans/2026-07-17-slice-03-read-apis.md +0 -0
  84. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/plans/2026-07-18-slice-04-snmp-write.md +0 -0
  85. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/plans/2026-07-18-slice-05-nsdp.md +0 -0
  86. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/plans/2026-07-18-slice-06-http.md +0 -0
  87. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/plans/2026-07-18-slice-07-cli.md +0 -0
  88. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/plans/2026-07-18-slice-08-packaging-ci.md +0 -0
  89. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/plans/2026-07-23-gsm7252ps-http-xe-dialect.md +0 -0
  90. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/specs/2026-07-15-netgear-control-library-design.md +0 -0
  91. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/specs/2026-07-23-gsm7252ps-http-xe-dialect-design.md +0 -0
  92. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/specs/2026-08-02-gs728tpp-poe-vlan-live.md +0 -0
  93. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/specs/2026-08-02-snmp-surface-findings.md +0 -0
  94. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/docs/superpowers/specs/2026-08-03-snmp-vendor-oid-sweep.md +0 -0
  95. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/packaging/ci-build.sh +0 -0
  96. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/packaging/deb-version.py +0 -0
  97. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/__init__.py +0 -0
  98. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/_dispatch.py +0 -0
  99. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/aio_api.py +0 -0
  100. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/capabilities.py +0 -0
  101. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/cli/__init__.py +0 -0
  102. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/cli/capture.py +0 -0
  103. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/cli/context.py +0 -0
  104. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/cli/format.py +0 -0
  105. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/cli/main.py +0 -0
  106. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/cli/resolve.py +0 -0
  107. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/cli/safety.py +0 -0
  108. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/cli_read.py +0 -0
  109. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/cli_write.py +0 -0
  110. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/config.py +0 -0
  111. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/errors.py +0 -0
  112. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/http_read.py +0 -0
  113. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/mcp/__init__.py +0 -0
  114. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/mcp/server.py +0 -0
  115. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/models.py +0 -0
  116. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/nsdp_read.py +0 -0
  117. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/nsdp_write.py +0 -0
  118. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/__init__.py +0 -0
  119. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/cli/__init__.py +0 -0
  120. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/cli/commands.py +0 -0
  121. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/cli/parse.py +0 -0
  122. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/http/__init__.py +0 -0
  123. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/http/crypt.py +0 -0
  124. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/http/endpoints.py +0 -0
  125. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/http/forms.py +0 -0
  126. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/http/session.py +0 -0
  127. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/http/types.py +0 -0
  128. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/nsdp/__init__.py +0 -0
  129. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/nsdp/auth.py +0 -0
  130. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/nsdp/client.py +0 -0
  131. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/nsdp/parsers.py +0 -0
  132. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/nsdp/protocol.py +0 -0
  133. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/nsdp/types.py +0 -0
  134. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/nsdp/write.py +0 -0
  135. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/snmp/__init__.py +0 -0
  136. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/snmp/client.py +0 -0
  137. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/snmp/oids.py +0 -0
  138. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/snmp/parse.py +0 -0
  139. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/protocols/snmp/write.py +0 -0
  140. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/py.typed +0 -0
  141. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/registry.py +0 -0
  142. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/snmp_read.py +0 -0
  143. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/snmp_write.py +0 -0
  144. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/sync_api.py +0 -0
  145. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/__init__.py +0 -0
  146. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/aio/__init__.py +0 -0
  147. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/aio/nsdp_udp.py +0 -0
  148. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/aio/snmp_pysnmp.py +0 -0
  149. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/cli/__init__.py +0 -0
  150. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/cli/console.py +0 -0
  151. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/cli/session.py +0 -0
  152. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/cli/ssh.py +0 -0
  153. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/cli/telnet.py +0 -0
  154. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/http/__init__.py +0 -0
  155. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/http/client.py +0 -0
  156. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/sync/__init__.py +0 -0
  157. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/sync/nsdp_udp.py +0 -0
  158. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/transport/sync/snmp_netsnmp_cli.py +0 -0
  159. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/__init__.py +0 -0
  160. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/cli_fastpath.py +0 -0
  161. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/faces/__init__.py +0 -0
  162. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/faces/cli.py +0 -0
  163. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/faces/http.py +0 -0
  164. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/faces/mibview.py +0 -0
  165. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/faces/nsdp.py +0 -0
  166. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/faces/snmp.py +0 -0
  167. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/seed.py +0 -0
  168. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/server.py +0 -0
  169. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/state.py +0 -0
  170. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/web.py +0 -0
  171. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/web_fastpath_vlan.py +0 -0
  172. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/web_fastpath_xui.py +0 -0
  173. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/web_gs105pe.py +0 -0
  174. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/web_gs110emx.py +0 -0
  175. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/web_gs110emx_templates.py +0 -0
  176. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/web_gs728tpp.py +0 -0
  177. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/web_gsm7228ps.py +0 -0
  178. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/web_gsm7252ps.py +0 -0
  179. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/src/netgear_switch/virtual/web_m4300.py +0 -0
  180. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/capture_parity.py +0 -0
  181. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_capture.py +0 -0
  182. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_cli_integration.py +0 -0
  183. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_control_poe_port.py +0 -0
  184. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_control_vlan_ip.py +0 -0
  185. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_format.py +0 -0
  186. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_main_framework.py +0 -0
  187. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_new_commands.py +0 -0
  188. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_op_coverage.py +0 -0
  189. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_prompt_wiring.py +0 -0
  190. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_read_commands.py +0 -0
  191. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_resolve.py +0 -0
  192. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_safety.py +0 -0
  193. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/cli/test_serve.py +0 -0
  194. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/conftest.py +0 -0
  195. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/equivalence.py +0 -0
  196. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/captures/gsm7228ps.json +0 -0
  197. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/captures/gsm7252ps.json +0 -0
  198. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/captures/m4300-16x.json +0 -0
  199. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/captures/m4300-24x.json +0 -0
  200. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7228ps_environment.txt +0 -0
  201. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7228ps_lldp.txt +0 -0
  202. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7228ps_mac_table.txt +0 -0
  203. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7228ps_network.txt +0 -0
  204. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7228ps_poe.txt +0 -0
  205. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7228ps_port_all.txt +0 -0
  206. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7228ps_show_version.txt +0 -0
  207. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7228ps_vlan.txt +0 -0
  208. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7228ps_vlan_brief.txt +0 -0
  209. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7228ps_vlan_port_all.txt +0 -0
  210. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7252ps_show_environment.txt +0 -0
  211. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7252ps_show_interface_ethernet_1_0_1.txt +0 -0
  212. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7252ps_show_lldp_remote_device_all.txt +0 -0
  213. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7252ps_show_mac_addr_table.txt +0 -0
  214. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7252ps_show_network.txt +0 -0
  215. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7252ps_show_poe_port_info_all.txt +0 -0
  216. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7252ps_show_port_all.txt +0 -0
  217. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7252ps_show_version.txt +0 -0
  218. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7252ps_show_vlan_90.txt +0 -0
  219. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7252ps_show_vlan_brief.txt +0 -0
  220. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/gsm7252ps_show_vlan_port_all.txt +0 -0
  221. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_environment.txt +0 -0
  222. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_interface_ethernet_1_0_1.txt +0 -0
  223. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_ip_management.txt +0 -0
  224. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_lldp_remote_device_all.txt +0 -0
  225. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_mac_addr_table.txt +0 -0
  226. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_poe_port_info_all.txt +0 -0
  227. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_port_all.txt +0 -0
  228. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_version.txt +0 -0
  229. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_vlan.txt +0 -0
  230. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_vlan_1.txt +0 -0
  231. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_vlan_4.txt +0 -0
  232. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_vlan_5.txt +0 -0
  233. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_16x_show_vlan_port_all.txt +0 -0
  234. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_24x_show_environment.txt +0 -0
  235. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_24x_show_interface_ethernet_1_0_1.txt +0 -0
  236. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_24x_show_ip_management.txt +0 -0
  237. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_24x_show_lldp_remote_device_all.txt +0 -0
  238. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_24x_show_mac_addr_table.txt +0 -0
  239. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_24x_show_port_all.txt +0 -0
  240. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_24x_show_version.txt +0 -0
  241. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_24x_show_vlan.txt +0 -0
  242. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_24x_show_vlan_5.txt +0 -0
  243. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_24x_show_vlan_90.txt +0 -0
  244. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/cli/m4300_24x_show_vlan_port_all.txt +0 -0
  245. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs105pe_membership.html +0 -0
  246. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs105pe_portstats.html +0 -0
  247. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs105pe_pvid.html +0 -0
  248. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs105pe_status.html +0 -0
  249. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs105pe_switch_info.html +0 -0
  250. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs105pe_vlancfg.html +0 -0
  251. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs110emx_cf8021q.html +0 -0
  252. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs110emx_interface_stats.html +0 -0
  253. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs110emx_login.html +0 -0
  254. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs110emx_port_settings.html +0 -0
  255. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs110emx_pvid.html +0 -0
  256. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs110emx_redirect.html +0 -0
  257. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs110emx_sysinfo.html +0 -0
  258. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs110emx_vlanmembership.html +0 -0
  259. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs305ep_dashboard.html +0 -0
  260. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs305ep_login.html +0 -0
  261. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs305ep_membership.html +0 -0
  262. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs305ep_poestatus.html +0 -0
  263. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs305ep_portstats.html +0 -0
  264. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs305ep_pvid.html +0 -0
  265. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs305ep_vlancfg.html +0 -0
  266. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs728tpp_device_info_and_sensors.xml +0 -0
  267. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs728tpp_lldp.xml +0 -0
  268. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs728tpp_macs.xml +0 -0
  269. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs728tpp_mgmt_ip.xml +0 -0
  270. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs728tpp_poe.xml +0 -0
  271. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs728tpp_ports.xml +0 -0
  272. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs728tpp_pvids_membership.xml +0 -0
  273. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs728tpp_vlan_membership_per_vlan.xml +0 -0
  274. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gs728tpp_vlans.xml +0 -0
  275. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7228ps_basicAddressTable.html +0 -0
  276. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7228ps_http_configuration.html +0 -0
  277. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7228ps_ipConfiguration.html +0 -0
  278. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7228ps_lldpRemoteInventory.html +0 -0
  279. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7228ps_poeInterfaceConfiguration.html +0 -0
  280. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7228ps_portPvidConfiguration.html +0 -0
  281. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7228ps_portStatistics.html +0 -0
  282. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7228ps_portsConfiguration.html +0 -0
  283. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7228ps_sysInfo.html +0 -0
  284. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7228ps_syslog_configuration.html +0 -0
  285. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7228ps_vlanPortCfg_vlan5.html +0 -0
  286. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7228ps_vlanStatus.html +0 -0
  287. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_basicAddressTable.html +0 -0
  288. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_http_configuration.html +0 -0
  289. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_https_configuration.html +0 -0
  290. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_ipConfiguration.html +0 -0
  291. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_lldpRemoteInventory.html +0 -0
  292. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_login.html +0 -0
  293. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_poeInterfaceConfiguration.html +0 -0
  294. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_portPvidConfiguration.html +0 -0
  295. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_portStatistics.html +0 -0
  296. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_portsConfiguration.html +0 -0
  297. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_ssh_configuration.html +0 -0
  298. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_sysInfo.html +0 -0
  299. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_syslog_configuration.html +0 -0
  300. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_telnet.html +0 -0
  301. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_user_configuration.html +0 -0
  302. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_user_management.html +0 -0
  303. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_vlanPortCfg_vlan1.html +0 -0
  304. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_vlanPortCfg_vlan141.html +0 -0
  305. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_vlanStatus.html +0 -0
  306. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_vlan_add_form.html +0 -0
  307. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_vlan_configuration.js +0 -0
  308. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_vlan_configuration_live.html +0 -0
  309. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/gsm7252ps_vlan_status_live.html +0 -0
  310. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_16x_lldpRemoteInventory.html +0 -0
  311. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_16x_mgmtVlanIpv4Configuration.html +0 -0
  312. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_16x_poeInterfaceConfiguration.html +0 -0
  313. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_16x_portsConfiguration.html +0 -0
  314. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_16x_syslog_configuration.html +0 -0
  315. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_16x_vlanportcfg_vlan4.html +0 -0
  316. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_24x_http_configuration.html +0 -0
  317. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_24x_https_configuration.html +0 -0
  318. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_24x_poeInterfaceConfiguration.html +0 -0
  319. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_24x_ssh_configuration.html +0 -0
  320. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_24x_syslog_configuration.html +0 -0
  321. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_24x_telnet.html +0 -0
  322. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_24x_user_management.html +0 -0
  323. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_addresstable.html +0 -0
  324. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_lldpRemoteInventory.html +0 -0
  325. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_mgmtVlanIpv4Configuration.html +0 -0
  326. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_ports.html +0 -0
  327. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_portstats.html +0 -0
  328. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_pvid.html +0 -0
  329. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_sysinfo.html +0 -0
  330. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_vlanportcfg_vlan1.html +0 -0
  331. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/http/m4300_vlanstatus.html +0 -0
  332. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/snmp/gsm7252ps_fans.txt +0 -0
  333. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/snmp/gsm7252ps_ifhighspeed.txt +0 -0
  334. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/snmp/gsm7252ps_ifoperstatus.txt +0 -0
  335. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/fixtures/snmp/gsm7252ps_psu.txt +0 -0
  336. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/http_specs.py +0 -0
  337. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/cli/test_cli_parse.py +0 -0
  338. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/http/test_crypt.py +0 -0
  339. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/http/test_endpoints.py +0 -0
  340. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/http/test_forms.py +0 -0
  341. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/http/test_goahead_write.py +0 -0
  342. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/http/test_parse.py +0 -0
  343. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/nsdp/test_auth.py +0 -0
  344. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/nsdp/test_parsers.py +0 -0
  345. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/nsdp/test_protocol.py +0 -0
  346. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/nsdp/test_write_frame.py +0 -0
  347. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/snmp/test_client.py +0 -0
  348. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/snmp/test_oids.py +0 -0
  349. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/snmp/test_parse_lldp_macs.py +0 -0
  350. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/snmp/test_parse_mgmt_ip.py +0 -0
  351. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/snmp/test_parse_poe_sensors.py +0 -0
  352. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/snmp/test_parse_ports.py +0 -0
  353. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/snmp/test_parse_system_info.py +0 -0
  354. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/snmp/test_parse_vlans.py +0 -0
  355. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/protocols/snmp/test_write_encode.py +0 -0
  356. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/snmp_fakes.py +0 -0
  357. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_aio_api.py +0 -0
  358. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_capabilities.py +0 -0
  359. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_cli_read.py +0 -0
  360. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_cli_vlan_write.py +0 -0
  361. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_cli_write.py +0 -0
  362. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_config.py +0 -0
  363. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_cross_backend_equivalence.py +0 -0
  364. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_dispatch.py +0 -0
  365. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_docs_coverage.py +0 -0
  366. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_errors.py +0 -0
  367. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_facade_equivalence.py +0 -0
  368. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_flow_control.py +0 -0
  369. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_http_dispatch.py +0 -0
  370. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_http_equivalence.py +0 -0
  371. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_http_hostname_emx.py +0 -0
  372. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_http_read.py +0 -0
  373. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_http_services.py +0 -0
  374. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_http_syslog.py +0 -0
  375. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_http_users.py +0 -0
  376. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_http_vlan_membership.py +0 -0
  377. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_http_write.py +0 -0
  378. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_http_xui_writes.py +0 -0
  379. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_import.py +0 -0
  380. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_mcp_server.py +0 -0
  381. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_models.py +0 -0
  382. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_models_snmp_read.py +0 -0
  383. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_nsdp_integration.py +0 -0
  384. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_nsdp_read.py +0 -0
  385. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_nsdp_write.py +0 -0
  386. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_port_speed.py +0 -0
  387. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_port_speed_http.py +0 -0
  388. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_public_api.py +0 -0
  389. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_quality_gates.py +0 -0
  390. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_registry.py +0 -0
  391. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_snmp_integration.py +0 -0
  392. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_snmp_read.py +0 -0
  393. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_snmp_write.py +0 -0
  394. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_sync_api.py +0 -0
  395. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_syslog_collectors.py +0 -0
  396. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_version.py +0 -0
  397. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/test_write_equivalence.py +0 -0
  398. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/transport/_fastpath_fake.py +0 -0
  399. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/transport/test_cli_console.py +0 -0
  400. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/transport/test_cli_scp_cert.py +0 -0
  401. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/transport/test_cli_telnet.py +0 -0
  402. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/transport/test_http_client.py +0 -0
  403. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/transport/test_nsdp_udp_sync.py +0 -0
  404. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/transport/test_set_transport.py +0 -0
  405. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/transport/test_snmp_netsnmp_cli.py +0 -0
  406. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/transport/test_snmp_pysnmp.py +0 -0
  407. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/transport/test_value_parity.py +0 -0
  408. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_cli_cross_backend.py +0 -0
  409. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_cli_gsm7228ps_parity.py +0 -0
  410. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_gs728tpp_vlan_fidelity.py +0 -0
  411. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_gsm7228ps_seed.py +0 -0
  412. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_hostname.py +0 -0
  413. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_m4300_seeds.py +0 -0
  414. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_mibview.py +0 -0
  415. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_mutable_state.py +0 -0
  416. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_nsdp_state.py +0 -0
  417. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_port_description_outcomes.py +0 -0
  418. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_serve_daemon.py +0 -0
  419. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_snmp_write_face.py +0 -0
  420. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_state_seed.py +0 -0
  421. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_switchport_vlan_write.py +0 -0
  422. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_syslog_fidelity.py +0 -0
  423. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_virtual_http_face.py +0 -0
  424. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_virtual_nsdp_face.py +0 -0
  425. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_virtual_snmp_face.py +0 -0
  426. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_web_projection.py +0 -0
  427. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/tests/virtual/test_write_outcomes.py +0 -0
  428. {python_netgear_switch_library-0.0.post404 → python_netgear_switch_library-0.1.post2}/uv.lock +0 -0
@@ -2,7 +2,10 @@ name: CI
2
2
 
3
3
  # Runs the SAME gates as local development (ruff, mypy --strict, pytest with
4
4
  # coverage >= 90) on every push to main and every pull request. A green run here
5
- # is what "mergeable" means; merging to main triggers the release workflows.
5
+ # is what "mergeable" means -- and what "releasable" means: publish-pypi.yml and
6
+ # deb.yml are triggered by this workflow COMPLETING on main and proceed only
7
+ # when it succeeded (workflow_run + conclusion check), so a red push to main
8
+ # is never published. Renaming this workflow breaks that trigger.
6
9
  on:
7
10
  push:
8
11
  branches: [main]
@@ -1,18 +1,30 @@
1
1
  name: Debian Packages + apt repo
2
2
 
3
- # Rolling release: every push to main builds python3-netgear-switch-library for
4
- # Debian trixie AND sid and republishes a signed flat apt repository on GitHub
5
- # Pages (https://mithro.github.io/python-netgear-switch-library/). Mirrors the pattern
6
- # used by other mithro apt-repo projects (sensors2mqtt, ten64-controller). The
7
- # package is Architecture: all (pure Python), so it builds on the default x86
8
- # runner and installs on any Debian arch. No tags: the version is git-derived.
3
+ # Rolling release: every GREEN push to main builds python3-netgear-switch-library
4
+ # for Debian trixie AND sid and republishes a signed flat apt repository on
5
+ # GitHub Pages (https://mith.ro/python-netgear-switch-library/). Mirrors the
6
+ # pattern used by other mithro apt-repo projects (sensors2mqtt, ten64-controller).
7
+ # The package is Architecture: all (pure Python), so it builds on the default x86
8
+ # runner and installs on any Debian arch. The version is git-derived (vX.Y at a
9
+ # tag, vX.Y.postN after it -- identical to the wheel's).
10
+ #
11
+ # Gated on CI exactly like publish-pypi.yml: triggered when the "CI" workflow
12
+ # completes for main, and build-deb only proceeds when that run succeeded, so a
13
+ # red commit never reaches the apt repo. workflow_dispatch stays for re-runs.
9
14
  on:
10
- push:
15
+ workflow_run:
16
+ workflows: [CI]
17
+ types: [completed]
11
18
  branches: [main]
12
19
  workflow_dispatch:
13
20
 
14
21
  jobs:
15
22
  build-deb:
23
+ # workflow_run fires on every completion (failure/cancelled too); only a
24
+ # successful CI run is a release. publish-apt inherits the skip via needs.
25
+ if: >-
26
+ github.event_name == 'workflow_dispatch' ||
27
+ github.event.workflow_run.conclusion == 'success'
16
28
  runs-on: ubuntu-latest
17
29
  strategy:
18
30
  fail-fast: false
@@ -21,7 +33,10 @@ jobs:
21
33
  steps:
22
34
  - uses: actions/checkout@v5
23
35
  with:
24
- fetch-depth: 0 # full history so deb-version.py can count commits
36
+ # Pin to the SHA CI validated, not the default-branch HEAD (which a
37
+ # workflow_run checkout would otherwise use and may already be past).
38
+ ref: ${{ github.event.workflow_run.head_sha || github.sha }}
39
+ fetch-depth: 0 # full history + tags so deb-version.py can describe
25
40
 
26
41
  - name: Build package in debian:${{ matrix.suite }}
27
42
  run: |
@@ -0,0 +1,71 @@
1
+ name: Publish to PyPI
2
+
3
+ # Every GREEN push to main is a release. The version is derived from git by
4
+ # hatch-vcs (see pyproject.toml): vX.Y at a tag, vX.Y.postN N commits later, so
5
+ # each commit produces a new, unique version -- no manual bump.
6
+ #
7
+ # This workflow is gated on CI: it runs when the "CI" workflow (ruff, mypy,
8
+ # pytest + coverage, docs) COMPLETES for a push to main, and the build job only
9
+ # proceeds when that run SUCCEEDED. Before this gate, a red CI run and a PyPI
10
+ # upload raced each other and broken commits were published (13ef042 shipped
11
+ # with the docs job failing, a60bae6 with every test job failing). The
12
+ # workflow_dispatch path stays for manual re-runs.
13
+ #
14
+ # Publishing uses PyPI Trusted Publishing (OIDC): there is no API token in the
15
+ # repo; the `pypi` environment + trusted publisher are registered (see
16
+ # RELEASING.md).
17
+ on:
18
+ workflow_run:
19
+ workflows: [CI]
20
+ types: [completed]
21
+ branches: [main]
22
+ workflow_dispatch:
23
+
24
+ jobs:
25
+ build:
26
+ # workflow_run fires on EVERY completion (failure and cancelled included);
27
+ # only a successful CI run is a release. Dependent jobs inherit the skip.
28
+ if: >-
29
+ github.event_name == 'workflow_dispatch' ||
30
+ github.event.workflow_run.conclusion == 'success'
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - uses: actions/checkout@v5
34
+ with:
35
+ # A workflow_run checkout defaults to the default branch HEAD, which
36
+ # may already be PAST the commit CI just validated. Pin to the SHA
37
+ # CI actually ran on, so the published version is exactly the one
38
+ # that went green.
39
+ ref: ${{ github.event.workflow_run.head_sha || github.sha }}
40
+ fetch-depth: 0 # full history + tags for hatch-vcs version derivation
41
+
42
+ - uses: astral-sh/setup-uv@v7
43
+
44
+ - name: Build sdist + wheel
45
+ run: uv build
46
+
47
+ - name: Show derived version
48
+ run: ls -1 dist/
49
+
50
+ - uses: actions/upload-artifact@v7
51
+ with:
52
+ name: dist
53
+ path: dist/
54
+
55
+ publish:
56
+ needs: build
57
+ runs-on: ubuntu-latest
58
+ # Trusted Publishing requires an OIDC token and a named environment.
59
+ environment: pypi
60
+ permissions:
61
+ id-token: write
62
+ steps:
63
+ - uses: actions/download-artifact@v8
64
+ with:
65
+ name: dist
66
+ path: dist/
67
+
68
+ - name: Publish to PyPI (OIDC trusted publishing)
69
+ uses: pypa/gh-action-pypi-publish@release/v1
70
+ with:
71
+ skip-existing: true
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: python-netgear-switch-library
3
- Version: 0.0.post404
3
+ Version: 0.1.post2
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
@@ -83,14 +83,14 @@ GitHub Pages apt repository. Pick the line matching your suite:
83
83
 
84
84
  ```sh
85
85
  sudo install -d -m0755 /etc/apt/keyrings
86
- curl -fsSL https://mithro.github.io/python-netgear-switch-library/netgear-switch.gpg \
86
+ curl -fsSL https://mith.ro/python-netgear-switch-library/netgear-switch.gpg \
87
87
  | sudo tee /etc/apt/keyrings/netgear-switch.gpg > /dev/null
88
88
 
89
89
  # trixie:
90
- echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mithro.github.io/python-netgear-switch-library/trixie/ ./" \
90
+ echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mith.ro/python-netgear-switch-library/trixie/ ./" \
91
91
  | sudo tee /etc/apt/sources.list.d/netgear-switch.list
92
92
  # sid:
93
- echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mithro.github.io/python-netgear-switch-library/sid/ ./" \
93
+ echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mith.ro/python-netgear-switch-library/sid/ ./" \
94
94
  | sudo tee /etc/apt/sources.list.d/netgear-switch.list
95
95
 
96
96
  sudo apt update
@@ -48,14 +48,14 @@ GitHub Pages apt repository. Pick the line matching your suite:
48
48
 
49
49
  ```sh
50
50
  sudo install -d -m0755 /etc/apt/keyrings
51
- curl -fsSL https://mithro.github.io/python-netgear-switch-library/netgear-switch.gpg \
51
+ curl -fsSL https://mith.ro/python-netgear-switch-library/netgear-switch.gpg \
52
52
  | sudo tee /etc/apt/keyrings/netgear-switch.gpg > /dev/null
53
53
 
54
54
  # trixie:
55
- echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mithro.github.io/python-netgear-switch-library/trixie/ ./" \
55
+ echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mith.ro/python-netgear-switch-library/trixie/ ./" \
56
56
  | sudo tee /etc/apt/sources.list.d/netgear-switch.list
57
57
  # sid:
58
- echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mithro.github.io/python-netgear-switch-library/sid/ ./" \
58
+ echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mith.ro/python-netgear-switch-library/sid/ ./" \
59
59
  | sudo tee /etc/apt/sources.list.d/netgear-switch.list
60
60
 
61
61
  sudo apt update
@@ -1,19 +1,38 @@
1
1
  # Releasing
2
2
 
3
- This project is a **rolling release**. There are no tags and no manual version
4
- bumps: the version is derived from git (`hatch-vcs` for the wheel,
5
- `packaging/deb-version.py` for the `.deb`), and **every merge to `main`
6
- publishes new packages** automatically:
3
+ This project is a **rolling release**. There are no manual version bumps: the
4
+ version is derived from `git describe` (`hatch-vcs` for the wheel,
5
+ `packaging/deb-version.py` for the `.deb`) `X.Y` at a `vX.Y` tag,
6
+ `X.Y.postN` N commits after it — and **every green merge to `main` publishes
7
+ new packages** automatically:
7
8
 
8
9
  - `.github/workflows/ci.yml` — runs the gates (ruff, mypy --strict, pytest with
9
- coverage >= 90) on every push and PR. A green run is what "mergeable" means.
10
+ coverage >= 90, docs build) on every push and PR. A green run is what
11
+ "mergeable" means, and it is what triggers the two release workflows.
10
12
  - `.github/workflows/publish-pypi.yml` — builds and uploads the wheel + sdist to
11
- PyPI on every push to `main`.
13
+ PyPI when CI **succeeds** on `main` (`workflow_run`; a failed or cancelled CI
14
+ run publishes nothing, and the checkout is pinned to the SHA CI validated).
12
15
  - `.github/workflows/deb.yml` — builds `.deb`s for trixie + sid and republishes
13
- the signed apt repo on GitHub Pages on every push to `main`.
16
+ the signed apt repo on GitHub Pages, gated the same way.
14
17
 
15
18
  Merges to `main` MUST use `--no-ff` merge commits so history stays linear per PR.
16
19
 
20
+ ## Tags
21
+
22
+ Tags are the only human input to the version. `v0.0` sits on the root commit
23
+ (so `git describe` works from the start of history, per the repo-setup
24
+ guidance) and `v0.1` marks where the CI-gated pipeline landed (2026-08-22). The
25
+ fallback before any tag existed was `0.0.post<commit count>`, which reached
26
+ `0.0.post405` on PyPI; `v0.1` was chosen because it sorts above that in both
27
+ PEP 440 and Debian ordering, whereas counting from a root tag alone would have
28
+ re-issued `0.0.post404`/`405` (and `skip-existing` would have silently dropped
29
+ the upload).
30
+
31
+ To cut a new series, push an annotated `vX.Y` tag on `main` (a GitHub tag
32
+ ruleset only admits `vXX.ZZZ`-shaped tags) — the next green CI run publishes
33
+ `X.Y`, and every commit after it `X.Y.postN`. Never move or delete a tag that
34
+ has been published from.
35
+
17
36
  ## One-time human setup
18
37
 
19
38
  These steps are done ONCE by a maintainer. **No secret or key is ever committed
@@ -83,7 +102,7 @@ re-runs idempotent.
83
102
 
84
103
  1. Settings → Pages → Source: **GitHub Actions**.
85
104
  2. The `deb.yml` `publish-apt` job deploys the apt repo to
86
- `https://mithro.github.io/python-netgear-switch-library/`. It targets the
105
+ `https://mith.ro/python-netgear-switch-library/`. It targets the
87
106
  `github-pages` deployment environment, which GitHub creates automatically
88
107
  once Pages is enabled — no separate environment setup is needed for this
89
108
  one (unlike the `pypi` environment above, which must be created by hand).
@@ -91,7 +110,8 @@ re-runs idempotent.
91
110
  ## Verifying a release
92
111
 
93
112
  - PyPI: check https://pypi.org/project/python-netgear-switch-library/ for the new
94
- `0.0.postN` version.
113
+ `X.Y.postN` version (matches `git describe --tags` on `main`, e.g. `v0.1-3-g…`
114
+ → `0.1.post3`).
95
115
  - apt: `sudo apt update && apt-cache policy python3-netgear-switch-library` on a
96
116
  Debian trixie/sid box configured per the README. Before the GPG key is set
97
117
  (see step 2 above), expect `apt update` to fail with a signature error for
@@ -82,14 +82,14 @@ GitHub Pages apt repository:
82
82
  .. code-block:: sh
83
83
 
84
84
  sudo install -d -m0755 /etc/apt/keyrings
85
- curl -fsSL https://mithro.github.io/python-netgear-switch-library/netgear-switch.gpg \
85
+ curl -fsSL https://mith.ro/python-netgear-switch-library/netgear-switch.gpg \
86
86
  | sudo tee /etc/apt/keyrings/netgear-switch.gpg > /dev/null
87
87
 
88
88
  # trixie:
89
- echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mithro.github.io/python-netgear-switch-library/trixie/ ./" \
89
+ echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mith.ro/python-netgear-switch-library/trixie/ ./" \
90
90
  | sudo tee /etc/apt/sources.list.d/netgear-switch.list
91
91
  # sid:
92
- echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mithro.github.io/python-netgear-switch-library/sid/ ./" \
92
+ echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mith.ro/python-netgear-switch-library/sid/ ./" \
93
93
  | sudo tee /etc/apt/sources.list.d/netgear-switch.list
94
94
 
95
95
  sudo apt update
@@ -102,10 +102,11 @@ the net-snmp tools automatically. The packaging lives in ``debian/`` and
102
102
  Versioning
103
103
  ----------
104
104
 
105
- A **rolling release**. The version is derived from git by ``hatch-vcs``
106
- (``0.0.postN``, or ``X.Y.postN`` once a ``vX.Y`` tag exists); every merge to
107
- ``main`` publishes to PyPI and to the apt repository. No manual version bumps —
108
- see ``RELEASING.md``.
105
+ A **rolling release**. The version is derived from ``git describe`` by
106
+ ``hatch-vcs``: ``X.Y`` at a ``vX.Y`` tag, ``X.Y.postN`` N commits after it
107
+ (``0.1``, ``0.1.post1``, …). Every merge to ``main`` whose CI run is green
108
+ publishes to PyPI and to the apt repository — a red run publishes nothing. No
109
+ manual version bumps — see ``RELEASING.md``.
109
110
 
110
111
  .. note::
111
112
 
@@ -14,10 +14,10 @@ Rolling release &mdash; every push to <code>main</code> publishes a new version
14
14
  <h2>Setup (Debian trixie)</h2>
15
15
  <pre>
16
16
  sudo install -d -m0755 /etc/apt/keyrings
17
- curl -fsSL https://mithro.github.io/python-netgear-switch-library/netgear-switch.gpg \
17
+ curl -fsSL https://mith.ro/python-netgear-switch-library/netgear-switch.gpg \
18
18
  | sudo tee /etc/apt/keyrings/netgear-switch.gpg > /dev/null
19
19
 
20
- echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mithro.github.io/python-netgear-switch-library/trixie/ ./" \
20
+ echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mith.ro/python-netgear-switch-library/trixie/ ./" \
21
21
  | sudo tee /etc/apt/sources.list.d/netgear-switch.list
22
22
 
23
23
  sudo apt update
@@ -27,10 +27,10 @@ sudo apt install python3-netgear-switch-library
27
27
  <h2>Setup (Debian sid)</h2>
28
28
  <pre>
29
29
  sudo install -d -m0755 /etc/apt/keyrings
30
- curl -fsSL https://mithro.github.io/python-netgear-switch-library/netgear-switch.gpg \
30
+ curl -fsSL https://mith.ro/python-netgear-switch-library/netgear-switch.gpg \
31
31
  | sudo tee /etc/apt/keyrings/netgear-switch.gpg > /dev/null
32
32
 
33
- echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mithro.github.io/python-netgear-switch-library/sid/ ./" \
33
+ echo "deb [signed-by=/etc/apt/keyrings/netgear-switch.gpg] https://mith.ro/python-netgear-switch-library/sid/ ./" \
34
34
  | sudo tee /etc/apt/sources.list.d/netgear-switch.list
35
35
 
36
36
  sudo apt update
@@ -63,11 +63,16 @@ ngsw-mcp = "netgear_switch.mcp.server:main"
63
63
  [dependency-groups]
64
64
  dev = ["pytest>=8.0", "ruff>=0.6", "mypy>=1.11", "pytest-cov>=5.0"]
65
65
 
66
- # Rolling release: the version is derived from git, never hand-edited and never
67
- # tagged. Every commit on main increments the commit height, so post-release
68
- # versioning yields a real, monotonic version (0.0.postN with no tag; X.Y.postN
69
- # once a vX.Y tag ever exists). "no-local-version" keeps the version PyPI-upload
70
- # safe. These forms are also valid Debian versions verbatim.
66
+ # Rolling release: the version is derived from git (`git describe`), never
67
+ # hand-edited. vX.Y tags (v0.0 on the root commit per the repo-setup guidance,
68
+ # v0.1 when the CI-gated release pipeline landed on 2026-08-22) are the only
69
+ # human input; every commit after a tag increments the distance, so post-release
70
+ # versioning yields a real, monotonic version: X.Y at the tag, X.Y.postN N
71
+ # commits later. (Before any tag existed the fallback was 0.0.post<commit
72
+ # count>, which reached 0.0.post405 on PyPI -- v0.1 was chosen to sort ABOVE
73
+ # that, since re-counting from a root tag would have re-issued 0.0.post404/405.)
74
+ # "no-local-version" keeps the version PyPI-upload safe. These forms are also
75
+ # valid Debian versions verbatim; packaging/deb-version.py applies the same rule.
71
76
  [tool.hatch.version]
72
77
  source = "vcs"
73
78
 
@@ -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.post404'
22
- __version_tuple__ = version_tuple = (0, 0, 'post404')
21
+ __version__ = version = '0.1.post2'
22
+ __version_tuple__ = version_tuple = (0, 1, 'post2')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -1593,13 +1593,13 @@ class HttpWriter:
1593
1593
  is an independent witness):
1594
1594
 
1595
1595
  * the body as first built -> failed on 'Host Address' and 'Port'
1596
- * + IP Address Type "IPv4" -> those two passed; the two ENUMS then
1596
+ * plus IP Address Type "IPv4" -> those two passed; the two ENUMS then
1597
1597
  failed ('IP Address Type', 'Severity Filter')
1598
- * + enums as INDICES instead of labels (xa_2_1_4 lists
1598
+ * plus enums as INDICES instead of labels (xa_2_1_4 lists
1599
1599
  Emergency..Debug in standard syslog order, xa_2_1_7 lists
1600
1600
  Unknown,IPv4,IPv6,DNS, so IPv4 = 1) -> the enums passed and
1601
1601
  'Host Address' failed again
1602
- * + row-status "Add" instead of "Active" (the page's own
1602
+ * plus row-status "Add" instead of "Active" (the page's own
1603
1603
  xeleValue_2_1_5) -> unchanged
1604
1604
 
1605
1605
  So three of the four fields can be made to stick and the address cannot,
@@ -55,7 +55,11 @@ if TYPE_CHECKING:
55
55
  # identical to _build_gs728tpp_cert_xml so its proven output is unchanged.
56
56
  _ESCAPES = {'"': "&quot;", "'": "&apos;"}
57
57
 
58
- #: interfaceType in every VLAN/port object: 1 = physical port, 2 = LAG.
58
+ #: interfaceType in every VLAN/port object -- 1 = physical port, 2 = LAG.
59
+ #: (No ``:`` after the name, deliberately. Napoleon reads a ONE-LINE ``#:``
60
+ #: comment shaped ``x: y`` as "type x, described as y", which rendered a
61
+ #: nonsense "Type: interfaceType in every VLAN/port object" field on the page
62
+ #: and failed the nitpicky build. The two-line comment below is unaffected.)
59
63
  INTERFACE_PHYSICAL = "1"
60
64
  INTERFACE_LAG = "2"
61
65
 
@@ -203,7 +207,7 @@ def vlan_delete_body(vlan: int) -> str:
203
207
 
204
208
  The shape is taken verbatim from ``VlanConfig.Reset``, which posts a
205
209
  literal string rather than building it through the framework -- so it
206
- states the delete envelope exactly:
210
+ states the delete envelope exactly::
207
211
 
208
212
  <DeviceConfiguration><VLANInterfaceList action="restoreAll"/>
209
213
  <VLANList action="delete"><VLAN><VLANID>4-4093</VLANID></VLAN>
@@ -1729,7 +1729,7 @@ SERVICE_NAMES: tuple[str, ...] = ("http", "https", "ssh", "telnet")
1729
1729
 
1730
1730
 
1731
1731
  def parse_service_page(html: str, service: str) -> ServiceStatus:
1732
- """One service's config page -> its :class:`ServiceStatus`.
1732
+ """One service's config page -> its :class:`~netgear_switch.models.ServiceStatus`.
1733
1733
 
1734
1734
  Tries the XUI coordinate, then the plain-form radio group. Raises
1735
1735
  ``HttpUnexpectedPageError`` when NEITHER is present rather than reporting
@@ -6,11 +6,14 @@ container with no third-party packages installed), so these tests drive it
6
6
  via ``subprocess`` under plain ``python3`` rather than importing it -- that
7
7
  also proves it truly needs nothing beyond the standard library.
8
8
 
9
- The commit count grows every time this repo gets a new commit, so nothing
10
- here hard-codes today's ``post<N>`` value; each assertion recomputes the
11
- expected value from ``git`` at test time, mirroring the derivation logic
12
- itself (see the brief's own verification: ``0.0.post$(git rev-list --count
13
- HEAD)``).
9
+ The version changes every time this repo gets a commit or a tag, so nothing
10
+ here hard-codes today's value; each assertion recomputes the expected value
11
+ from ``git`` at test time. The live-repo check deliberately uses DIFFERENT git
12
+ commands from the script (``describe --abbrev=0`` + ``rev-list --count
13
+ TAG..HEAD`` versus the script's ``describe --long`` regex) so the two can
14
+ disagree if either is wrong. The tagless fallback (``0.0.post<count>``) is
15
+ exercised in a throwaway repo: the live repo has been tagged since v0.0/v0.1
16
+ on 2026-08-22, so it no longer takes that path.
14
17
  """
15
18
 
16
19
  from __future__ import annotations
@@ -116,12 +119,37 @@ def test_only_stdlib_imports():
116
119
  assert seen <= stdlib_allow, f"non-stdlib imports found: {seen - stdlib_allow}"
117
120
 
118
121
 
119
- def test_version_matches_commit_count_fallback():
120
- """No tags exist upstream, so the fallback path (0.0.post<count>) is live."""
121
- expected = f"0.0.post{_git('rev-list', '--count', 'HEAD')}"
122
+ def test_live_repo_version_matches_git_describe():
123
+ """The real checkout: X.Y at the nearest vX.Y tag, X.Y.postN N commits on.
124
+
125
+ Expected value is derived independently of the script: the nearest tag via
126
+ ``describe --abbrev=0`` and the distance via ``rev-list --count TAG..HEAD``
127
+ (the script parses ``describe --long`` instead). This broke on 2026-08-22
128
+ when v0.1 was pushed and the old assertion still expected the tagless
129
+ ``0.0.post<count>`` fallback -- CI went red and, correctly, nothing was
130
+ published for that commit.
131
+ """
132
+ tag = _git("describe", "--tags", "--abbrev=0", "--match", "v[0-9]*")
133
+ assert tag.startswith("v"), tag
134
+ base = tag[1:]
135
+ distance = int(_git("rev-list", "--count", f"{tag}..HEAD"))
136
+ expected = base if distance == 0 else f"{base}.post{distance}"
122
137
  assert _run() == expected
123
138
 
124
139
 
140
+ def test_commit_count_fallback_in_tagless_repo(tmp_path):
141
+ """With no vX.Y tag at all the version is 0.0.post<commit count>.
142
+
143
+ The live repo left this path when it was tagged, so exercise it in a
144
+ throwaway repo: three commits, no tags -> 0.0.post3.
145
+ """
146
+ repo = tmp_path / "tagless-repo"
147
+ _init_repo(repo)
148
+ for i in range(3):
149
+ _commit(repo, f"commit {i}")
150
+ assert _run_in_repo(repo).stdout.strip() == "0.0.post3"
151
+
152
+
125
153
  def test_version_is_a_valid_debian_version_string():
126
154
  printed = _run()
127
155
  assert _DEBIAN_VERSION_RE.match(printed), printed
@@ -159,9 +187,10 @@ def test_write_changelog_produces_parseable_debian_changelog(tmp_path):
159
187
  def test_version_tag_based_path(tmp_path):
160
188
  """vX.Y -> X.Y at the tag; X.Y.postN with N commits after it.
161
189
 
162
- The live upstream repo has no tags, so this path (the ``git describe``
163
- branch of ``version()``) has no coverage from the other tests above --
164
- exercise it directly against a throwaway repo instead.
190
+ This is the path the live upstream repo takes since v0.0 (root commit) and
191
+ v0.1 (2026-08-22) were tagged; the live-repo test above checks it against
192
+ the real checkout, this one pins the exact arithmetic on a throwaway
193
+ repo whose tag and distance are fully controlled.
165
194
  """
166
195
  repo = tmp_path / "tag-repo"
167
196
  _init_repo(repo)
@@ -1,52 +0,0 @@
1
- name: Publish to PyPI
2
-
3
- # Every push to main is a release. The version is derived from git by
4
- # hatch-vcs (see pyproject.toml), so each commit produces a new, unique
5
- # version -- no tag, no manual bump. Publishing uses PyPI Trusted Publishing
6
- # (OIDC): there is no API token in the repo. FINAL HUMAN SETUP STEP: register
7
- # this repo+workflow as a trusted publisher on PyPI and create the `pypi`
8
- # environment (see RELEASING.md). Until that is done the build job still
9
- # runs and the publish job is a no-op-safe gate.
10
- on:
11
- push:
12
- branches: [main]
13
- workflow_dispatch:
14
-
15
- jobs:
16
- build:
17
- runs-on: ubuntu-latest
18
- steps:
19
- - uses: actions/checkout@v5
20
- with:
21
- fetch-depth: 0 # full history for hatch-vcs version derivation
22
-
23
- - uses: astral-sh/setup-uv@v7
24
-
25
- - name: Build sdist + wheel
26
- run: uv build
27
-
28
- - name: Show derived version
29
- run: ls -1 dist/
30
-
31
- - uses: actions/upload-artifact@v7
32
- with:
33
- name: dist
34
- path: dist/
35
-
36
- publish:
37
- needs: build
38
- runs-on: ubuntu-latest
39
- # Trusted Publishing requires an OIDC token and a named environment.
40
- environment: pypi
41
- permissions:
42
- id-token: write
43
- steps:
44
- - uses: actions/download-artifact@v8
45
- with:
46
- name: dist
47
- path: dist/
48
-
49
- - name: Publish to PyPI (OIDC trusted publishing)
50
- uses: pypa/gh-action-pypi-publish@release/v1
51
- with:
52
- skip-existing: true