proxytool 2.0.1__py3-none-any.whl

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.
proxytool/__init__.py ADDED
@@ -0,0 +1,108 @@
1
+ """proxytool: FastAPI middleware conduit standing between agent clients and Qwen servers."""
2
+
3
+ import logging as _logging
4
+ from importlib.metadata import PackageNotFoundError
5
+ from importlib.metadata import version as _metadata_version
6
+
7
+ try:
8
+ __version__: str = _metadata_version("proxytool")
9
+ except PackageNotFoundError: # unbuilt dev checkout
10
+ __version__ = "0.0.0.dev0+local"
11
+
12
+
13
+ def configure_logging(*, level: str | None = None, quiet: bool = False) -> None:
14
+ """Configure app-level logging for proxytool modules.
15
+
16
+ ``level`` selects the app logger threshold from the standard tiers
17
+ ``debug``, ``info``, ``warning``, or ``error``. When omitted the
18
+ environment variable ``LTP_LOG_LEVEL`` (or its legacy ``LMW_LOG_LEVEL``
19
+ spelling) is used, falling back to ``info``.
20
+
21
+ ``quiet`` suppresses non-error app output to stderr by raising the app
22
+ logger threshold to ``error``.
23
+
24
+ This sets up a simple stderr handler so app-level log lines (server
25
+ lifecycle, loop-guard notes, toolpatch-internal debug) are emitted
26
+ consistently. Uvicorn/FastAPI server logging is still configured
27
+ separately by the CLI via ``uvicorn.run(log_level=...)``.
28
+ """
29
+ import os
30
+
31
+ from toolpatch.logging import LogLevels as _LogLevels
32
+
33
+ _tier_map: dict[str, _LogLevels | None] = {
34
+ "debug": "debug",
35
+ "info": "info",
36
+ "warning": "warning",
37
+ "error": None, # errors-only: hand toolpatch a no-op logger
38
+ }
39
+
40
+ if quiet:
41
+ effective: str = "error"
42
+ elif level:
43
+ effective = level
44
+ else:
45
+ effective = os.environ.get("LTP_LOG_LEVEL") or os.environ.get("LMW_LOG_LEVEL") or "info"
46
+
47
+ _level = _resolve_level(effective)
48
+ _app = _logging.getLogger("proxytool")
49
+ _app.setLevel(_level)
50
+ _configure_handler(_app, _level)
51
+ _configure_handler(_logging.getLogger("toolpatch"), _level)
52
+
53
+ # toolpatch uses its own logger names; mirror the same threshold into the
54
+ # shared library so its internal debug lines are visible at the same tier.
55
+ try:
56
+ from toolpatch.logging import configure_logger as _toolpatch_configure
57
+
58
+ _toolpatch_configure("toolpatch", _tier_map.get(effective))
59
+ except Exception:
60
+ # toolpatch logging setup is best-effort; never let it break startup.
61
+ pass
62
+
63
+ # Mirror app threshold into toolpatch's shared logger too (it exposes
64
+ # ``get_logger`` which returns a stdlib logger once configured).
65
+ try:
66
+ from toolpatch import _configure_logging as _toolpatch_logging
67
+
68
+ _toolpatch_logging(level=effective, quiet=False)
69
+ except Exception:
70
+ pass
71
+
72
+
73
+ def _resolve_level(raw: str) -> int:
74
+ mapping = {
75
+ "debug": _logging.DEBUG,
76
+ "info": _logging.INFO,
77
+ "warning": _logging.WARNING,
78
+ "error": _logging.ERROR,
79
+ }
80
+ normalized = raw.strip().lower()
81
+ if normalized not in mapping:
82
+ raise ValueError(
83
+ f"unsupported log level {raw!r}; expected one of {list(mapping)}"
84
+ )
85
+ return mapping[normalized]
86
+
87
+
88
+ def _configure_handler(logger: _logging.Logger, level: int) -> None:
89
+ import sys
90
+
91
+ _ensure_handler(logger, level, stream=sys.stderr)
92
+
93
+
94
+ def _ensure_handler(logger: _logging.Logger, level: int, *, stream) -> None:
95
+ import logging as _logging
96
+
97
+ has_target = any(
98
+ isinstance(h, _logging.StreamHandler) and getattr(h, "stream", None) is stream
99
+ for h in logger.handlers
100
+ )
101
+ if has_target:
102
+ return
103
+ handler = _logging.StreamHandler(stream)
104
+ handler.setLevel(level)
105
+ handler.setFormatter(_logging.Formatter(
106
+ "%(levelname)s [%(name)s] %(message)s",
107
+ ))
108
+ logger.addHandler(handler)
proxytool/__main__.py ADDED
@@ -0,0 +1,14 @@
1
+ """`python -m proxytool`: delegate to the ``proxytool`` CLI.
2
+
3
+ Previously this started a dev server unconditionally (ignoring args), which
4
+ made `python -m proxytool --help` launch uvicorn. Now it forwards to the same
5
+ argparse CLI the console script uses; the dev-reload workflow is
6
+ `uv run uvicorn proxytool.main:app --reload` (as documented in the README).
7
+ """
8
+
9
+ import sys
10
+
11
+ from proxytool.cli import main
12
+
13
+ if __name__ == "__main__":
14
+ sys.exit(main())