elastro-client 1.2.2__tar.gz → 1.2.4__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.
Files changed (134) hide show
  1. {elastro_client-1.2.2 → elastro_client-1.2.4}/MANIFEST.in +2 -1
  2. {elastro_client-1.2.2/elastro_client.egg-info → elastro_client-1.2.4}/PKG-INFO +54 -7
  3. {elastro_client-1.2.2 → elastro_client-1.2.4}/README.md +47 -5
  4. elastro_client-1.2.4/docs/commands_reference.md +101 -0
  5. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/__init__.py +1 -1
  6. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/advanced/aggregations.py +14 -18
  7. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/advanced/query_builder.py +22 -13
  8. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/advanced/scroll.py +41 -30
  9. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/art.py +4 -1
  10. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/cli.py +68 -37
  11. elastro_client-1.2.4/elastro/cli/commands/__init__.py +48 -0
  12. elastro_client-1.2.4/elastro/cli/commands/cluster.py +111 -0
  13. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/config.py +50 -36
  14. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/datastream.py +31 -13
  15. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/document.py +93 -48
  16. elastro_client-1.2.4/elastro/cli/commands/gui.py +38 -0
  17. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/ilm.py +95 -65
  18. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/index.py +205 -44
  19. elastro_client-1.2.4/elastro/cli/commands/index_recipes.py +193 -0
  20. elastro_client-1.2.4/elastro/cli/commands/ingest.py +92 -0
  21. elastro_client-1.2.4/elastro/cli/commands/security.py +92 -0
  22. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/snapshot.py +97 -60
  23. elastro_client-1.2.4/elastro/cli/commands/tasks.py +97 -0
  24. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/template.py +91 -39
  25. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/commands/utils.py +76 -30
  26. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/completion.py +24 -19
  27. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/output.py +20 -17
  28. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/config/__init__.py +7 -1
  29. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/config/defaults.py +10 -23
  30. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/config/loader.py +37 -20
  31. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/client.py +51 -26
  32. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/datastream.py +50 -41
  33. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/document.py +73 -40
  34. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/document_bulk.py +6 -19
  35. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/errors.py +9 -0
  36. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/ilm.py +14 -14
  37. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/index.py +16 -15
  38. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/logger.py +9 -9
  39. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/query_builder.py +35 -33
  40. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/snapshot.py +45 -36
  41. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/validation.py +81 -22
  42. elastro_client-1.2.4/elastro/gui/assets/index-7HiKWxC0.js +293 -0
  43. elastro_client-1.2.4/elastro/gui/assets/index-BGQLoyNJ.css +1 -0
  44. elastro_client-1.2.4/elastro/gui/elastro.svg +10 -0
  45. elastro_client-1.2.4/elastro/gui/favicon.ico +0 -0
  46. elastro_client-1.2.4/elastro/gui/index.html +17 -0
  47. elastro_client-1.2.4/elastro/gui/vite.svg +1 -0
  48. elastro_client-1.2.4/elastro/server.py +524 -0
  49. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/utils/aliases.py +37 -22
  50. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/utils/health.py +33 -27
  51. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/utils/snapshots.py +105 -80
  52. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/utils/templates.py +19 -8
  53. {elastro_client-1.2.2 → elastro_client-1.2.4/elastro_client.egg-info}/PKG-INFO +54 -7
  54. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro_client.egg-info/SOURCES.txt +14 -0
  55. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro_client.egg-info/requires.txt +2 -0
  56. {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/client.py +25 -29
  57. {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/config_usage.py +17 -24
  58. {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/datastreams.py +93 -110
  59. {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/debug_connection.py +52 -25
  60. {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/document_operations.py +36 -42
  61. {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/index_management.py +34 -53
  62. {elastro_client-1.2.2 → elastro_client-1.2.4}/examples/search.py +102 -139
  63. {elastro_client-1.2.2 → elastro_client-1.2.4}/pyproject.toml +34 -6
  64. elastro_client-1.2.4/requirements.txt +58 -0
  65. {elastro_client-1.2.2 → elastro_client-1.2.4}/setup.py +1 -1
  66. elastro_client-1.2.4/tests/__init__.py +1 -0
  67. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/conftest.py +5 -5
  68. elastro_client-1.2.4/tests/fixtures/__init__.py +1 -0
  69. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/fixtures/datastream_fixtures.py +18 -32
  70. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/fixtures/document_fixtures.py +20 -40
  71. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/fixtures/index_fixtures.py +8 -16
  72. elastro_client-1.2.4/tests/integration/__init__.py +1 -0
  73. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_aggregations_integration.py +66 -108
  74. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_client_integration.py +40 -40
  75. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_datastream_integration.py +27 -29
  76. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_docs_quickstart.py +14 -13
  77. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_document_integration.py +65 -75
  78. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_index_integration.py +22 -21
  79. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_query_builder_integration.py +42 -42
  80. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_scroll_integration.py +55 -61
  81. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/integration/test_workflow_integration.py +69 -95
  82. elastro_client-1.2.4/tests/manual/test_es.py +5 -0
  83. elastro_client-1.2.4/tests/unit/__init__.py +1 -0
  84. elastro_client-1.2.4/tests/unit/advanced/__init__.py +1 -0
  85. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/advanced/test_aggregations.py +36 -77
  86. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/advanced/test_query_builder.py +85 -136
  87. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/advanced/test_scroll.py +56 -107
  88. elastro_client-1.2.4/tests/unit/config/__init__.py +1 -0
  89. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/config/test_defaults.py +38 -17
  90. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/config/test_loader.py +94 -93
  91. elastro_client-1.2.4/tests/unit/core/__init__.py +1 -0
  92. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_client.py +85 -85
  93. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_datastream.py +168 -108
  94. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_document.py +124 -247
  95. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_document_bulk.py +56 -46
  96. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_errors.py +1 -1
  97. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_index.py +173 -140
  98. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/core/test_validation.py +18 -46
  99. elastro_client-1.2.4/tests/unit/utils/__init__.py +1 -0
  100. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/utils/test_aliases.py +75 -74
  101. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/utils/test_health.py +121 -129
  102. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/utils/test_snapshots.py +110 -115
  103. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/unit/utils/test_templates.py +93 -58
  104. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/verify_api_actions.py +10 -9
  105. {elastro_client-1.2.2 → elastro_client-1.2.4}/tests/verify_cli_e2e.py +149 -95
  106. elastro_client-1.2.2/elastro/cli/commands/__init__.py +0 -32
  107. elastro_client-1.2.2/requirements.txt +0 -6
  108. elastro_client-1.2.2/tests/__init__.py +0 -1
  109. elastro_client-1.2.2/tests/fixtures/__init__.py +0 -1
  110. elastro_client-1.2.2/tests/integration/__init__.py +0 -1
  111. elastro_client-1.2.2/tests/manual/test_es.py +0 -1
  112. elastro_client-1.2.2/tests/unit/__init__.py +0 -1
  113. elastro_client-1.2.2/tests/unit/advanced/__init__.py +0 -1
  114. elastro_client-1.2.2/tests/unit/config/__init__.py +0 -1
  115. elastro_client-1.2.2/tests/unit/core/__init__.py +0 -1
  116. elastro_client-1.2.2/tests/unit/utils/__init__.py +0 -1
  117. {elastro_client-1.2.2 → elastro_client-1.2.4}/.coveragerc +0 -0
  118. {elastro_client-1.2.2 → elastro_client-1.2.4}/LICENSE +0 -0
  119. {elastro_client-1.2.2 → elastro_client-1.2.4}/docs/advanced_features.md +0 -0
  120. {elastro_client-1.2.2 → elastro_client-1.2.4}/docs/api_reference.md +0 -0
  121. {elastro_client-1.2.2 → elastro_client-1.2.4}/docs/cli_usage.md +0 -0
  122. {elastro_client-1.2.2 → elastro_client-1.2.4}/docs/getting_started.md +0 -0
  123. {elastro_client-1.2.2 → elastro_client-1.2.4}/docs/roadmap.md +0 -0
  124. {elastro_client-1.2.2 → elastro_client-1.2.4}/docs/troubleshooting.md +0 -0
  125. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/advanced/__init__.py +0 -0
  126. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/cli/__init__.py +0 -0
  127. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/core/__init__.py +0 -0
  128. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/py.typed +0 -0
  129. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro/utils/__init__.py +0 -0
  130. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro_client.egg-info/dependency_links.txt +0 -0
  131. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro_client.egg-info/entry_points.txt +0 -0
  132. {elastro_client-1.2.2 → elastro_client-1.2.4}/elastro_client.egg-info/top_level.txt +0 -0
  133. {elastro_client-1.2.2 → elastro_client-1.2.4}/pytest.ini +0 -0
  134. {elastro_client-1.2.2 → elastro_client-1.2.4}/setup.cfg +0 -0
@@ -11,4 +11,5 @@ include .coveragerc
11
11
  global-exclude *.pyc
12
12
  global-exclude __pycache__
13
13
  global-exclude *.so
14
- global-exclude .DS_Store
14
+ global-exclude .DS_Store
15
+ recursive-include elastro/gui *
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elastro-client
3
- Version: 1.2.2
3
+ Version: 1.2.4
4
4
  Summary: A comprehensive Python library for Elasticsearch management with both programmatic and CLI interfaces
5
5
  Author: Austin Jorgensen
6
6
  License-Expression: MIT
@@ -9,11 +9,14 @@ Project-URL: Repository, https://github.com/Fremen-Labs/elastro
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: Programming Language :: Python :: 3.9
11
11
  Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
12
15
  Classifier: Operating System :: OS Independent
13
16
  Classifier: Development Status :: 3 - Alpha
14
17
  Classifier: Intended Audience :: Developers
15
18
  Classifier: Topic :: Database
16
- Requires-Python: >=3.8
19
+ Requires-Python: <3.14,>=3.9
17
20
  Description-Content-Type: text/markdown
18
21
  License-File: LICENSE
19
22
  Requires-Dist: elasticsearch<9.0.0,>=8.18.0
@@ -24,6 +27,8 @@ Requires-Dist: pyyaml>=6.0
24
27
  Requires-Dist: colorlog>=6.0.0
25
28
  Requires-Dist: rich>=10.0.0
26
29
  Requires-Dist: rich-click>=1.7.0
30
+ Requires-Dist: fastapi>=0.111.0
31
+ Requires-Dist: uvicorn>=0.30.0
27
32
  Provides-Extra: test
28
33
  Requires-Dist: pytest>=7.0.0; extra == "test"
29
34
  Requires-Dist: pytest-cov>=3.0.0; extra == "test"
@@ -68,18 +73,42 @@ The library offers both a programmatic API and a command-line interface for seam
68
73
 
69
74
  ## Installation
70
75
 
76
+ ### Global CLI Installation (Recommended)
77
+
78
+ To heavily simplify installation across all operating systems and elegantly check your Python compatibility, run our automated `install.sh` via curl:
79
+
80
+ ```bash
81
+ # Safely check your python version and install the elastro CLI globally
82
+ curl -sSfL https://raw.githubusercontent.com/Fremen-Labs/elastro/main/install.sh | bash
83
+ ```
84
+
85
+ Alternatively, if you already have pipx installed and your Python version is compatible (>=3.9, <3.14):
86
+
71
87
  ```bash
72
- pip install elastro
88
+ # Manual installation via pipx
89
+ pipx install elastro-client
90
+
91
+ # Upgrade later
92
+ pipx upgrade elastro-client
73
93
  ```
74
94
 
75
- Or from source:
95
+ ### Library Installation (For Development)
96
+
97
+ If you are using Elastro as a library in your Python project:
76
98
 
77
99
  ```bash
78
- git clone https://github.com/Fremen-Labs/elastro.git
79
- cd elastro
80
- pip install -e .
100
+ # Using a virtual environment
101
+ python3 -m venv venv
102
+ source venv/bin/activate
103
+ pip install elastro-client
81
104
  ```
82
105
 
106
+ ### Troubleshooting: "externally-managed-environment"
107
+
108
+ If you see an `externally-managed-environment` error when running `pip install`, it means your OS (like macOS with Homebrew) prevents system-wide package installation.
109
+
110
+ **Solution:** Use `pipx` (above) or a virtual environment. Do not use `--break-system-packages` unless you are certain of the consequences.
111
+
83
112
  ## Basic Usage
84
113
 
85
114
  ### Client Connection
@@ -169,6 +198,9 @@ print(results)
169
198
  # Initialize configuration
170
199
  elastro config init
171
200
 
201
+ # Launch the Elastro Local Web GUI
202
+ elastro gui
203
+
172
204
  # Create an index
173
205
  elastro index create products --shards 3 --replicas 1
174
206
 
@@ -186,6 +218,21 @@ elastro doc index products --id 1 --file ./product.json
186
218
 
187
219
  # Search documents
188
220
  elastro doc search products --term category=laptop
221
+
222
+ # View cluster health and routing allocation
223
+ elastro cluster health
224
+ elastro cluster allocation
225
+
226
+ # Manage ingest pipelines
227
+ elastro ingest list
228
+ elastro ingest simulate my-pipeline --docs ./docs.json
229
+
230
+ # Manage native realm security users and roles
231
+ elastro security users list
232
+ elastro security roles create my-role --privileges "monitor,manage"
233
+
234
+ # View long-running cluster tasks
235
+ elastro tasks list --detailed
189
236
  ```
190
237
 
191
238
  ### ILM (Index Lifecycle Management)
@@ -30,18 +30,42 @@ The library offers both a programmatic API and a command-line interface for seam
30
30
 
31
31
  ## Installation
32
32
 
33
+ ### Global CLI Installation (Recommended)
34
+
35
+ To heavily simplify installation across all operating systems and elegantly check your Python compatibility, run our automated `install.sh` via curl:
36
+
37
+ ```bash
38
+ # Safely check your python version and install the elastro CLI globally
39
+ curl -sSfL https://raw.githubusercontent.com/Fremen-Labs/elastro/main/install.sh | bash
40
+ ```
41
+
42
+ Alternatively, if you already have pipx installed and your Python version is compatible (>=3.9, <3.14):
43
+
33
44
  ```bash
34
- pip install elastro
45
+ # Manual installation via pipx
46
+ pipx install elastro-client
47
+
48
+ # Upgrade later
49
+ pipx upgrade elastro-client
35
50
  ```
36
51
 
37
- Or from source:
52
+ ### Library Installation (For Development)
53
+
54
+ If you are using Elastro as a library in your Python project:
38
55
 
39
56
  ```bash
40
- git clone https://github.com/Fremen-Labs/elastro.git
41
- cd elastro
42
- pip install -e .
57
+ # Using a virtual environment
58
+ python3 -m venv venv
59
+ source venv/bin/activate
60
+ pip install elastro-client
43
61
  ```
44
62
 
63
+ ### Troubleshooting: "externally-managed-environment"
64
+
65
+ If you see an `externally-managed-environment` error when running `pip install`, it means your OS (like macOS with Homebrew) prevents system-wide package installation.
66
+
67
+ **Solution:** Use `pipx` (above) or a virtual environment. Do not use `--break-system-packages` unless you are certain of the consequences.
68
+
45
69
  ## Basic Usage
46
70
 
47
71
  ### Client Connection
@@ -131,6 +155,9 @@ print(results)
131
155
  # Initialize configuration
132
156
  elastro config init
133
157
 
158
+ # Launch the Elastro Local Web GUI
159
+ elastro gui
160
+
134
161
  # Create an index
135
162
  elastro index create products --shards 3 --replicas 1
136
163
 
@@ -148,6 +175,21 @@ elastro doc index products --id 1 --file ./product.json
148
175
 
149
176
  # Search documents
150
177
  elastro doc search products --term category=laptop
178
+
179
+ # View cluster health and routing allocation
180
+ elastro cluster health
181
+ elastro cluster allocation
182
+
183
+ # Manage ingest pipelines
184
+ elastro ingest list
185
+ elastro ingest simulate my-pipeline --docs ./docs.json
186
+
187
+ # Manage native realm security users and roles
188
+ elastro security users list
189
+ elastro security roles create my-role --privileges "monitor,manage"
190
+
191
+ # View long-running cluster tasks
192
+ elastro tasks list --detailed
151
193
  ```
152
194
 
153
195
  ### ILM (Index Lifecycle Management)
@@ -0,0 +1,101 @@
1
+ # Elastro CLI Commands Reference
2
+
3
+ The Elastro CLI provides a robust feature set for managing your Elasticsearch cluster operations safely and efficiently. This guide details each primary command group, its associated subcommands, what they do, and why they are important for your workflow.
4
+
5
+ ---
6
+
7
+ ## 1. `config`
8
+ **Purpose**: Manage local configuration and connection profiles.
9
+ **Why it's important**: Centralizing connection strings, credentials, and API keys ensures you don't accidentally leak secrets or push them to version control. It also enables rapid context-switching between dev, staging, and production environments.
10
+
11
+ - **`profile`**: Switch or define which configuration profile is actively used by Elastro.
12
+ - **`set`**: Set individual configuration values securely within the active profile.
13
+
14
+ ---
15
+
16
+ ## 2. `gui`
17
+ **Purpose**: Launch the Elastro Local Web GUI.
18
+ **Why it's important**: Sometimes the CLI isn't enough to visualize complex index metrics or health statuses. The fully autonomous local GUI acts as a single pane of glass, allowing you to quickly spot cluster degradation (yellow/red indices) and manage your instances without deploying heavy Kibana stacks.
19
+
20
+ - **`elastro gui`**: Starts a secure, detached background server and immediately opens the web dashboard in your browser with a unique, one-time authentication token.
21
+
22
+ ---
23
+
24
+ ## 3. `index`
25
+ **Purpose**: Manage Elasticsearch indices.
26
+ **Why it's important**: Indices are the foundational storage mechanism of Elasticsearch. Proper index management ensures that your data is correctly sharded, optimally routed, and easily purged.
27
+
28
+ - **`wizard`**: Interactive wizard for creating indices using "Certified Engineer" optimized recipes (highly recommended).
29
+ - **`list`** / **`find`**: Filter and list indices, displaying vital statistics like size, document counts, and health status.
30
+ - **`create`** / **`delete`**: Safely deploy mapped index schemas or purge indices entirely.
31
+ - **`get`** / **`exists`**: Query the exact structure, mappings, and existence of a target index.
32
+ - **`update`**: Inject dynamic settings updates into live indices.
33
+ - **`close`** / **`open`**: Freeze indices to save cluster memory footprint, and thaw them later for searching.
34
+
35
+ ---
36
+
37
+ ## 4. `doc`
38
+ **Purpose**: Manage Elasticsearch documents.
39
+ **Why it's important**: While indexing logs via beats is common, debugging mapping errors or orchestrating CRUD operations manually is a critical administrative function. The `doc` commands let you easily ingest, query, and mutate specific records directly from the terminal.
40
+
41
+ - **`bulk`**: Perform high-throughput bulk insertion of documents from NDJSON payloads.
42
+ - **`search`**: Execute direct search queries against your indexes for ad-hoc debugging.
43
+ - **`index`**: Insert a new specific document or overwrite an existing one.
44
+ - **`get`**: Retrieve a document by its ID to examine its exact structured payload.
45
+ - **`update`**: Perform partial updates to an existing document without full replacement.
46
+ - **`delete`**: Remove an individual document.
47
+
48
+ ---
49
+
50
+ ## 5. `datastream`
51
+ **Purpose**: Manage Elasticsearch datastreams.
52
+ **Why it's important**: Data streams are the modern, scalable approach to handling time-series data (like logs and metrics). Elastro abstracts the complexities of backing indices so you can manage the continuous stream elegantly.
53
+
54
+ - **`create`**: Establish a new datastream (requires a matching index template).
55
+ - **`list`** / **`get`** / **`exists`**: Discover and inspect streaming channels.
56
+ - **`stats`**: Retrieve detailed volumetric and performance statistics about your streams.
57
+ - **`delete`**: Teardown deprecated datastreams.
58
+
59
+ ---
60
+
61
+ ## 6. `template`
62
+ **Purpose**: Manage index and component templates.
63
+ **Why it's important**: Templates guarantee that newly generated rolling indices (or datastreams) automatically inherit the correct shards, replicas, mappings, and lifecycles dynamically, avoiding manual intervention at runtime.
64
+
65
+ - **`wizard`**: An interactive wizard that makes assembling advanced index schemas from reusable component templates easy.
66
+ - **`create`**: Apply a template JSON manifest to the cluster.
67
+ - **`list`** / **`get`**: Inspect currently active templates.
68
+ - **`delete`**: Purge outdated templates.
69
+
70
+ ---
71
+
72
+ ## 7. `ilm`
73
+ **Purpose**: Manage Index Lifecycle Management (ILM) policies.
74
+ **Why it's important**: Managing the cost of compute versus storage requires aging out data. ILM policies automate the transition of indices through Hot, Warm, Cold, and Delete phases automatically, saving enormous amounts of hardware resources.
75
+
76
+ - **`wizard`**: Interactively define retention durations, rollover sizes, and phase transitions to build robust lifecycle policies without writing complex JSON.
77
+ - **`create`**: Upload a customized JSON ILM policy.
78
+ - **`list`** / **`get`**: Inspect the policies currently governing your cluster data.
79
+ - **`delete`**: Remove an ILM policy.
80
+
81
+ ---
82
+
83
+ ## 8. `snapshot`
84
+ **Purpose**: Manage Snapshots and Repositories.
85
+ **Why it's important**: Hardware failures, ransomware, or unexpected deletions happen. Standardized cluster snapshotting is the only reliable path to disaster recovery (DR).
86
+
87
+ - **`repo`**: Manage the snapshot storage backends (e.g., S3, Azure Blob, or local FS).
88
+ - **`create`**: Trigger a manual snapshot of the cluster or specific indices.
89
+ - **`list`**: View all historical snapshots held in a repository.
90
+ - **`restore`**: Recover your cluster state and data instantly from a previously saved snapshot.
91
+ - **`delete`**: Prune old snapshots to reclaim storage space.
92
+
93
+ ---
94
+
95
+ ## 9. `utils`
96
+ **Purpose**: Miscellaneous utility commands.
97
+ **Why it's important**: Fast access to high-level cluster metrics and organizational operations for general system administration.
98
+
99
+ - **`health`**: Get a quick snapshot of the cluster's pulse (Green, Yellow, Red) and node availability.
100
+ - **`aliases`**: Inspect index aliases, showing how applications transparently route to underlying indices.
101
+ - **`templates`**: Manage legacy index templates (if supporting older Elasticsearch 7.x clusters).
@@ -4,7 +4,7 @@ Elasticsearch Management Module.
4
4
  A module for managing Elasticsearch operations within a pipeline process.
5
5
  """
6
6
 
7
- __version__ = "1.2.2"
7
+ __version__ = "1.2.4"
8
8
 
9
9
  # Core component imports
10
10
  from elastro.core.client import ElasticsearchClient
@@ -14,8 +14,9 @@ class AggregationBuilder:
14
14
  """Initialize an empty aggregation builder."""
15
15
  self._aggregations: Dict[str, Dict[str, Any]] = {}
16
16
 
17
- def terms(self, name: str, field: str, size: int = 10,
18
- min_doc_count: Optional[int] = None) -> "AggregationBuilder":
17
+ def terms(
18
+ self, name: str, field: str, size: int = 10, min_doc_count: Optional[int] = None
19
+ ) -> "AggregationBuilder":
19
20
  """Add a terms aggregation.
20
21
 
21
22
  Args:
@@ -34,8 +35,9 @@ class AggregationBuilder:
34
35
  self._aggregations[name] = {"terms": agg}
35
36
  return self
36
37
 
37
- def date_histogram(self, name: str, field: str, interval: str,
38
- format: Optional[str] = None) -> "AggregationBuilder":
38
+ def date_histogram(
39
+ self, name: str, field: str, interval: str, format: Optional[str] = None
40
+ ) -> "AggregationBuilder":
39
41
  """Add a date_histogram aggregation.
40
42
 
41
43
  Args:
@@ -65,15 +67,12 @@ class AggregationBuilder:
65
67
  Returns:
66
68
  Self for method chaining
67
69
  """
68
- self._aggregations[name] = {
69
- "histogram": {
70
- "field": field,
71
- "interval": interval
72
- }
73
- }
70
+ self._aggregations[name] = {"histogram": {"field": field, "interval": interval}}
74
71
  return self
75
72
 
76
- def range(self, name: str, field: str, ranges: List[Dict[str, Any]]) -> "AggregationBuilder":
73
+ def range(
74
+ self, name: str, field: str, ranges: List[Dict[str, Any]]
75
+ ) -> "AggregationBuilder":
77
76
  """Add a range aggregation.
78
77
 
79
78
  Args:
@@ -84,12 +83,7 @@ class AggregationBuilder:
84
83
  Returns:
85
84
  Self for method chaining
86
85
  """
87
- self._aggregations[name] = {
88
- "range": {
89
- "field": field,
90
- "ranges": ranges
91
- }
92
- }
86
+ self._aggregations[name] = {"range": {"field": field, "ranges": ranges}}
93
87
  return self
94
88
 
95
89
  def avg(self, name: str, field: str) -> "AggregationBuilder":
@@ -157,7 +151,9 @@ class AggregationBuilder:
157
151
  self._aggregations[name] = {"cardinality": {"field": field}}
158
152
  return self
159
153
 
160
- def nested_agg(self, parent_name: str, child_builder: "AggregationBuilder") -> "AggregationBuilder":
154
+ def nested_agg(
155
+ self, parent_name: str, child_builder: "AggregationBuilder"
156
+ ) -> "AggregationBuilder":
161
157
  """Add nested aggregations to a parent aggregation.
162
158
 
163
159
  Args:
@@ -14,7 +14,13 @@ class QueryBuilder:
14
14
  """Initialize an empty query builder."""
15
15
  self._query: Dict[str, Any] = {}
16
16
 
17
- def match(self, field: str, value: Any, operator: str = "or", fuzziness: Optional[str] = None) -> "QueryBuilder":
17
+ def match(
18
+ self,
19
+ field: str,
20
+ value: Any,
21
+ operator: str = "or",
22
+ fuzziness: Optional[str] = None,
23
+ ) -> "QueryBuilder":
18
24
  """Create a match query.
19
25
 
20
26
  Args:
@@ -26,7 +32,9 @@ class QueryBuilder:
26
32
  Returns:
27
33
  Self for method chaining
28
34
  """
29
- match_query: Dict[str, Any] = {"match": {field: {"query": value, "operator": operator}}}
35
+ match_query: Dict[str, Any] = {
36
+ "match": {field: {"query": value, "operator": operator}}
37
+ }
30
38
  if fuzziness:
31
39
  match_query["match"][field]["fuzziness"] = fuzziness
32
40
 
@@ -44,14 +52,7 @@ class QueryBuilder:
44
52
  Returns:
45
53
  Self for method chaining
46
54
  """
47
- self._query = {
48
- "match_phrase": {
49
- field: {
50
- "query": value,
51
- "slop": slop
52
- }
53
- }
54
- }
55
+ self._query = {"match_phrase": {field: {"query": value, "slop": slop}}}
55
56
  return self
56
57
 
57
58
  def term(self, field: str, value: Any) -> "QueryBuilder":
@@ -80,8 +81,14 @@ class QueryBuilder:
80
81
  self._query = {"terms": {field: values}}
81
82
  return self
82
83
 
83
- def range(self, field: str, gte: Optional[Any] = None, lte: Optional[Any] = None,
84
- gt: Optional[Any] = None, lt: Optional[Any] = None) -> "QueryBuilder":
84
+ def range(
85
+ self,
86
+ field: str,
87
+ gte: Optional[Any] = None,
88
+ lte: Optional[Any] = None,
89
+ gt: Optional[Any] = None,
90
+ lt: Optional[Any] = None,
91
+ ) -> "QueryBuilder":
85
92
  """Create a range query.
86
93
 
87
94
  Args:
@@ -188,7 +195,9 @@ class BoolQueryBuilder:
188
195
  self._must.append(query)
189
196
  return self
190
197
 
191
- def must_not(self, query: Union[QueryBuilder, Dict[str, Any]]) -> "BoolQueryBuilder":
198
+ def must_not(
199
+ self, query: Union[QueryBuilder, Dict[str, Any]]
200
+ ) -> "BoolQueryBuilder":
192
201
  """Add a must_not clause to the bool query.
193
202
 
194
203
  Args:
@@ -2,14 +2,18 @@
2
2
 
3
3
  from typing import Any, Callable, Dict, Generator, List, Optional, Union
4
4
  from elasticsearch import Elasticsearch
5
+ from elasticsearch import Elasticsearch
6
+ from elastro.core.logger import get_logger
7
+
8
+ logger = get_logger(__name__)
5
9
 
6
10
 
7
11
  class ScrollHelper:
8
12
  """Helper for managing Elasticsearch scroll searches.
9
13
 
10
- Scroll searches allow retrieving large numbers of documents from Elasticsearch
11
- that would otherwise exceed result size limits. This helper simplifies the
12
- process of initializing and maintaining scroll contexts.
14
+ Scroll searches allow retrieving large numbers of documents from Elasticsearch
15
+ that would otherwise exceed result size limits. This helper simplifies the
16
+ process of initializing and maintaining scroll contexts.
13
17
  """
14
18
 
15
19
  def __init__(self, client: Elasticsearch) -> None:
@@ -20,9 +24,14 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
20
24
  """
21
25
  self._client = client
22
26
 
23
- def scroll(self, index: str, query: Dict[str, Any],
24
- scroll_timeout: str = "1m", size: int = 1000,
25
- source_fields: Optional[List[str]] = None) -> Generator[Dict[str, Any], None, None]:
27
+ def scroll(
28
+ self,
29
+ index: str,
30
+ query: Dict[str, Any],
31
+ scroll_timeout: str = "1m",
32
+ size: int = 1000,
33
+ source_fields: Optional[List[str]] = None,
34
+ ) -> Generator[List[Dict[str, Any]], None, None]:
26
35
  """Perform a scroll search and yield batches of results.
27
36
 
28
37
  Args:
@@ -40,11 +49,7 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
40
49
  body["_source"] = source_fields
41
50
 
42
51
  # Initialize scroll
43
- resp = self._client.search(
44
- index=index,
45
- body=body,
46
- scroll=scroll_timeout
47
- )
52
+ resp = self._client.search(index=index, body=body, scroll=scroll_timeout)
48
53
 
49
54
  # Get the scroll ID
50
55
  scroll_id = resp.get("_scroll_id")
@@ -56,10 +61,7 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
56
61
  yield batch
57
62
 
58
63
  # Continue scrolling
59
- resp = self._client.scroll(
60
- scroll_id=scroll_id,
61
- scroll=scroll_timeout
62
- )
64
+ resp = self._client.scroll(scroll_id=scroll_id, scroll=scroll_timeout)
63
65
 
64
66
  # Update scroll_id as it may change
65
67
  scroll_id = resp.get("_scroll_id")
@@ -75,14 +77,18 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
75
77
  if scroll_id:
76
78
  try:
77
79
  self._client.clear_scroll(scroll_id=scroll_id)
78
- except Exception:
79
- # Log but don't raise
80
- pass
81
-
82
- def process_all(self, index: str, query: Dict[str, Any],
83
- processor: Callable[[Dict[str, Any]], None],
84
- scroll_timeout: str = "1m", size: int = 1000,
85
- source_fields: Optional[List[str]] = None) -> int:
80
+ except Exception as e:
81
+ logger.warning(f"Failed to clear scroll context: {str(e)}")
82
+
83
+ def process_all(
84
+ self,
85
+ index: str,
86
+ query: Dict[str, Any],
87
+ processor: Callable[[Dict[str, Any]], None],
88
+ scroll_timeout: str = "1m",
89
+ size: int = 1000,
90
+ source_fields: Optional[List[str]] = None,
91
+ ) -> int:
86
92
  """Process all matching documents with a callback function.
87
93
 
88
94
  Args:
@@ -103,7 +109,7 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
103
109
  query=query,
104
110
  scroll_timeout=scroll_timeout,
105
111
  size=size,
106
- source_fields=source_fields
112
+ source_fields=source_fields,
107
113
  ):
108
114
  for doc in batch:
109
115
  processor(doc)
@@ -111,10 +117,15 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
111
117
 
112
118
  return total_processed
113
119
 
114
- def collect_all(self, index: str, query: Dict[str, Any],
115
- scroll_timeout: str = "1m", size: int = 1000,
116
- source_fields: Optional[List[str]] = None,
117
- max_documents: Optional[int] = None) -> List[Dict[str, Any]]:
120
+ def collect_all(
121
+ self,
122
+ index: str,
123
+ query: Dict[str, Any],
124
+ scroll_timeout: str = "1m",
125
+ size: int = 1000,
126
+ source_fields: Optional[List[str]] = None,
127
+ max_documents: Optional[int] = None,
128
+ ) -> List[Dict[str, Any]]:
118
129
  """Collect all matching documents into a single list.
119
130
 
120
131
  Warning: This can consume a lot of memory for large result sets.
@@ -130,7 +141,7 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
130
141
  Returns:
131
142
  List of all matching documents
132
143
  """
133
- all_docs = []
144
+ all_docs: List[Dict[str, Any]] = []
134
145
  docs_collected = 0
135
146
 
136
147
  for batch in self.scroll(
@@ -138,7 +149,7 @@ Scroll searches allow retrieving large numbers of documents from Elasticsearch
138
149
  query=query,
139
150
  scroll_timeout=scroll_timeout,
140
151
  size=size,
141
- source_fields=source_fields
152
+ source_fields=source_fields,
142
153
  ):
143
154
  if max_documents is not None:
144
155
  remaining = max_documents - docs_collected
@@ -14,10 +14,13 @@ ELASTRO_ART = r"""
14
14
  ```
15
15
  """
16
16
 
17
+
17
18
  def get_banner() -> str:
18
19
  return ELASTRO_ART
19
20
 
20
- def print_banner():
21
+
22
+ def print_banner() -> None:
21
23
  from rich.console import Console
24
+
22
25
  console = Console()
23
26
  console.print(ELASTRO_ART, style="bold blue")