mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-09 08:18:12 +00:00
* refactor(router): move litellm/router.py to litellm/router_python_core.py A pure rename with no content change, so git and review tools track the router body as a move. The next commit turns it into PythonCore and adds the Router facade back at litellm/router.py * refactor(router): extract PythonCore behind RouterCore and pass the router its config The routing logic moves unchanged from litellm/router.py into PythonCore in litellm/router_python_core.py. Router becomes a facade that builds a RouterConfig, picks a RouterCore with make_core and delegates every member to it. The core no longer reads or writes litellm.* directly: process settings come from RouterDynamicConfig, and inference calls, sleeps, callback lists and the global cache go through PythonHost. A CI check bans litellm.* in the router modules, and the proxy's construction sites build the config outside the router Settings are static: the constructor arguments and changeset values are copied when the router is built or the change applied, and a write to a setting attribute becomes apply(ChangeSet(assign=...)). A Router subclass's core class also subclasses the facade, so an override's super(Sub, self) works, and an instance-level patch of a core method is kept on the facade so nested patches unwind. tests/unit/test_router/core tests the core in isolation: ScriptedHost serves every host operation (scripted inference answers, recorded sleeps, settings, callbacks, cache), and make_core runs each test once per core in CORE_BUILDERS
54 lines
1.9 KiB
Python
54 lines
1.9 KiB
Python
"""
|
|
The router and its cores never read or write ``litellm.*``.
|
|
|
|
Process settings reach the router through ``RouterDynamicConfig`` (litellm/router_config.py) and
|
|
everything else outside it (inference calls, callbacks, the global cache) through ``PythonHost``
|
|
(litellm/router_python_host.py). Those two modules are the only router code allowed to touch the
|
|
``litellm`` package namespace. This check fails on ``import litellm`` (or ``import litellm.<x>``,
|
|
which binds the same name) and on any ``litellm.<attr>`` access in the files below.
|
|
|
|
Run: python tests/code_coverage_tests/router_litellm_globals_check.py
|
|
"""
|
|
|
|
import ast
|
|
import os
|
|
import sys
|
|
|
|
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
|
CHECKED = (
|
|
"litellm/router.py",
|
|
"litellm/router_api.py",
|
|
"litellm/router_core.py",
|
|
"litellm/router_deprecated.py",
|
|
"litellm/router_python_core.py",
|
|
)
|
|
|
|
|
|
def violations(rel: str) -> list[str]:
|
|
tree = ast.parse(open(os.path.join(ROOT, rel)).read(), rel)
|
|
found = []
|
|
for node in ast.walk(tree):
|
|
if isinstance(node, ast.Import):
|
|
found.extend(
|
|
f"{rel}:{node.lineno}: import {alias.name}"
|
|
for alias in node.names
|
|
if alias.asname is None and (alias.name == "litellm" or alias.name.startswith("litellm."))
|
|
)
|
|
elif isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name) and node.value.id == "litellm":
|
|
found.append(f"{rel}:{node.lineno}: litellm.{node.attr}")
|
|
return found
|
|
|
|
|
|
def main() -> int:
|
|
found = [line for rel in CHECKED for line in violations(rel)]
|
|
for line in found:
|
|
print(line)
|
|
if found:
|
|
print(f"{len(found)} litellm.* uses in router modules; read settings from RouterDynamicConfig and use PythonHost")
|
|
return 1
|
|
print("router modules use no litellm.* globals")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|