snmp-query-engine 0.1.0__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 (44) hide show
  1. snmp_query_engine-0.1.0/.changes/header.tpl.md +3 -0
  2. snmp_query_engine-0.1.0/.changes/unreleased/.gitkeep +0 -0
  3. snmp_query_engine-0.1.0/.changes/v0.1.0.md +5 -0
  4. snmp_query_engine-0.1.0/.changie.yaml +38 -0
  5. snmp_query_engine-0.1.0/.github/workflows/ci.yml +62 -0
  6. snmp_query_engine-0.1.0/.github/workflows/release.yml +20 -0
  7. snmp_query_engine-0.1.0/.gitignore +23 -0
  8. snmp_query_engine-0.1.0/.python-version +1 -0
  9. snmp_query_engine-0.1.0/CHANGELOG.md +10 -0
  10. snmp_query_engine-0.1.0/LICENSE +24 -0
  11. snmp_query_engine-0.1.0/PKG-INFO +107 -0
  12. snmp_query_engine-0.1.0/README.md +81 -0
  13. snmp_query_engine-0.1.0/dist/.gitignore +1 -0
  14. snmp_query_engine-0.1.0/pyproject.toml +70 -0
  15. snmp_query_engine-0.1.0/src/sqe/__init__.py +21 -0
  16. snmp_query_engine-0.1.0/src/sqe/aio.py +284 -0
  17. snmp_query_engine-0.1.0/src/sqe/client.py +301 -0
  18. snmp_query_engine-0.1.0/src/sqe/errors.py +18 -0
  19. snmp_query_engine-0.1.0/src/sqe/protocol.py +261 -0
  20. snmp_query_engine-0.1.0/src/sqe/py.typed +0 -0
  21. snmp_query_engine-0.1.0/tests/__init__.py +0 -0
  22. snmp_query_engine-0.1.0/tests/conftest.py +37 -0
  23. snmp_query_engine-0.1.0/tests/integration/__init__.py +0 -0
  24. snmp_query_engine-0.1.0/tests/integration/conftest.py +184 -0
  25. snmp_query_engine-0.1.0/tests/integration/data/public.snmprec +8 -0
  26. snmp_query_engine-0.1.0/tests/integration/test_live.py +81 -0
  27. snmp_query_engine-0.1.0/tests/integration/test_live_reconnect.py +51 -0
  28. snmp_query_engine-0.1.0/tests/integration/test_live_v3.py +59 -0
  29. snmp_query_engine-0.1.0/tests/support.py +271 -0
  30. snmp_query_engine-0.1.0/tests/transport/__init__.py +0 -0
  31. snmp_query_engine-0.1.0/tests/transport/conftest.py +16 -0
  32. snmp_query_engine-0.1.0/tests/transport/test_aio.py +96 -0
  33. snmp_query_engine-0.1.0/tests/transport/test_client_sync.py +34 -0
  34. snmp_query_engine-0.1.0/tests/transport/test_fake_server.py +31 -0
  35. snmp_query_engine-0.1.0/tests/transport/test_scenarios.py +206 -0
  36. snmp_query_engine-0.1.0/tests/unit/__init__.py +0 -0
  37. snmp_query_engine-0.1.0/tests/unit/test_decoding.py +130 -0
  38. snmp_query_engine-0.1.0/tests/unit/test_encoding.py +83 -0
  39. snmp_query_engine-0.1.0/tests/unit/test_errors.py +50 -0
  40. snmp_query_engine-0.1.0/tests/unit/test_framing.py +46 -0
  41. snmp_query_engine-0.1.0/tests/unit/test_package.py +8 -0
  42. snmp_query_engine-0.1.0/tests/unit/test_protocol_errors.py +77 -0
  43. snmp_query_engine-0.1.0/tests/unit/test_state.py +132 -0
  44. snmp_query_engine-0.1.0/uv.lock +764 -0
@@ -0,0 +1,3 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
File without changes
@@ -0,0 +1,5 @@
1
+ ## [v0.1.0] - 2026-07-23
2
+
3
+ ### Added
4
+
5
+ - Initial release: sync and asyncio clients for the snmp-query-engine daemon
@@ -0,0 +1,38 @@
1
+ changesDir: .changes
2
+ unreleasedDir: unreleased
3
+ headerPath: header.tpl.md
4
+ changelogPath: CHANGELOG.md
5
+ versionExt: md
6
+ versionFormat: '## [{{.Version}}] - {{.Time.Format "2006-01-02"}}'
7
+ kindFormat: '### {{.Kind}}'
8
+ changeFormat: '- {{.Body}}'
9
+ kinds:
10
+ - label: Added
11
+ auto: minor
12
+ - label: Changed
13
+ auto: minor
14
+ - label: Deprecated
15
+ auto: minor
16
+ - label: Removed
17
+ auto: minor
18
+ - label: Fixed
19
+ auto: patch
20
+ - label: Security
21
+ auto: patch
22
+ newlines:
23
+ afterChangelogHeader: 1
24
+ afterChangelogVersion: 1
25
+ endOfVersion: 1
26
+ beforeKind: 1
27
+ afterKind: 1
28
+ envPrefix: CHANGIE_
29
+ replacements:
30
+ - path: pyproject.toml
31
+ find: '^version = "[^"]+"'
32
+ replace: 'version = "{{.VersionNoPrefix}}"'
33
+ - path: src/sqe/__init__.py
34
+ find: '^__version__ = "[^"]+"'
35
+ replace: '__version__ = "{{.VersionNoPrefix}}"'
36
+ - path: uv.lock
37
+ find: 'name = "snmp-query-engine"\nversion = "[^"]+"'
38
+ replace: "name = \"snmp-query-engine\"\nversion = \"{{.VersionNoPrefix}}\""
@@ -0,0 +1,62 @@
1
+ # ABOUTME: CI: lint (ruff, mypy), unit tests across Python 3.10-3.14, and an
2
+ # ABOUTME: integration job against a freshly built snmp-query-engine daemon.
3
+ name: ci
4
+
5
+ on:
6
+ push:
7
+ branches: [main]
8
+ pull_request:
9
+
10
+ jobs:
11
+ lint:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v7
15
+ - uses: astral-sh/setup-uv@v8.3.2
16
+ - name: Install dependencies
17
+ run: uv sync --locked
18
+ - name: ruff lint
19
+ run: uv run ruff check .
20
+ - name: ruff format
21
+ run: uv run ruff format --check .
22
+ - name: mypy
23
+ run: uv run mypy
24
+
25
+ unit:
26
+ strategy:
27
+ fail-fast: false
28
+ matrix:
29
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
30
+ runs-on: ubuntu-latest
31
+ steps:
32
+ - uses: actions/checkout@v7
33
+ - uses: astral-sh/setup-uv@v8.3.2
34
+ with:
35
+ python-version: ${{ matrix.python-version }}
36
+ - name: Install dependencies
37
+ run: uv sync --locked
38
+ - name: Run unit and transport tests
39
+ run: uv run pytest -m "not integration"
40
+
41
+ integration:
42
+ runs-on: ubuntu-latest
43
+ steps:
44
+ - uses: actions/checkout@v7
45
+ - uses: actions/checkout@v7
46
+ with:
47
+ repository: tobez/snmp-query-engine
48
+ path: snmp-query-engine
49
+ - name: Install daemon build dependencies
50
+ run: |
51
+ sudo apt-get update
52
+ sudo apt-get install -y libjudy-dev libssl-dev \
53
+ $(apt-cache -q0 show libmsgpack-c-dev >/dev/null 2>&1 && echo libmsgpack-c-dev || echo libmsgpack-dev)
54
+ - name: Build the daemon
55
+ run: make -C snmp-query-engine snmp-query-engine
56
+ - uses: astral-sh/setup-uv@v8.3.2
57
+ - name: Install dependencies
58
+ run: uv sync --locked
59
+ - name: Run integration tests
60
+ env:
61
+ SQE_BINARY: ${{ github.workspace }}/snmp-query-engine/snmp-query-engine
62
+ run: uv run pytest -m integration
@@ -0,0 +1,20 @@
1
+ # ABOUTME: Release workflow: on v* tag push, builds sdist+wheel and publishes
2
+ # ABOUTME: to PyPI via trusted publishing (OIDC).
3
+ name: release
4
+
5
+ on:
6
+ push:
7
+ tags: ['v*']
8
+
9
+ jobs:
10
+ pypi:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ id-token: write
14
+ steps:
15
+ - uses: actions/checkout@v7
16
+ - uses: astral-sh/setup-uv@v8.3.2
17
+ - name: Build distributions
18
+ run: uv build
19
+ - name: Publish to PyPI
20
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,23 @@
1
+ # Hidden files and directories, except those explicitly tracked below.
2
+ # Note: any future dotfile that should be tracked needs its own ! entry here.
3
+ .*
4
+ !.gitignore
5
+ !.github/
6
+ !.changie.yaml
7
+ !.changes/
8
+ !.changes/unreleased/.gitkeep
9
+ !.python-version
10
+
11
+ # Python
12
+ __pycache__/
13
+ *.py[cod]
14
+ *$py.class
15
+
16
+ # Packaging / build
17
+ build/
18
+ dist/
19
+ *.egg-info/
20
+
21
+ # Test / coverage
22
+ htmlcov/
23
+ coverage.xml
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [v0.1.0] - 2026-07-23
6
+
7
+ ### Added
8
+
9
+ - Initial release: sync and asyncio clients for the snmp-query-engine daemon
10
+
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2026, Anton Berezin <tobez@tobez.org>
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
+ POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,107 @@
1
+ Metadata-Version: 2.4
2
+ Name: snmp-query-engine
3
+ Version: 0.1.0
4
+ Summary: Client library for the snmp-query-engine SNMP query daemon
5
+ Project-URL: Homepage, https://github.com/tobez/sqe-python
6
+ Project-URL: Changelog, https://github.com/tobez/sqe-python/blob/main/CHANGELOG.md
7
+ Author-email: Anton Berezin <tobez@tobez.org>
8
+ License-Expression: BSD-2-Clause
9
+ License-File: LICENSE
10
+ Keywords: monitoring,msgpack,snmp
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: System Administrators
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: System :: Networking :: Monitoring
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: msgpack>=1.0
25
+ Description-Content-Type: text/markdown
26
+
27
+ # snmp-query-engine (Python client)
28
+
29
+ Python client library for the
30
+ [snmp-query-engine](https://github.com/tobez/snmp-query-engine) daemon — a
31
+ multiplexing SNMP query engine that performs throttled SNMP queries towards
32
+ many destinations on behalf of its clients.
33
+
34
+ Distribution name `snmp-query-engine`, import name `sqe`.
35
+
36
+ ```sh
37
+ pip install snmp-query-engine # or: uv add snmp-query-engine
38
+ ```
39
+
40
+ ## Synchronous client
41
+
42
+ ```python
43
+ import sqe
44
+
45
+ with sqe.Client() as c: # daemon on 127.0.0.1:7667
46
+ c.setopt("10.0.0.1", 161, {"community": "secret", "version": 2})
47
+ for vb in c.get("10.0.0.1", 161, ["1.3.6.1.2.1.1.5.0"]):
48
+ print(vb.oid, vb.value if vb.ok else f"error: {vb.error}")
49
+ for vb in c.gettable("10.0.0.1", 161, "1.3.6.1.2.1.2.2.1.2"):
50
+ print(vb.oid, vb.value)
51
+ ```
52
+
53
+ The client is thread-safe; call it from a thread pool for concurrency.
54
+
55
+ ## asyncio client
56
+
57
+ ```python
58
+ import asyncio
59
+ import sqe
60
+
61
+ async def main():
62
+ async with sqe.AsyncClient() as c:
63
+ vbs = await c.get("10.0.0.1", 161, ["1.3.6.1.2.1.1.5.0"])
64
+ print(vbs[0].value)
65
+
66
+ asyncio.run(main())
67
+ ```
68
+
69
+ Both clients expose the same six methods: `setopt`, `getopt`, `get`,
70
+ `gettable`, `info`, `dest_info`. See the
71
+ [daemon manual](https://github.com/tobez/snmp-query-engine/blob/main/manual.mdwn)
72
+ for the available options and the semantics behind them.
73
+
74
+ ## Semantics worth knowing
75
+
76
+ - **Values are msgpack-native.** SNMP string values arrive as `bytes`
77
+ (they are genuinely binary); OIDs, map keys, and error strings are `str`.
78
+ - **Per-OID errors are values, not exceptions**: check `VarBind.ok` /
79
+ `VarBind.error`. Request-level daemon errors raise `sqe.RequestError`.
80
+ - **Reconnect is automatic by default**: on connection loss, in-flight
81
+ requests fail with `sqe.ConnectionLost`, the client reconnects with
82
+ capped exponential backoff, replays your accumulated `setopt` options,
83
+ and only then releases new traffic. Opt out with `reconnect=False`.
84
+ - **Per-call safety timeout**: every method takes `timeout=` (seconds) as a
85
+ guard against a wedged daemon; `None` (default) trusts the daemon's own
86
+ timeout/retry machinery, which always answers eventually.
87
+ - **SETOPT options pass through verbatim** as a dict, named exactly as in
88
+ the daemon manual. Convenience: `bytes` values for the hexstring options
89
+ (`engineid`, `authkul`, `privkul`) are hex-encoded automatically.
90
+
91
+ ## Development
92
+
93
+ ```sh
94
+ uv sync
95
+ uv run pytest # unit + transport tiers
96
+ uv run pytest -m integration # live tier: needs a daemon binary
97
+ # ($SQE_BINARY, PATH, or ../snmp-query-engine)
98
+ uv run ruff check . && uv run mypy
99
+ ```
100
+
101
+ The sans-I/O protocol core lives in `sqe/protocol.py`; alternative event
102
+ loops (trio, ...) can drive it directly.
103
+
104
+ ## License
105
+
106
+ BSD 2-clause, matching the daemon and the Perl client
107
+ [Net::SNMP::QueryEngine::AnyEvent](https://metacpan.org/pod/Net::SNMP::QueryEngine::AnyEvent).
@@ -0,0 +1,81 @@
1
+ # snmp-query-engine (Python client)
2
+
3
+ Python client library for the
4
+ [snmp-query-engine](https://github.com/tobez/snmp-query-engine) daemon — a
5
+ multiplexing SNMP query engine that performs throttled SNMP queries towards
6
+ many destinations on behalf of its clients.
7
+
8
+ Distribution name `snmp-query-engine`, import name `sqe`.
9
+
10
+ ```sh
11
+ pip install snmp-query-engine # or: uv add snmp-query-engine
12
+ ```
13
+
14
+ ## Synchronous client
15
+
16
+ ```python
17
+ import sqe
18
+
19
+ with sqe.Client() as c: # daemon on 127.0.0.1:7667
20
+ c.setopt("10.0.0.1", 161, {"community": "secret", "version": 2})
21
+ for vb in c.get("10.0.0.1", 161, ["1.3.6.1.2.1.1.5.0"]):
22
+ print(vb.oid, vb.value if vb.ok else f"error: {vb.error}")
23
+ for vb in c.gettable("10.0.0.1", 161, "1.3.6.1.2.1.2.2.1.2"):
24
+ print(vb.oid, vb.value)
25
+ ```
26
+
27
+ The client is thread-safe; call it from a thread pool for concurrency.
28
+
29
+ ## asyncio client
30
+
31
+ ```python
32
+ import asyncio
33
+ import sqe
34
+
35
+ async def main():
36
+ async with sqe.AsyncClient() as c:
37
+ vbs = await c.get("10.0.0.1", 161, ["1.3.6.1.2.1.1.5.0"])
38
+ print(vbs[0].value)
39
+
40
+ asyncio.run(main())
41
+ ```
42
+
43
+ Both clients expose the same six methods: `setopt`, `getopt`, `get`,
44
+ `gettable`, `info`, `dest_info`. See the
45
+ [daemon manual](https://github.com/tobez/snmp-query-engine/blob/main/manual.mdwn)
46
+ for the available options and the semantics behind them.
47
+
48
+ ## Semantics worth knowing
49
+
50
+ - **Values are msgpack-native.** SNMP string values arrive as `bytes`
51
+ (they are genuinely binary); OIDs, map keys, and error strings are `str`.
52
+ - **Per-OID errors are values, not exceptions**: check `VarBind.ok` /
53
+ `VarBind.error`. Request-level daemon errors raise `sqe.RequestError`.
54
+ - **Reconnect is automatic by default**: on connection loss, in-flight
55
+ requests fail with `sqe.ConnectionLost`, the client reconnects with
56
+ capped exponential backoff, replays your accumulated `setopt` options,
57
+ and only then releases new traffic. Opt out with `reconnect=False`.
58
+ - **Per-call safety timeout**: every method takes `timeout=` (seconds) as a
59
+ guard against a wedged daemon; `None` (default) trusts the daemon's own
60
+ timeout/retry machinery, which always answers eventually.
61
+ - **SETOPT options pass through verbatim** as a dict, named exactly as in
62
+ the daemon manual. Convenience: `bytes` values for the hexstring options
63
+ (`engineid`, `authkul`, `privkul`) are hex-encoded automatically.
64
+
65
+ ## Development
66
+
67
+ ```sh
68
+ uv sync
69
+ uv run pytest # unit + transport tiers
70
+ uv run pytest -m integration # live tier: needs a daemon binary
71
+ # ($SQE_BINARY, PATH, or ../snmp-query-engine)
72
+ uv run ruff check . && uv run mypy
73
+ ```
74
+
75
+ The sans-I/O protocol core lives in `sqe/protocol.py`; alternative event
76
+ loops (trio, ...) can drive it directly.
77
+
78
+ ## License
79
+
80
+ BSD 2-clause, matching the daemon and the Perl client
81
+ [Net::SNMP::QueryEngine::AnyEvent](https://metacpan.org/pod/Net::SNMP::QueryEngine::AnyEvent).
@@ -0,0 +1 @@
1
+ *
@@ -0,0 +1,70 @@
1
+ [project]
2
+ name = "snmp-query-engine"
3
+ version = "0.1.0"
4
+ description = "Client library for the snmp-query-engine SNMP query daemon"
5
+ readme = "README.md"
6
+ authors = [{ name = "Anton Berezin", email = "tobez@tobez.org" }]
7
+ license = "BSD-2-Clause"
8
+ license-files = ["LICENSE"]
9
+ requires-python = ">=3.10"
10
+ dependencies = [
11
+ "msgpack>=1.0",
12
+ ]
13
+ keywords = ["snmp", "monitoring", "msgpack"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "Intended Audience :: System Administrators",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
25
+ "Topic :: System :: Networking :: Monitoring",
26
+ "Typing :: Typed",
27
+ ]
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/tobez/sqe-python"
31
+ Changelog = "https://github.com/tobez/sqe-python/blob/main/CHANGELOG.md"
32
+
33
+ [build-system]
34
+ requires = ["hatchling"]
35
+ build-backend = "hatchling.build"
36
+
37
+ [tool.hatch.build.targets.wheel]
38
+ packages = ["src/sqe"]
39
+
40
+ [dependency-groups]
41
+ dev = [
42
+ "mypy>=2.2.0",
43
+ "pysmi>=2.0.0",
44
+ "pytest>=9.1.1",
45
+ "ruff>=0.15.20",
46
+ "snmpsim>=1.2.2",
47
+ ]
48
+
49
+ [tool.uv]
50
+ exclude-newer = "7 days"
51
+
52
+ [tool.pytest.ini_options]
53
+ testpaths = ["tests"]
54
+ addopts = "-ra"
55
+ markers = ["integration: tests requiring a live snmp-query-engine daemon"]
56
+
57
+ [tool.ruff]
58
+ line-length = 100
59
+ target-version = "py310"
60
+
61
+ [tool.ruff.lint]
62
+ select = ["E", "F", "W", "I", "UP", "B"]
63
+
64
+ [tool.mypy]
65
+ strict = true
66
+ files = ["src"]
67
+
68
+ [[tool.mypy.overrides]]
69
+ module = "msgpack"
70
+ ignore_missing_imports = true
@@ -0,0 +1,21 @@
1
+ # ABOUTME: Public package surface for the snmp-query-engine client library.
2
+ # ABOUTME: Re-exports the clients, VarBind, and the exception hierarchy.
3
+ """Python client library for the snmp-query-engine daemon."""
4
+
5
+ from .aio import AsyncClient
6
+ from .client import Client
7
+ from .errors import ConnectionLost, ProtocolError, RequestError, SqeError
8
+ from .protocol import VarBind
9
+
10
+ __version__ = "0.1.0"
11
+
12
+ __all__ = [
13
+ "AsyncClient",
14
+ "Client",
15
+ "ConnectionLost",
16
+ "ProtocolError",
17
+ "RequestError",
18
+ "SqeError",
19
+ "VarBind",
20
+ "__version__",
21
+ ]