proxytool 0.4.0__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,107 @@
1
+ """proxytool: FastAPI proxy standing between agent clients and local model 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 ``PTP_LOG_LEVEL`` is used, falling back to ``info``.
19
+
20
+ ``quiet`` suppresses non-error app output to stderr by raising the app
21
+ logger threshold to ``error``.
22
+
23
+ This sets up a simple stderr handler so app-level log lines (server
24
+ lifecycle, loop-guard notes, toolpatch-internal debug) are emitted
25
+ consistently. Uvicorn/FastAPI server logging is still configured
26
+ separately by the CLI via ``uvicorn.run(log_level=...)``.
27
+ """
28
+ import os
29
+
30
+ from toolpatch.logging import LogLevels as _LogLevels
31
+
32
+ _tier_map: dict[str, _LogLevels | None] = {
33
+ "debug": "debug",
34
+ "info": "info",
35
+ "warning": "warning",
36
+ "error": None, # errors-only: hand toolpatch a no-op logger
37
+ }
38
+
39
+ if quiet:
40
+ effective: str = "error"
41
+ elif level:
42
+ effective = level
43
+ else:
44
+ effective = os.environ.get("PTP_LOG_LEVEL", "info")
45
+
46
+ _level = _resolve_level(effective)
47
+ _app = _logging.getLogger("proxytool")
48
+ _app.setLevel(_level)
49
+ _configure_handler(_app, _level)
50
+ _configure_handler(_logging.getLogger("toolpatch"), _level)
51
+
52
+ # toolpatch uses its own logger names; mirror the same threshold into the
53
+ # shared library so its internal debug lines are visible at the same tier.
54
+ try:
55
+ from toolpatch.logging import configure_logger as _toolpatch_configure
56
+
57
+ _toolpatch_configure("toolpatch", _tier_map.get(effective))
58
+ except Exception:
59
+ # toolpatch logging setup is best-effort; never let it break startup.
60
+ pass
61
+
62
+ # Mirror app threshold into toolpatch's shared logger too (it exposes
63
+ # ``get_logger`` which returns a stdlib logger once configured).
64
+ try:
65
+ from toolpatch import _configure_logging as _toolpatch_logging
66
+
67
+ _toolpatch_logging(level=effective, quiet=False)
68
+ except Exception:
69
+ pass
70
+
71
+
72
+ def _resolve_level(raw: str) -> int:
73
+ mapping = {
74
+ "debug": _logging.DEBUG,
75
+ "info": _logging.INFO,
76
+ "warning": _logging.WARNING,
77
+ "error": _logging.ERROR,
78
+ }
79
+ normalized = raw.strip().lower()
80
+ if normalized not in mapping:
81
+ raise ValueError(
82
+ f"unsupported log level {raw!r}; expected one of {list(mapping)}"
83
+ )
84
+ return mapping[normalized]
85
+
86
+
87
+ def _configure_handler(logger: _logging.Logger, level: int) -> None:
88
+ import sys
89
+
90
+ _ensure_handler(logger, level, stream=sys.stderr)
91
+
92
+
93
+ def _ensure_handler(logger: _logging.Logger, level: int, *, stream) -> None:
94
+ import logging as _logging
95
+
96
+ has_target = any(
97
+ isinstance(h, _logging.StreamHandler) and getattr(h, "stream", None) is stream
98
+ for h in logger.handlers
99
+ )
100
+ if has_target:
101
+ return
102
+ handler = _logging.StreamHandler(stream)
103
+ handler.setLevel(level)
104
+ handler.setFormatter(_logging.Formatter(
105
+ "%(levelname)s [%(name)s] %(message)s",
106
+ ))
107
+ 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())