mirror of
https://github.com/VectifyAI/PageIndex.git
synced 2026-05-13 00:32:36 +02:00
* feat:compatible with Pageindex SDK
* corner cases fixed
* fix: mock behavior of old SDK
* fix: close streaming response and warn on empty api_key
- LegacyCloudAPI: close response in `finally` for both _stream_chat_response
variants so abandoned iterators no longer leak the TCP connection.
- PageIndexClient: emit a warning instead of silently falling back to local
when api_key is the empty string, surfacing typical env-var-unset misconfig.
- FakeResponse: add close()/closed to match the real requests.Response API.
- Add unit coverage for stream close (both paths) and the empty-api_key warning.
- Add scripts/e2e_legacy_sdk.py to smoke-test the legacy SDK contract end-to-end
against api.pageindex.ai.
* chore: mark legacy SDK methods with @deprecated and docstring pointers
- Decorate the 12 PageIndexClient cloud-SDK compat methods with
@typing_extensions.deprecated(..., category=PendingDeprecationWarning):
- IDE/type-checkers render them with a strikethrough hint
- runtime warnings stay silent by default (no spam for existing callers),
surfaceable via `python -W default::PendingDeprecationWarning`
- Add a one-line docstring on each pointing to the Collection-based equivalent.
- Promote typing-extensions to a direct dependency (was transitive via litellm).
---------
Co-authored-by: XinyanZhou <xinyanzhou@XinyanZhoudeMacBook-Pro.local>
Co-authored-by: saccharin98 <xinyanzhou938@gmail.com>
Co-authored-by: mountain <kose2livs@gmail.com>
106 lines
3 KiB
Python
106 lines
3 KiB
Python
import sys
|
|
import asyncio
|
|
from types import SimpleNamespace
|
|
|
|
from pageindex import utils
|
|
|
|
|
|
def test_remove_fields_keeps_legacy_max_len():
|
|
data = {
|
|
"title": "A long title",
|
|
"text": "hidden",
|
|
"nodes": [{"summary": "abcdefghijklmnopqrstuvwxyz"}],
|
|
}
|
|
|
|
result = utils.remove_fields(data, fields=["text"], max_len=5)
|
|
|
|
assert "text" not in result
|
|
assert result["title"] == "A lon..."
|
|
assert result["nodes"][0]["summary"] == "abcde..."
|
|
|
|
|
|
def test_create_node_mapping_keeps_legacy_page_ranges():
|
|
tree = [
|
|
{
|
|
"node_id": "0001",
|
|
"title": "Root",
|
|
"page_index": 1,
|
|
"nodes": [
|
|
{"node_id": "0002", "title": "Child", "page_index": 3, "nodes": []},
|
|
],
|
|
}
|
|
]
|
|
|
|
plain = utils.create_node_mapping(tree)
|
|
ranged = utils.create_node_mapping(tree, include_page_ranges=True, max_page=8)
|
|
|
|
assert plain["0001"]["title"] == "Root"
|
|
assert ranged["0001"]["start_index"] == 1
|
|
assert ranged["0001"]["end_index"] == 3
|
|
assert ranged["0002"]["start_index"] == 3
|
|
assert ranged["0002"]["end_index"] == 8
|
|
|
|
|
|
def test_create_node_mapping_prefers_existing_start_end_ranges():
|
|
tree = [
|
|
{
|
|
"node_id": "0001",
|
|
"title": "Root",
|
|
"start_index": 1,
|
|
"end_index": 10,
|
|
"nodes": [
|
|
{"node_id": "0002", "title": "Child", "start_index": 3, "end_index": 5},
|
|
],
|
|
}
|
|
]
|
|
|
|
ranged = utils.create_node_mapping(tree, include_page_ranges=True, max_page=12)
|
|
|
|
assert ranged["0001"]["start_index"] == 1
|
|
assert ranged["0001"]["end_index"] == 10
|
|
assert ranged["0002"]["start_index"] == 3
|
|
assert ranged["0002"]["end_index"] == 5
|
|
|
|
|
|
def test_print_tree_keeps_legacy_exclude_fields(capsys):
|
|
tree = [{"node_id": "0001", "title": "Root", "text": "hidden", "page_index": 1}]
|
|
|
|
utils.print_tree(tree)
|
|
|
|
out = capsys.readouterr().out
|
|
assert "Root" in out
|
|
assert "hidden" not in out
|
|
assert "page_index" not in out
|
|
|
|
|
|
def test_call_llm_keeps_legacy_async_openai_contract(monkeypatch):
|
|
calls = []
|
|
|
|
class FakeCompletions:
|
|
async def create(self, **kwargs):
|
|
calls.append(kwargs)
|
|
message = SimpleNamespace(content=" answer ")
|
|
choice = SimpleNamespace(message=message)
|
|
return SimpleNamespace(choices=[choice])
|
|
|
|
class FakeAsyncOpenAI:
|
|
def __init__(self, api_key):
|
|
self.api_key = api_key
|
|
self.chat = SimpleNamespace(completions=FakeCompletions())
|
|
|
|
fake_openai = SimpleNamespace(AsyncOpenAI=FakeAsyncOpenAI)
|
|
monkeypatch.setitem(sys.modules, "openai", fake_openai)
|
|
|
|
result = asyncio.run(utils.call_llm(
|
|
"hello",
|
|
api_key="sk-test",
|
|
model="gpt-test",
|
|
temperature=0.2,
|
|
))
|
|
|
|
assert result == "answer"
|
|
assert calls == [{
|
|
"model": "gpt-test",
|
|
"messages": [{"role": "user", "content": "hello"}],
|
|
"temperature": 0.2,
|
|
}]
|