python-netgear-switch-library 0.0.post325__tar.gz → 0.0.post326__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.
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/PKG-INFO +1 -1
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/_ext/support_tables.py +6 -1
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/api/cli.rst +1 -1
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/api/facades.rst +1 -1
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/api/index.rst +1 -1
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/conf.py +43 -2
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/development.rst +2 -2
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/fake/internals.rst +7 -5
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/fake/serving.rst +1 -1
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/fake/testing.rst +105 -41
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/guide/concepts.rst +21 -20
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/guide/configuration.rst +8 -8
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/guide/installation.rst +1 -1
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/guide/quickstart.rst +4 -4
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/guide/reading.rst +17 -17
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/guide/writing.rst +15 -15
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/mcp.rst +1 -1
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/models/gs110emx.rst +1 -1
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/models/gsm7228ps.rst +3 -3
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/models/index.rst +3 -3
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/models/m4300-16x.rst +1 -1
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/models/m4300-24x.rst +5 -5
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/models/support.rst +4 -4
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/protocols/cli.rst +7 -7
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/protocols/http.rst +3 -3
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/protocols/nsdp.rst +4 -4
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/protocols/snmp.rst +3 -3
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/_version.py +2 -2
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/aio_api.py +12 -6
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/.github/workflows/ci.yml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/.github/workflows/deb.yml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/.github/workflows/publish-pypi.yml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/.gitignore +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/.readthedocs.yaml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/CLAUDE.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/LICENSE +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/README.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/RELEASING.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/debian/changelog +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/debian/control +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/debian/copyright +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/debian/rules +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/debian/source/format +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/Makefile +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/_ext/filelinks.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/_static/ngsw.css +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/api/core.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/api/mcp.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/api/operations.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/api/protocols.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/api/transport.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/api/virtual.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/cli.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/fake/index.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/guide/principles.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/index.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/models/gs105pe.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/models/gs305ep.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/models/gs728tpp.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/models/gsm7252ps.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/protocols/index.rst +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/superpowers/plans/2026-07-15-foundation.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/superpowers/plans/2026-07-17-slice-02-snmp-read-core.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/superpowers/plans/2026-07-17-slice-03-read-apis.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/superpowers/plans/2026-07-18-slice-04-snmp-write.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/superpowers/plans/2026-07-18-slice-05-nsdp.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/superpowers/plans/2026-07-18-slice-06-http.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/superpowers/plans/2026-07-18-slice-07-cli.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/superpowers/plans/2026-07-18-slice-08-packaging-ci.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/superpowers/plans/2026-07-23-gsm7252ps-http-xe-dialect.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/superpowers/specs/2026-07-15-netgear-control-library-design.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/superpowers/specs/2026-07-23-gsm7252ps-http-xe-dialect-design.md +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/packaging/apt-index.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/packaging/ci-build.sh +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/packaging/deb-version.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/pyproject.toml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/_dispatch.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/capabilities.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/cli/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/cli/capture.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/cli/context.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/cli/format.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/cli/main.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/cli/resolve.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/cli/safety.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/cli_read.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/cli_write.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/config.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/errors.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/http_read.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/http_write.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/mcp/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/mcp/server.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/models.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/nsdp_read.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/nsdp_write.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/cli/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/cli/commands.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/cli/parse.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/http/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/http/crypt.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/http/endpoints.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/http/forms.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/http/parse.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/http/session.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/http/types.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/nsdp/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/nsdp/auth.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/nsdp/client.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/nsdp/parsers.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/nsdp/protocol.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/nsdp/types.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/nsdp/write.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/snmp/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/snmp/client.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/snmp/oids.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/snmp/parse.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/protocols/snmp/write.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/py.typed +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/registry.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/snmp_read.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/snmp_write.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/sync_api.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/aio/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/aio/nsdp_udp.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/aio/snmp_pysnmp.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/cli/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/cli/console.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/cli/session.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/cli/ssh.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/cli/telnet.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/http/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/http/client.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/sync/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/sync/nsdp_udp.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/transport/sync/snmp_netsnmp_cli.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/cli_fastpath.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/faces/__init__.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/faces/cli.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/faces/http.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/faces/mibview.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/faces/nsdp.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/faces/snmp.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/seed.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/server.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/state.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/web.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/web_fastpath_vlan.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/web_fastpath_xui.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/web_gs105pe.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/web_gs110emx.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/web_gs110emx_templates.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/web_gs728tpp.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/web_gsm7228ps.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/web_gsm7252ps.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/src/netgear_switch/virtual/web_m4300.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/capture_parity.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_capture.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_cli_integration.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_control_poe_port.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_control_vlan_ip.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_format.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_main_framework.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_new_commands.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_op_coverage.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_prompt_wiring.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_read_commands.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_resolve.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_safety.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/cli/test_serve.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/conftest.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/equivalence.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/captures/gsm7228ps.json +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/captures/gsm7252ps.json +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/captures/m4300-16x.json +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/captures/m4300-24x.json +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7228ps_environment.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7228ps_lldp.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7228ps_mac_table.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7228ps_network.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7228ps_poe.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7228ps_port_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7228ps_show_version.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7228ps_vlan.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7228ps_vlan_brief.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7228ps_vlan_port_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7252ps_show_environment.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7252ps_show_interface_ethernet_1_0_1.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7252ps_show_lldp_remote_device_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7252ps_show_mac_addr_table.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7252ps_show_network.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7252ps_show_poe_port_info_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7252ps_show_port_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7252ps_show_version.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7252ps_show_vlan_90.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7252ps_show_vlan_brief.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/gsm7252ps_show_vlan_port_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_environment.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_interface_ethernet_1_0_1.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_ip_management.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_lldp_remote_device_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_mac_addr_table.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_poe_port_info_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_port_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_version.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_vlan.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_vlan_1.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_vlan_4.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_vlan_5.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_16x_show_vlan_port_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_24x_show_environment.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_24x_show_interface_ethernet_1_0_1.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_24x_show_ip_management.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_24x_show_lldp_remote_device_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_24x_show_mac_addr_table.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_24x_show_port_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_24x_show_version.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_24x_show_vlan.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_24x_show_vlan_5.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_24x_show_vlan_90.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/cli/m4300_24x_show_vlan_port_all.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs105pe_membership.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs105pe_portstats.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs105pe_pvid.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs105pe_status.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs105pe_switch_info.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs105pe_vlancfg.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs110emx_cf8021q.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs110emx_interface_stats.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs110emx_login.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs110emx_port_settings.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs110emx_pvid.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs110emx_redirect.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs110emx_sysinfo.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs110emx_vlanmembership.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs305ep_dashboard.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs305ep_login.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs305ep_membership.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs305ep_poestatus.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs305ep_portstats.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs305ep_pvid.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs305ep_vlancfg.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs728tpp_device_info_and_sensors.xml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs728tpp_lldp.xml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs728tpp_macs.xml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs728tpp_mgmt_ip.xml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs728tpp_poe.xml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs728tpp_ports.xml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs728tpp_pvids_membership.xml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs728tpp_vlan_membership_per_vlan.xml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gs728tpp_vlans.xml +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7228ps_basicAddressTable.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7228ps_ipConfiguration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7228ps_lldpRemoteInventory.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7228ps_poeInterfaceConfiguration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7228ps_portPvidConfiguration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7228ps_portStatistics.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7228ps_portsConfiguration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7228ps_sysInfo.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7228ps_vlanPortCfg_vlan5.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7228ps_vlanStatus.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7252ps_basicAddressTable.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7252ps_ipConfiguration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7252ps_lldpRemoteInventory.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7252ps_login.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7252ps_poeInterfaceConfiguration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7252ps_portPvidConfiguration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7252ps_portStatistics.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7252ps_portsConfiguration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7252ps_sysInfo.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7252ps_vlanPortCfg_vlan1.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7252ps_vlanPortCfg_vlan141.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/gsm7252ps_vlanStatus.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_16x_lldpRemoteInventory.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_16x_mgmtVlanIpv4Configuration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_16x_poeInterfaceConfiguration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_16x_portsConfiguration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_16x_vlanportcfg_vlan4.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_24x_poeInterfaceConfiguration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_addresstable.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_lldpRemoteInventory.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_mgmtVlanIpv4Configuration.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_ports.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_portstats.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_pvid.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_sysinfo.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_vlanportcfg_vlan1.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/http/m4300_vlanstatus.html +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/snmp/gsm7252ps_fans.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/snmp/gsm7252ps_ifhighspeed.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/snmp/gsm7252ps_ifoperstatus.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/fixtures/snmp/gsm7252ps_psu.txt +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/http_specs.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/cli/test_cli_parse.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/http/test_crypt.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/http/test_endpoints.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/http/test_forms.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/http/test_parse.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/nsdp/test_auth.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/nsdp/test_parsers.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/nsdp/test_protocol.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/nsdp/test_write_frame.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/snmp/test_client.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/snmp/test_oids.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/snmp/test_parse_lldp_macs.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/snmp/test_parse_mgmt_ip.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/snmp/test_parse_poe_sensors.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/snmp/test_parse_ports.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/snmp/test_parse_system_info.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/snmp/test_parse_vlans.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/protocols/snmp/test_write_encode.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_aio_api.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_capabilities.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_cli_read.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_cli_vlan_write.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_cli_write.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_config.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_cross_backend_equivalence.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_deb_version.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_dispatch.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_errors.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_facade_equivalence.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_http_dispatch.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_http_equivalence.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_http_read.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_http_vlan_membership.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_http_write.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_http_xui_writes.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_import.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_mcp_server.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_models.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_models_snmp_read.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_nsdp_integration.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_nsdp_read.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_nsdp_write.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_public_api.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_quality_gates.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_registry.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_snmp_integration.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_snmp_read.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_snmp_write.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_sync_api.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_version.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/test_write_equivalence.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/transport/_fastpath_fake.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/transport/test_cli_console.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/transport/test_cli_scp_cert.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/transport/test_cli_telnet.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/transport/test_http_client.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/transport/test_nsdp_udp_sync.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/transport/test_set_transport.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/transport/test_snmp_netsnmp_cli.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/transport/test_snmp_pysnmp.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/transport/test_value_parity.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_cli_cross_backend.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_cli_gsm7228ps_parity.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_gsm7228ps_seed.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_m4300_seeds.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_mibview.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_mutable_state.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_nsdp_state.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_serve_daemon.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_snmp_write_face.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_state_seed.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_switchport_vlan_write.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_virtual_http_face.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_virtual_nsdp_face.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_virtual_snmp_face.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/tests/virtual/test_web_projection.py +0 -0
- {python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/uv.lock +0 -0
{python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-netgear-switch-library
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.post326
|
|
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
|
|
@@ -399,7 +399,12 @@ class BackendOperationTable(_GeneratedTable):
|
|
|
399
399
|
seen[reason] = index
|
|
400
400
|
notes.append(reason)
|
|
401
401
|
cells.append(f"{_NO} [{label}-{index}]_")
|
|
402
|
-
|
|
402
|
+
# The facade class is documented under its defining module, so a
|
|
403
|
+
# `netgear_switch.SyncSwitch.x` target does not resolve and would
|
|
404
|
+
# render as plain text rather than a link.
|
|
405
|
+
rows.append(
|
|
406
|
+
[f":py:meth:`~netgear_switch.sync_api.SyncSwitch.{op.name}`", *cells]
|
|
407
|
+
)
|
|
403
408
|
table = _list_table("", ["Operation", *keys], rows)
|
|
404
409
|
if not notes:
|
|
405
410
|
return table
|
|
@@ -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
|
|
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
|
-
|
|
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` (
|
|
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
|
|
{python_netgear_switch_library-0.0.post325 → python_netgear_switch_library-0.0.post326}/docs/conf.py
RENAMED
|
@@ -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
|
-
|
|
79
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
97
|
-
|
|
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
|
-
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
..
|
|
139
|
+
.. tab-set::
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
163
|
-
|
|
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
|
-
..
|
|
235
|
+
.. tab-set::
|
|
201
236
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
from netgear_switch.virtual.server import VirtualSwitch
|
|
237
|
+
.. tab-item:: Sync
|
|
238
|
+
:sync: sync
|
|
205
239
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
87
|
-
that operation, you get
|
|
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,
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
* -
|
|
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
|
-
* -
|
|
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
|
-
* -
|
|
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
|
-
* -
|
|
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
|
-
* -
|
|
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
|
-
* -
|
|
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*
|
|
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.
|
|
@@ -2,7 +2,7 @@ Inventories and credentials
|
|
|
2
2
|
===========================
|
|
3
3
|
|
|
4
4
|
Hosts, models and credentials belong in an inventory file, not in your code or
|
|
5
|
-
your shell history.
|
|
5
|
+
your shell history. :py:obj:`~netgear_switch.config.load_inventory` reads a TOML file into
|
|
6
6
|
``{name: SwitchConfig}``; the ``ngsw`` CLI and the MCP server both use it, via
|
|
7
7
|
the same resolver.
|
|
8
8
|
|
|
@@ -70,7 +70,7 @@ Per switch:
|
|
|
70
70
|
Secret specs
|
|
71
71
|
------------
|
|
72
72
|
|
|
73
|
-
Any value marked "secret spec" above is resolved by
|
|
73
|
+
Any value marked "secret spec" above is resolved by :py:obj:`~netgear_switch.config.resolve_secret`, which
|
|
74
74
|
accepts three forms:
|
|
75
75
|
|
|
76
76
|
.. list-table::
|
|
@@ -80,16 +80,16 @@ accepts three forms:
|
|
|
80
80
|
* - Form
|
|
81
81
|
- Behaviour
|
|
82
82
|
* - ``${NAME}``
|
|
83
|
-
- Read environment variable ``NAME``.
|
|
83
|
+
- Read environment variable ``NAME``. :py:obj:`~netgear_switch.errors.CredentialError` if unset.
|
|
84
84
|
* - ``!command args``
|
|
85
85
|
- Run the command (split with ``shlex``, no shell) and take its stdout,
|
|
86
|
-
stripped. A 10-second timeout; a non-zero exit raises
|
|
86
|
+
stripped. A 10-second timeout; a non-zero exit raises :py:obj:`~netgear_switch.errors.CredentialError`
|
|
87
87
|
with the command's stderr.
|
|
88
88
|
* - anything else
|
|
89
89
|
- The literal secret.
|
|
90
90
|
|
|
91
91
|
Prefer the first two. **If any secret in the file is a literal, the file's
|
|
92
|
-
permissions are checked** and
|
|
92
|
+
permissions are checked** and :py:obj:`~netgear_switch.config.load_inventory` raises :py:obj:`~netgear_switch.errors.ConfigError` unless the
|
|
93
93
|
file is unreadable by group and other:
|
|
94
94
|
|
|
95
95
|
.. code-block:: text
|
|
@@ -97,7 +97,7 @@ file is unreadable by group and other:
|
|
|
97
97
|
ConfigError: inventory.toml has insecure permissions 0o644; chmod 600 it
|
|
98
98
|
(contains a literal secret)
|
|
99
99
|
|
|
100
|
-
That check is
|
|
100
|
+
That check is :py:obj:`~netgear_switch.config.ensure_secure_file`, and it only fires when a literal is present
|
|
101
101
|
— a file containing only ``${VAR}`` and ``!command`` specs needs no special
|
|
102
102
|
mode.
|
|
103
103
|
|
|
@@ -136,7 +136,7 @@ Using an inventory
|
|
|
136
136
|
finally:
|
|
137
137
|
await switch.aclose()
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
:py:attr:`~netgear_switch.config.SwitchConfig.snmp_write_community` and :py:attr:`~netgear_switch.config.SwitchConfig.http_password` resolve
|
|
140
140
|
their specs on demand and take an explicit ``env=`` mapping, which makes them
|
|
141
141
|
straightforward to test.
|
|
142
142
|
|
|
@@ -177,7 +177,7 @@ Protected ports
|
|
|
177
177
|
---------------
|
|
178
178
|
|
|
179
179
|
``protected_ports`` is enforced by the library, not just the CLI. Every write
|
|
180
|
-
that names a port checks it and raises
|
|
180
|
+
that names a port checks it and raises :py:obj:`~netgear_switch.errors.ProtectedPortError` unless
|
|
181
181
|
``force=True``:
|
|
182
182
|
|
|
183
183
|
.. tab-set::
|
|
@@ -32,7 +32,7 @@ in an HTTP stack, and vice versa.
|
|
|
32
32
|
- Needed for
|
|
33
33
|
* - ``[async]``
|
|
34
34
|
- :pypi:`pysnmp`
|
|
35
|
-
- The asynchronous SNMP transport used by
|
|
35
|
+
- The asynchronous SNMP transport used by :py:obj:`~netgear_switch.aio_api.AsyncSwitch`.
|
|
36
36
|
* - ``[http]``
|
|
37
37
|
- :pypi:`httpx`
|
|
38
38
|
- Every web-UI backend, synchronous and asynchronous.
|
|
@@ -9,8 +9,8 @@ faithful mock switches, and the example points at one.
|
|
|
9
9
|
Every example below appears in **synchronous** and **asynchronous** form.
|
|
10
10
|
Choosing one switches every example on the page, and the choice is
|
|
11
11
|
remembered as you move around the site.
|
|
12
|
-
:py:class:`~netgear_switch.SyncSwitch` and
|
|
13
|
-
:py:class:`~netgear_switch.AsyncSwitch` expose the same operations with the
|
|
12
|
+
:py:class:`~netgear_switch.sync_api.SyncSwitch` and
|
|
13
|
+
:py:class:`~netgear_switch.aio_api.AsyncSwitch` expose the same operations with the
|
|
14
14
|
same arguments; only the transports differ.
|
|
15
15
|
|
|
16
16
|
Talk to a mock in-process
|
|
@@ -88,8 +88,8 @@ the switch at 10.1.5.22, not from invented values. See :doc:`../fake/index`.
|
|
|
88
88
|
Talk to a real switch
|
|
89
89
|
---------------------
|
|
90
90
|
|
|
91
|
-
The first argument is a :py:class:`~netgear_switch.SwitchModel`, which
|
|
92
|
-
:py:func:`~netgear_switch.get_model` resolves from a registry key (``ngsw
|
|
91
|
+
The first argument is a :py:class:`~netgear_switch.registry.SwitchModel`, which
|
|
92
|
+
:py:func:`~netgear_switch.registry.get_model` resolves from a registry key (``ngsw
|
|
93
93
|
models`` lists them all).
|
|
94
94
|
|
|
95
95
|
.. tab-set::
|