elastro-client 1.3.34__tar.gz → 1.3.37__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.
- {elastro_client-1.3.34/elastro_client.egg-info → elastro_client-1.3.37}/PKG-INFO +1 -1
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/__init__.py +1 -1
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/cli.py +33 -1
- elastro_client-1.3.37/elastro/cli/commands/daemon.py +60 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/client.py +1 -0
- elastro_client-1.3.37/elastro/core/daemon.py +132 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/document.py +2 -2
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/document_bulk.py +2 -2
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/rag/ast_parser.py +1 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/rag/ingestor.py +0 -1
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/validation.py +1 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/server.py +5 -5
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/utils/aliases.py +6 -6
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/utils/health.py +2 -1
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/utils/snapshots.py +1 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37/elastro_client.egg-info}/PKG-INFO +1 -1
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro_client.egg-info/SOURCES.txt +2 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/pyproject.toml +12 -4
- {elastro_client-1.3.34 → elastro_client-1.3.37}/.coveragerc +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/LICENSE +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/MANIFEST.in +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/README.md +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/docs/advanced_features.md +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/docs/api_reference.md +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/docs/cli_usage.md +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/docs/commands_reference.md +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/docs/getting_started.md +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/docs/roadmap.md +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/docs/troubleshooting.md +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/advanced/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/advanced/aggregations.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/advanced/query_builder.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/advanced/scroll.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/art.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/cluster.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/config.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/datastream.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/document.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/gui.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/ilm.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/index.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/index_recipes.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/ingest.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/ml.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/painless_commands.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/rag.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/script.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/security.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/snapshot.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/tasks.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/template.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/commands/utils.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/completion.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/cli/output.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/config/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/config/defaults.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/config/loader.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/datastream.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/errors.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/ilm.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/index.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/logger.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/query_builder.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/core/snapshot.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/gui/assets/index-CeUjjtn-.css +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/gui/assets/index-DNdGuJvV.js +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/gui/elastro.svg +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/gui/favicon.ico +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/gui/index.html +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/gui/vite.svg +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/py.typed +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/utils/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro/utils/templates.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro_client.egg-info/dependency_links.txt +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro_client.egg-info/entry_points.txt +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro_client.egg-info/requires.txt +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/elastro_client.egg-info/top_level.txt +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/examples/client.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/examples/config_usage.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/examples/datastreams.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/examples/debug_connection.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/examples/document_operations.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/examples/index_management.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/examples/search.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/pytest.ini +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/requirements.txt +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/setup.cfg +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/setup.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/conftest.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/fixtures/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/fixtures/datastream_fixtures.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/fixtures/document_fixtures.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/fixtures/index_fixtures.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_aggregations_integration.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_client_integration.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_datastream_integration.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_docs_quickstart.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_document_integration.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_index_integration.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_query_builder_integration.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_scroll_integration.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_workflow_integration.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/manual/test_es.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/advanced/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/advanced/test_aggregations.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/advanced/test_query_builder.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/advanced/test_scroll.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/config/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/config/test_defaults.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/config/test_loader.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/core/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/core/test_client.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/core/test_datastream.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/core/test_document.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/core/test_document_bulk.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/core/test_errors.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/core/test_index.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/core/test_validation.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/utils/__init__.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/utils/test_aliases.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/utils/test_health.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/utils/test_snapshots.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/unit/utils/test_templates.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/verify_api_actions.py +0 -0
- {elastro_client-1.3.34 → elastro_client-1.3.37}/tests/verify_cli_e2e.py +0 -0
|
@@ -4,10 +4,40 @@ Command-line interface main module.
|
|
|
4
4
|
This module defines the main CLI structure using Click.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
# --- FAST PATH INTERCEPTOR ---
|
|
10
|
+
# Must run before any other heavy imports to avoid the ~214ms startup penalty
|
|
11
|
+
if len(sys.argv) >= 3 and sys.argv[1] == "doc" and sys.argv[2] == "search":
|
|
12
|
+
# Only use the fast path if '--help' is not requested
|
|
13
|
+
if "--help" not in sys.argv and "-h" not in sys.argv:
|
|
14
|
+
try:
|
|
15
|
+
import json
|
|
16
|
+
import urllib.request
|
|
17
|
+
from http.client import HTTPResponse
|
|
18
|
+
from typing import cast, Dict, Any
|
|
19
|
+
|
|
20
|
+
req = urllib.request.Request(
|
|
21
|
+
"http://127.0.0.1:9201/fast-path/doc/search",
|
|
22
|
+
data=json.dumps({"args": sys.argv[3:]}).encode("utf-8"),
|
|
23
|
+
headers={"Content-Type": "application/json"},
|
|
24
|
+
method="POST",
|
|
25
|
+
)
|
|
26
|
+
with urllib.request.urlopen(req, timeout=0.05) as _response:
|
|
27
|
+
response = cast(HTTPResponse, _response)
|
|
28
|
+
if getattr(response, "status", 0) == 200:
|
|
29
|
+
print(response.read().decode("utf-8"), end="")
|
|
30
|
+
sys.exit(0)
|
|
31
|
+
except Exception:
|
|
32
|
+
# If the daemon is offline or crashes, silently fall through
|
|
33
|
+
# to the normal heavy Click execution.
|
|
34
|
+
pass
|
|
35
|
+
# --- END FAST PATH INTERCEPTOR ---
|
|
36
|
+
|
|
7
37
|
import os
|
|
8
|
-
import rich_click as click
|
|
9
38
|
import json
|
|
10
39
|
import yaml
|
|
40
|
+
import rich_click as click
|
|
11
41
|
from typing import Dict, Any, Optional, List, Union
|
|
12
42
|
from rich.console import Console
|
|
13
43
|
from rich.table import Table
|
|
@@ -245,6 +275,7 @@ utils.add_command(aliases)
|
|
|
245
275
|
|
|
246
276
|
from elastro.cli.commands.gui import gui
|
|
247
277
|
from elastro.cli.commands.rag import rag_group
|
|
278
|
+
from elastro.cli.commands.daemon import daemon_group
|
|
248
279
|
|
|
249
280
|
# Register Top-Level Groups
|
|
250
281
|
cli.add_command(template_group)
|
|
@@ -259,6 +290,7 @@ cli.add_command(script_group)
|
|
|
259
290
|
cli.add_command(painless_group)
|
|
260
291
|
cli.add_command(gui)
|
|
261
292
|
cli.add_command(rag_group)
|
|
293
|
+
cli.add_command(daemon_group)
|
|
262
294
|
|
|
263
295
|
|
|
264
296
|
def main() -> None:
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Daemon management commands.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
# fmt: off
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
import urllib.request
|
|
9
|
+
|
|
10
|
+
import rich_click as click
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.group("daemon")
|
|
14
|
+
def daemon_group() -> None:
|
|
15
|
+
"""
|
|
16
|
+
Manage the Fast-Path Agentic Daemon.
|
|
17
|
+
"""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@daemon_group.command("start")
|
|
22
|
+
@click.option("--port", type=int, default=9201, help="Port to run the daemon on")
|
|
23
|
+
@click.option(
|
|
24
|
+
"--host", type=str, default="127.0.0.1", help="Host to bind the daemon to"
|
|
25
|
+
)
|
|
26
|
+
def start(port: int, host: str) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Start the Fast-Path CLI Daemon.
|
|
29
|
+
|
|
30
|
+
Keeps the Elasticsearch connection hot in memory so subsequent agents querying via
|
|
31
|
+
'elastro doc search' will bypass the slow Python startup sequence.
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
from elastro.core.daemon import start_daemon
|
|
35
|
+
|
|
36
|
+
click.echo(f"Starting Elastro Daemon on {host}:{port}...")
|
|
37
|
+
start_daemon(host=host, port=port)
|
|
38
|
+
except ImportError as e:
|
|
39
|
+
click.echo(f"Failed to load daemon dependencies: {e}", err=True)
|
|
40
|
+
sys.exit(1)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@daemon_group.command("status")
|
|
44
|
+
@click.option("--port", type=int, default=9201, help="Port the daemon is running on")
|
|
45
|
+
def status(port: int) -> None:
|
|
46
|
+
"""Check if the Daemon is active."""
|
|
47
|
+
try:
|
|
48
|
+
import urllib.request
|
|
49
|
+
from http.client import HTTPResponse
|
|
50
|
+
from typing import cast
|
|
51
|
+
|
|
52
|
+
req = urllib.request.Request(f"http://127.0.0.1:{port}/health")
|
|
53
|
+
with urllib.request.urlopen(req, timeout=1.0) as _response:
|
|
54
|
+
response = cast(HTTPResponse, _response)
|
|
55
|
+
if getattr(response, "status", 0) == 200:
|
|
56
|
+
click.echo("Daemon is ONLINE and responding.")
|
|
57
|
+
else:
|
|
58
|
+
click.echo(f"Daemon returned status: {getattr(response, 'status', 'unknown')}")
|
|
59
|
+
except Exception as e:
|
|
60
|
+
click.echo(f"Daemon is OFFLINE. ({e})")
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Elastro Fast-Path Daemon.
|
|
3
|
+
|
|
4
|
+
Maintains a persistent Elasticsearch client for sub-millisecond agentic queries.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
from contextlib import asynccontextmanager
|
|
9
|
+
from typing import List, Optional, AsyncGenerator, Any, Dict
|
|
10
|
+
|
|
11
|
+
import uvicorn
|
|
12
|
+
from fastapi import FastAPI, Request
|
|
13
|
+
from fastapi.responses import PlainTextResponse
|
|
14
|
+
from pydantic import BaseModel
|
|
15
|
+
|
|
16
|
+
from elastro.cli.output import format_output
|
|
17
|
+
from elastro.config.loader import get_config
|
|
18
|
+
from elastro.core.client import ElasticsearchClient
|
|
19
|
+
from elastro.core.document import DocumentManager
|
|
20
|
+
from elastro.core.query_builder import QueryBuilder
|
|
21
|
+
|
|
22
|
+
# Global client
|
|
23
|
+
client: Optional[ElasticsearchClient] = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@asynccontextmanager
|
|
27
|
+
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
|
|
28
|
+
global client
|
|
29
|
+
config = get_config()
|
|
30
|
+
client = ElasticsearchClient(
|
|
31
|
+
hosts=config["elasticsearch"]["hosts"],
|
|
32
|
+
auth=config["elasticsearch"].get("auth"),
|
|
33
|
+
timeout=config["elasticsearch"].get("timeout", 30),
|
|
34
|
+
retry_on_timeout=config["elasticsearch"].get("retry_on_timeout", True),
|
|
35
|
+
max_retries=config["elasticsearch"].get("max_retries", 3),
|
|
36
|
+
)
|
|
37
|
+
client.connect()
|
|
38
|
+
yield
|
|
39
|
+
if client:
|
|
40
|
+
client.disconnect()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
app = FastAPI(lifespan=lifespan, title="Elastro Agentic Daemon")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class DocSearchRequest(BaseModel):
|
|
47
|
+
args: List[str]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@app.get("/health")
|
|
51
|
+
def health_check() -> Dict[str, Any]:
|
|
52
|
+
return {
|
|
53
|
+
"status": "alive",
|
|
54
|
+
"client_connected": client.is_connected() if client else False,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@app.post("/fast-path/doc/search")
|
|
59
|
+
async def fast_path_search(req: DocSearchRequest) -> PlainTextResponse:
|
|
60
|
+
# Parse args manually for top 10 query types
|
|
61
|
+
parser = argparse.ArgumentParser()
|
|
62
|
+
parser.add_argument("index", type=str)
|
|
63
|
+
parser.add_argument("query", type=str, nargs="?", default=None)
|
|
64
|
+
parser.add_argument("--size", type=int, default=10)
|
|
65
|
+
parser.add_argument("--from", "from_", type=int, default=0, dest="from_")
|
|
66
|
+
|
|
67
|
+
# Query types
|
|
68
|
+
parser.add_argument("--match", action="append", default=[])
|
|
69
|
+
parser.add_argument(
|
|
70
|
+
"--match-phrase", action="append", default=[], dest="match_phrase"
|
|
71
|
+
)
|
|
72
|
+
parser.add_argument("--term", action="append", default=[])
|
|
73
|
+
parser.add_argument("--terms", action="append", default=[])
|
|
74
|
+
parser.add_argument("--range", action="append", default=[])
|
|
75
|
+
parser.add_argument("--prefix", action="append", default=[])
|
|
76
|
+
parser.add_argument("--wildcard", action="append", default=[])
|
|
77
|
+
parser.add_argument("--exists", action="append", default=[])
|
|
78
|
+
parser.add_argument("--ids", action="append", default=[])
|
|
79
|
+
parser.add_argument("--fuzzy", action="append", default=[])
|
|
80
|
+
|
|
81
|
+
# Excludes
|
|
82
|
+
parser.add_argument(
|
|
83
|
+
"--exclude-match", action="append", default=[], dest="exclude_match"
|
|
84
|
+
)
|
|
85
|
+
parser.add_argument(
|
|
86
|
+
"--exclude-term", action="append", default=[], dest="exclude_term"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
parser.add_argument("--output", "-o", type=str, default="json")
|
|
90
|
+
|
|
91
|
+
parsed, _ = parser.parse_known_args(req.args)
|
|
92
|
+
|
|
93
|
+
if not client:
|
|
94
|
+
return PlainTextResponse(
|
|
95
|
+
"Error: Elasticsearch client not connected in daemon.", status_code=500
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
doc_manager = DocumentManager(client)
|
|
99
|
+
|
|
100
|
+
inner_query = QueryBuilder.build_bool_query(
|
|
101
|
+
must_match=getattr(parsed, "match", None),
|
|
102
|
+
must_match_phrase=getattr(parsed, "match_phrase", None),
|
|
103
|
+
must_term=getattr(parsed, "term", None),
|
|
104
|
+
must_terms=getattr(parsed, "terms", None),
|
|
105
|
+
must_range=getattr(parsed, "range", None),
|
|
106
|
+
must_prefix=getattr(parsed, "prefix", None),
|
|
107
|
+
must_wildcard=getattr(parsed, "wildcard", None),
|
|
108
|
+
must_exists=getattr(parsed, "exists", None),
|
|
109
|
+
must_ids=getattr(parsed, "ids", None),
|
|
110
|
+
must_fuzzy=getattr(parsed, "fuzzy", None),
|
|
111
|
+
exclude_match=getattr(parsed, "exclude_match", None),
|
|
112
|
+
exclude_term=getattr(parsed, "exclude_term", None),
|
|
113
|
+
query_string=getattr(parsed, "query", None),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
query_body = {"query": inner_query}
|
|
117
|
+
options = {"size": getattr(parsed, "size", 10), "from": getattr(parsed, "from_", 0)}
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
results = doc_manager.search(getattr(parsed, "index", ""), query_body, options)
|
|
121
|
+
output_format = getattr(parsed, "output", "json")
|
|
122
|
+
output_str = format_output(results, output_format=output_format)
|
|
123
|
+
return PlainTextResponse(content=output_str)
|
|
124
|
+
except Exception as e:
|
|
125
|
+
return PlainTextResponse(
|
|
126
|
+
content=f"Daemon search error: {str(e)}", status_code=500
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def start_daemon(host: str = "127.0.0.1", port: int = 9201) -> None:
|
|
131
|
+
"""Start the Elastro daemon server."""
|
|
132
|
+
uvicorn.run(app, host=host, port=port, log_level="info")
|
|
@@ -74,7 +74,7 @@ class DocumentManager:
|
|
|
74
74
|
|
|
75
75
|
logger.debug(f"Indexing document into '{index}' with ID '{id}'")
|
|
76
76
|
# Execute the index operation
|
|
77
|
-
response = self.client.client.index(**params)
|
|
77
|
+
response = self.client.client.index(**params) # type: ignore
|
|
78
78
|
return response.body if hasattr(response, "body") else dict(response)
|
|
79
79
|
except Exception as e:
|
|
80
80
|
logger.error(f"Failed to index document info '{index}': {str(e)}")
|
|
@@ -355,7 +355,7 @@ class DocumentManager:
|
|
|
355
355
|
|
|
356
356
|
try:
|
|
357
357
|
logger.debug(f"Searching index '{index}'...")
|
|
358
|
-
response = self.client.client.search(**search_params)
|
|
358
|
+
response = self.client.client.search(**search_params) # type: ignore
|
|
359
359
|
return response.body if hasattr(response, "body") else dict(response)
|
|
360
360
|
except Exception as e:
|
|
361
361
|
logger.error(f"Failed to search documents in '{index}': {str(e)}")
|
|
@@ -74,7 +74,7 @@ class BulkDocumentManager:
|
|
|
74
74
|
# Execute bulk operation
|
|
75
75
|
return self.client.client.bulk(
|
|
76
76
|
operations=operations, refresh="true" if refresh else "false"
|
|
77
|
-
)
|
|
77
|
+
) # type: ignore
|
|
78
78
|
except Exception as e:
|
|
79
79
|
raise DocumentError(f"Failed to bulk index documents: {str(e)}")
|
|
80
80
|
|
|
@@ -112,6 +112,6 @@ class BulkDocumentManager:
|
|
|
112
112
|
# Execute bulk operation
|
|
113
113
|
return self.client.client.bulk(
|
|
114
114
|
operations=operations, refresh="true" if refresh else "false"
|
|
115
|
-
)
|
|
115
|
+
) # type: ignore
|
|
116
116
|
except Exception as e:
|
|
117
117
|
raise DocumentError(f"Failed to bulk delete documents: {str(e)}")
|
|
@@ -9,11 +9,11 @@ import shlex
|
|
|
9
9
|
import subprocess
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Dict, Any, List, Optional
|
|
12
|
-
import uvicorn
|
|
13
|
-
from fastapi import FastAPI, Depends, HTTPException, Header, Body
|
|
14
|
-
from fastapi.staticfiles import StaticFiles
|
|
15
|
-
from fastapi.responses import HTMLResponse
|
|
16
|
-
from fastapi.middleware.cors import CORSMiddleware
|
|
12
|
+
import uvicorn
|
|
13
|
+
from fastapi import FastAPI, Depends, HTTPException, Header, Body
|
|
14
|
+
from fastapi.staticfiles import StaticFiles
|
|
15
|
+
from fastapi.responses import HTMLResponse
|
|
16
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
17
17
|
from elastro.core.client import ElasticsearchClient
|
|
18
18
|
|
|
19
19
|
# Optional Pydantic based schema since Elastro uses Pydantic
|
|
@@ -85,13 +85,13 @@ class AliasManager:
|
|
|
85
85
|
"""
|
|
86
86
|
try:
|
|
87
87
|
if name and index:
|
|
88
|
-
return self._es.indices.get_alias(name=name, index=index)
|
|
88
|
+
return self._es.indices.get_alias(name=name, index=index) # type: ignore
|
|
89
89
|
elif name:
|
|
90
|
-
return self._es.indices.get_alias(name=name)
|
|
90
|
+
return self._es.indices.get_alias(name=name) # type: ignore
|
|
91
91
|
elif index:
|
|
92
|
-
return self._es.indices.get_alias(index=index)
|
|
92
|
+
return self._es.indices.get_alias(index=index) # type: ignore
|
|
93
93
|
else:
|
|
94
|
-
return self._es.indices.get_alias()
|
|
94
|
+
return self._es.indices.get_alias() # type: ignore
|
|
95
95
|
except Exception as e:
|
|
96
96
|
raise OperationError(f"Failed to get alias information: {str(e)}")
|
|
97
97
|
|
|
@@ -107,9 +107,9 @@ class AliasManager:
|
|
|
107
107
|
"""
|
|
108
108
|
try:
|
|
109
109
|
if index:
|
|
110
|
-
return self._es.indices.exists_alias(name=name, index=index)
|
|
110
|
+
return self._es.indices.exists_alias(name=name, index=index) # type: ignore
|
|
111
111
|
else:
|
|
112
|
-
return self._es.indices.exists_alias(name=name)
|
|
112
|
+
return self._es.indices.exists_alias(name=name) # type: ignore
|
|
113
113
|
except Exception:
|
|
114
114
|
return False
|
|
115
115
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# mypy: ignore-errors
|
|
1
2
|
"""Health check and diagnostics utilities for Elasticsearch."""
|
|
2
3
|
|
|
3
4
|
from typing import Dict, List, Any, Optional, Union
|
|
@@ -240,7 +241,7 @@ class HealthManager:
|
|
|
240
241
|
diagnostic: Dict[str, Any] = {
|
|
241
242
|
"cluster_health": self.cluster_health(),
|
|
242
243
|
"nodes_count": len(self._es.nodes.info().get("nodes", {})),
|
|
243
|
-
"indices_count": len(self._es.indices.get("*").keys()),
|
|
244
|
+
"indices_count": len(self._es.indices.get(index="*").keys()),
|
|
244
245
|
"pending_tasks": len(self.pending_tasks()),
|
|
245
246
|
}
|
|
246
247
|
|
|
@@ -28,6 +28,7 @@ elastro/cli/output.py
|
|
|
28
28
|
elastro/cli/commands/__init__.py
|
|
29
29
|
elastro/cli/commands/cluster.py
|
|
30
30
|
elastro/cli/commands/config.py
|
|
31
|
+
elastro/cli/commands/daemon.py
|
|
31
32
|
elastro/cli/commands/datastream.py
|
|
32
33
|
elastro/cli/commands/document.py
|
|
33
34
|
elastro/cli/commands/gui.py
|
|
@@ -49,6 +50,7 @@ elastro/config/defaults.py
|
|
|
49
50
|
elastro/config/loader.py
|
|
50
51
|
elastro/core/__init__.py
|
|
51
52
|
elastro/core/client.py
|
|
53
|
+
elastro/core/daemon.py
|
|
52
54
|
elastro/core/datastream.py
|
|
53
55
|
elastro/core/document.py
|
|
54
56
|
elastro/core/document_bulk.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "elastro-client"
|
|
7
|
-
version = "1.3.
|
|
7
|
+
version = "1.3.37"
|
|
8
8
|
description = "A comprehensive Python library for Elasticsearch management with both programmatic and CLI interfaces"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9,<3.14"
|
|
@@ -70,6 +70,11 @@ exclude = ["tests*", "examples*"]
|
|
|
70
70
|
[tool.black]
|
|
71
71
|
line-length = 88
|
|
72
72
|
target-version = ["py39"]
|
|
73
|
+
extend-exclude = '''
|
|
74
|
+
/(
|
|
75
|
+
.*daemon\.py
|
|
76
|
+
)/
|
|
77
|
+
'''
|
|
73
78
|
|
|
74
79
|
[tool.isort]
|
|
75
80
|
profile = "black"
|
|
@@ -85,8 +90,8 @@ check_untyped_defs = true
|
|
|
85
90
|
disallow_untyped_decorators = false
|
|
86
91
|
no_implicit_optional = true
|
|
87
92
|
warn_redundant_casts = true
|
|
88
|
-
warn_unused_ignores =
|
|
89
|
-
exclude = ["build/", "dist/", "examples/", "tests/"]
|
|
93
|
+
warn_unused_ignores = false
|
|
94
|
+
exclude = ["build/", "dist/", "examples/", "tests/", "gh_proxy.*", "single_shot.*", "auto_deploy.py", "run_mypy.*", "dump_git.*", "test_.*", "setup.py"]
|
|
90
95
|
disable_error_code = ["import-untyped"]
|
|
91
96
|
|
|
92
97
|
[[tool.mypy.overrides]]
|
|
@@ -98,6 +103,9 @@ module = [
|
|
|
98
103
|
"elasticsearch.*",
|
|
99
104
|
"setuptools.*",
|
|
100
105
|
"urllib3.*",
|
|
101
|
-
"colorlog.*"
|
|
106
|
+
"colorlog.*",
|
|
107
|
+
"click.*",
|
|
108
|
+
"fastapi.*",
|
|
109
|
+
"uvicorn.*"
|
|
102
110
|
]
|
|
103
111
|
ignore_missing_imports = true
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{elastro_client-1.3.34 → elastro_client-1.3.37}/elastro_client.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_aggregations_integration.py
RENAMED
|
File without changes
|
{elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_client_integration.py
RENAMED
|
File without changes
|
{elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_datastream_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
{elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_document_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
{elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_query_builder_integration.py
RENAMED
|
File without changes
|
{elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_scroll_integration.py
RENAMED
|
File without changes
|
{elastro_client-1.3.34 → elastro_client-1.3.37}/tests/integration/test_workflow_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|