mplang-nightly 0.1.dev269__py3-none-any.whl → 0.1.dev270__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.
Files changed (180) hide show
  1. mplang/__init__.py +391 -17
  2. mplang/{v2/backends → backends}/__init__.py +9 -7
  3. mplang/{v2/backends → backends}/bfv_impl.py +6 -6
  4. mplang/{v2/backends → backends}/crypto_impl.py +6 -6
  5. mplang/{v2/backends → backends}/field_impl.py +5 -5
  6. mplang/{v2/backends → backends}/func_impl.py +4 -4
  7. mplang/{v2/backends → backends}/phe_impl.py +3 -3
  8. mplang/{v2/backends → backends}/simp_design.md +1 -1
  9. mplang/{v2/backends → backends}/simp_driver/__init__.py +5 -5
  10. mplang/{v2/backends → backends}/simp_driver/http.py +8 -8
  11. mplang/{v2/backends → backends}/simp_driver/mem.py +9 -9
  12. mplang/{v2/backends → backends}/simp_driver/ops.py +4 -4
  13. mplang/{v2/backends → backends}/simp_driver/state.py +2 -2
  14. mplang/{v2/backends → backends}/simp_driver/values.py +2 -2
  15. mplang/{v2/backends → backends}/simp_worker/__init__.py +3 -3
  16. mplang/{v2/backends → backends}/simp_worker/http.py +10 -10
  17. mplang/{v2/backends → backends}/simp_worker/mem.py +1 -1
  18. mplang/{v2/backends → backends}/simp_worker/ops.py +5 -5
  19. mplang/{v2/backends → backends}/simp_worker/state.py +2 -4
  20. mplang/{v2/backends → backends}/spu_impl.py +8 -8
  21. mplang/{v2/backends → backends}/spu_state.py +4 -4
  22. mplang/{v2/backends → backends}/store_impl.py +3 -3
  23. mplang/{v2/backends → backends}/table_impl.py +8 -8
  24. mplang/{v2/backends → backends}/tee_impl.py +6 -6
  25. mplang/{v2/backends → backends}/tensor_impl.py +6 -6
  26. mplang/{v2/cli.py → cli.py} +9 -9
  27. mplang/{v2/cli_guide.md → cli_guide.md} +12 -12
  28. mplang/{v2/dialects → dialects}/__init__.py +5 -5
  29. mplang/{v2/dialects → dialects}/bfv.py +6 -6
  30. mplang/{v2/dialects → dialects}/crypto.py +5 -5
  31. mplang/{v2/dialects → dialects}/dtypes.py +2 -2
  32. mplang/{v2/dialects → dialects}/field.py +3 -3
  33. mplang/{v2/dialects → dialects}/func.py +2 -2
  34. mplang/{v2/dialects → dialects}/phe.py +6 -6
  35. mplang/{v2/dialects → dialects}/simp.py +6 -6
  36. mplang/{v2/dialects → dialects}/spu.py +7 -7
  37. mplang/{v2/dialects → dialects}/store.py +2 -2
  38. mplang/{v2/dialects → dialects}/table.py +3 -3
  39. mplang/{v2/dialects → dialects}/tee.py +6 -6
  40. mplang/{v2/dialects → dialects}/tensor.py +5 -5
  41. mplang/{v2/edsl → edsl}/__init__.py +3 -3
  42. mplang/{v2/edsl → edsl}/context.py +6 -6
  43. mplang/{v2/edsl → edsl}/graph.py +5 -5
  44. mplang/{v2/edsl → edsl}/jit.py +2 -2
  45. mplang/{v2/edsl → edsl}/object.py +1 -1
  46. mplang/{v2/edsl → edsl}/primitive.py +5 -5
  47. mplang/{v2/edsl → edsl}/printer.py +1 -1
  48. mplang/{v2/edsl → edsl}/serde.py +1 -1
  49. mplang/{v2/edsl → edsl}/tracer.py +7 -7
  50. mplang/{v2/edsl → edsl}/typing.py +1 -1
  51. mplang/{v2/kernels → kernels}/ldpc.cpp +13 -13
  52. mplang/{v2/kernels → kernels}/okvs.cpp +4 -4
  53. mplang/{v2/kernels → kernels}/okvs_opt.cpp +31 -31
  54. mplang/{v2/kernels → kernels}/py_kernels.py +1 -1
  55. mplang/{v2/libs → libs}/collective.py +5 -5
  56. mplang/{v2/libs → libs}/device/__init__.py +1 -1
  57. mplang/{v2/libs → libs}/device/api.py +12 -12
  58. mplang/{v2/libs → libs}/ml/__init__.py +1 -1
  59. mplang/{v2/libs → libs}/ml/sgb.py +4 -4
  60. mplang/{v2/libs → libs}/mpc/__init__.py +3 -3
  61. mplang/{v2/libs → libs}/mpc/_utils.py +2 -2
  62. mplang/{v2/libs → libs}/mpc/analytics/aggregation.py +1 -1
  63. mplang/{v2/libs → libs}/mpc/analytics/groupby.py +2 -2
  64. mplang/{v2/libs → libs}/mpc/analytics/permutation.py +3 -3
  65. mplang/{v2/libs → libs}/mpc/ot/base.py +3 -3
  66. mplang/{v2/libs → libs}/mpc/ot/extension.py +2 -2
  67. mplang/{v2/libs → libs}/mpc/ot/silent.py +4 -4
  68. mplang/{v2/libs → libs}/mpc/psi/cuckoo.py +3 -3
  69. mplang/{v2/libs → libs}/mpc/psi/okvs.py +1 -1
  70. mplang/{v2/libs → libs}/mpc/psi/okvs_gct.py +3 -3
  71. mplang/{v2/libs → libs}/mpc/psi/oprf.py +3 -3
  72. mplang/{v2/libs → libs}/mpc/psi/rr22.py +7 -7
  73. mplang/{v2/libs → libs}/mpc/psi/unbalanced.py +4 -4
  74. mplang/{v2/libs → libs}/mpc/vole/gilboa.py +3 -3
  75. mplang/{v2/libs → libs}/mpc/vole/ldpc.py +2 -2
  76. mplang/{v2/libs → libs}/mpc/vole/silver.py +6 -6
  77. mplang/{v2/runtime → runtime}/interpreter.py +11 -11
  78. mplang/{v2/runtime → runtime}/value.py +2 -2
  79. mplang/{v1/runtime → utils}/__init__.py +18 -15
  80. mplang/{v1/utils → utils}/func_utils.py +1 -1
  81. {mplang_nightly-0.1.dev269.dist-info → mplang_nightly-0.1.dev270.dist-info}/METADATA +2 -2
  82. mplang_nightly-0.1.dev270.dist-info/RECORD +102 -0
  83. mplang/v1/__init__.py +0 -157
  84. mplang/v1/_device.py +0 -602
  85. mplang/v1/analysis/__init__.py +0 -37
  86. mplang/v1/analysis/diagram.py +0 -567
  87. mplang/v1/core/__init__.py +0 -157
  88. mplang/v1/core/cluster.py +0 -343
  89. mplang/v1/core/comm.py +0 -281
  90. mplang/v1/core/context_mgr.py +0 -50
  91. mplang/v1/core/dtypes.py +0 -335
  92. mplang/v1/core/expr/__init__.py +0 -80
  93. mplang/v1/core/expr/ast.py +0 -542
  94. mplang/v1/core/expr/evaluator.py +0 -581
  95. mplang/v1/core/expr/printer.py +0 -285
  96. mplang/v1/core/expr/transformer.py +0 -141
  97. mplang/v1/core/expr/utils.py +0 -78
  98. mplang/v1/core/expr/visitor.py +0 -85
  99. mplang/v1/core/expr/walk.py +0 -387
  100. mplang/v1/core/interp.py +0 -160
  101. mplang/v1/core/mask.py +0 -325
  102. mplang/v1/core/mpir.py +0 -965
  103. mplang/v1/core/mpobject.py +0 -117
  104. mplang/v1/core/mptype.py +0 -407
  105. mplang/v1/core/pfunc.py +0 -130
  106. mplang/v1/core/primitive.py +0 -877
  107. mplang/v1/core/table.py +0 -218
  108. mplang/v1/core/tensor.py +0 -75
  109. mplang/v1/core/tracer.py +0 -383
  110. mplang/v1/host.py +0 -130
  111. mplang/v1/kernels/__init__.py +0 -41
  112. mplang/v1/kernels/base.py +0 -125
  113. mplang/v1/kernels/basic.py +0 -240
  114. mplang/v1/kernels/context.py +0 -369
  115. mplang/v1/kernels/crypto.py +0 -122
  116. mplang/v1/kernels/fhe.py +0 -858
  117. mplang/v1/kernels/mock_tee.py +0 -72
  118. mplang/v1/kernels/phe.py +0 -1864
  119. mplang/v1/kernels/spu.py +0 -341
  120. mplang/v1/kernels/sql_duckdb.py +0 -44
  121. mplang/v1/kernels/stablehlo.py +0 -90
  122. mplang/v1/kernels/value.py +0 -626
  123. mplang/v1/ops/__init__.py +0 -35
  124. mplang/v1/ops/base.py +0 -424
  125. mplang/v1/ops/basic.py +0 -294
  126. mplang/v1/ops/crypto.py +0 -262
  127. mplang/v1/ops/fhe.py +0 -272
  128. mplang/v1/ops/jax_cc.py +0 -147
  129. mplang/v1/ops/nnx_cc.py +0 -168
  130. mplang/v1/ops/phe.py +0 -216
  131. mplang/v1/ops/spu.py +0 -151
  132. mplang/v1/ops/sql_cc.py +0 -303
  133. mplang/v1/ops/tee.py +0 -36
  134. mplang/v1/protos/v1alpha1/mpir_pb2.py +0 -63
  135. mplang/v1/protos/v1alpha1/mpir_pb2.pyi +0 -557
  136. mplang/v1/protos/v1alpha1/value_pb2.py +0 -34
  137. mplang/v1/protos/v1alpha1/value_pb2.pyi +0 -169
  138. mplang/v1/runtime/channel.py +0 -230
  139. mplang/v1/runtime/cli.py +0 -451
  140. mplang/v1/runtime/client.py +0 -456
  141. mplang/v1/runtime/communicator.py +0 -131
  142. mplang/v1/runtime/data_providers.py +0 -303
  143. mplang/v1/runtime/driver.py +0 -324
  144. mplang/v1/runtime/exceptions.py +0 -27
  145. mplang/v1/runtime/http_api.md +0 -56
  146. mplang/v1/runtime/link_comm.py +0 -196
  147. mplang/v1/runtime/server.py +0 -501
  148. mplang/v1/runtime/session.py +0 -270
  149. mplang/v1/runtime/simulation.py +0 -324
  150. mplang/v1/simp/__init__.py +0 -13
  151. mplang/v1/simp/api.py +0 -353
  152. mplang/v1/simp/mpi.py +0 -131
  153. mplang/v1/simp/party.py +0 -225
  154. mplang/v1/simp/random.py +0 -120
  155. mplang/v1/simp/smpc.py +0 -238
  156. mplang/v1/utils/__init__.py +0 -13
  157. mplang/v1/utils/crypto.py +0 -32
  158. mplang/v1/utils/spu_utils.py +0 -130
  159. mplang/v1/utils/table_utils.py +0 -185
  160. mplang/v2/__init__.py +0 -424
  161. mplang_nightly-0.1.dev269.dist-info/RECORD +0 -180
  162. /mplang/{v2/backends → backends}/channel.py +0 -0
  163. /mplang/{v2/edsl → edsl}/README.md +0 -0
  164. /mplang/{v2/edsl → edsl}/registry.py +0 -0
  165. /mplang/{v2/kernels → kernels}/Makefile +0 -0
  166. /mplang/{v2/kernels → kernels}/__init__.py +0 -0
  167. /mplang/{v2/kernels → kernels}/gf128.cpp +0 -0
  168. /mplang/{v2/libs → libs}/device/cluster.py +0 -0
  169. /mplang/{v2/libs → libs}/mpc/analytics/__init__.py +0 -0
  170. /mplang/{v2/libs → libs}/mpc/analytics/groupby.md +0 -0
  171. /mplang/{v2/libs → libs}/mpc/common/constants.py +0 -0
  172. /mplang/{v2/libs → libs}/mpc/ot/__init__.py +0 -0
  173. /mplang/{v2/libs → libs}/mpc/psi/__init__.py +0 -0
  174. /mplang/{v2/libs → libs}/mpc/vole/__init__.py +0 -0
  175. /mplang/{v2/runtime → runtime}/__init__.py +0 -0
  176. /mplang/{v2/runtime → runtime}/dialect_state.py +0 -0
  177. /mplang/{v2/runtime → runtime}/object_store.py +0 -0
  178. {mplang_nightly-0.1.dev269.dist-info → mplang_nightly-0.1.dev270.dist-info}/WHEEL +0 -0
  179. {mplang_nightly-0.1.dev269.dist-info → mplang_nightly-0.1.dev270.dist-info}/entry_points.txt +0 -0
  180. {mplang_nightly-0.1.dev269.dist-info → mplang_nightly-0.1.dev270.dist-info}/licenses/LICENSE +0 -0
mplang/v1/runtime/cli.py DELETED
@@ -1,451 +0,0 @@
1
- #!/usr/bin/env python3
2
- # Copyright 2025 Ant Group Co., Ltd.
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
-
16
- """
17
- Command-line interface for managing MPLang clusters.
18
- """
19
-
20
- import argparse
21
- import asyncio
22
- import multiprocessing
23
- import sys
24
- from typing import Any
25
-
26
- import uvicorn
27
- import yaml
28
-
29
- from mplang.v1.core import ClusterSpec
30
- from mplang.v1.runtime.client import HttpExecutorClient
31
- from mplang.v1.runtime.server import app
32
-
33
-
34
- def load_config(config_path: str) -> ClusterSpec:
35
- """Load configuration from a YAML file."""
36
- with open(config_path) as file:
37
- conf = yaml.safe_load(file)
38
- return ClusterSpec.from_dict(conf)
39
-
40
-
41
- def run_server(port: int, node_id: str) -> None:
42
- """Run a uvicorn server on a specific port.
43
-
44
- Args:
45
- port: The port to run the server on
46
- node_id: The ID of the node
47
- """
48
- log_config = {
49
- "version": 1,
50
- "disable_existing_loggers": False,
51
- "formatters": {
52
- "default": {
53
- "()": "uvicorn.logging.DefaultFormatter",
54
- "fmt": f"%(levelname)s: [{node_id}] %(message)s",
55
- "use_colors": None,
56
- },
57
- "access": {
58
- "()": "uvicorn.logging.AccessFormatter",
59
- "fmt": f'%(levelname)s: [{node_id}] %(client_addr)s - "%(request_line)s" %(status_code)s',
60
- "use_colors": None,
61
- },
62
- },
63
- "handlers": {
64
- "default": {
65
- "formatter": "default",
66
- "class": "logging.StreamHandler",
67
- "stream": "ext://sys.stderr",
68
- },
69
- "access": {
70
- "formatter": "access",
71
- "class": "logging.StreamHandler",
72
- "stream": "ext://sys.stdout",
73
- },
74
- },
75
- "loggers": {
76
- "uvicorn": {"handlers": ["default"], "level": "INFO", "propagate": False},
77
- "uvicorn.error": {"level": "INFO"},
78
- "uvicorn.access": {
79
- "handlers": ["access"],
80
- "level": "INFO",
81
- "propagate": False,
82
- },
83
- },
84
- }
85
- config = uvicorn.Config(
86
- app,
87
- host="127.0.0.1",
88
- port=port,
89
- log_config=log_config,
90
- ws="none", # Disable websockets
91
- )
92
- server = uvicorn.Server(config)
93
- server.run()
94
-
95
-
96
- def start_command(args: argparse.Namespace) -> int:
97
- """Handle the start command.
98
-
99
- Args:
100
- args: Parsed command line arguments
101
-
102
- Returns:
103
- Exit code (0 for success, non-zero for failure)
104
- """
105
- try:
106
- # Load configuration
107
- cluster_spec = load_config(args.config)
108
- nodes = cluster_spec.nodes
109
-
110
- if not nodes:
111
- print("No nodes defined in configuration")
112
- return 1
113
-
114
- # Find the endpoint for the specified node
115
- node_id = args.node_id
116
- if node_id not in nodes:
117
- print(f"Node {node_id} not found in configuration")
118
- return 1
119
-
120
- endpoint = nodes[node_id].endpoint
121
- # Extract port from endpoint (format: host:port)
122
- port = int(endpoint.split(":")[-1])
123
-
124
- print(f"Starting node {node_id} on port {port}...")
125
- # Run the server directly (blocking)
126
- run_server(port, node_id)
127
-
128
- return 0
129
- except Exception as e:
130
- print(f"Error starting node: {e}")
131
- return 1
132
-
133
-
134
- def start_cluster_command(args: argparse.Namespace) -> int:
135
- """Handle the start-cluster command.
136
-
137
- Args:
138
- args: Parsed command line arguments
139
-
140
- Returns:
141
- Exit code (0 for success, non-zero for failure)
142
- """
143
- try:
144
- # Load configuration
145
- cluster_spec = load_config(args.config)
146
- nodes = cluster_spec.nodes
147
-
148
- if not nodes:
149
- print("No nodes defined in configuration")
150
- return 1
151
-
152
- # Start a process for each node
153
- processes = []
154
- for node_id, node in nodes.items():
155
- # Extract port from endpoint (format: host:port)
156
- port = int(node.endpoint.split(":")[-1])
157
-
158
- # Create and start process
159
- process = multiprocessing.Process(target=run_server, args=(port, node_id))
160
- process.start()
161
- processes.append((node_id, process))
162
- print(f"Started node {node_id} on port {port} (PID: {process.pid})")
163
-
164
- print(f"Started {len(processes)} nodes in cluster")
165
- print("Press Ctrl+C to stop all nodes")
166
-
167
- # Wait for all processes to complete or for interruption
168
- try:
169
- for _, process in processes:
170
- process.join()
171
- except KeyboardInterrupt:
172
- print("\nStopping all nodes...")
173
- for _, process in processes:
174
- if process.is_alive():
175
- process.terminate()
176
- process.join(timeout=5)
177
- if process.is_alive():
178
- process.kill()
179
- print("All nodes stopped")
180
-
181
- return 0
182
- except Exception as e:
183
- print(f"Error starting cluster: {e}")
184
- return 1
185
-
186
-
187
- def status_command(args: argparse.Namespace) -> int:
188
- """Handle the status command.
189
-
190
- Args:
191
- args: Parsed command line arguments
192
-
193
- Returns:
194
- Exit code (0 for success, non-zero for failure)
195
- """
196
-
197
- async def _get_node_status(
198
- node_id: str, endpoint: str, details: int = 0, timeout: int = 60
199
- ) -> dict[str, Any]:
200
- """Get status information for a single node.
201
-
202
- Args:
203
- node_id: Identifier for the node
204
- endpoint: HTTP endpoint of the node
205
- details: Verbosity level (0=basic, 1=-v, 2=-vv)
206
- timeout: HTTP request timeout in seconds (default: 60)
207
- """
208
-
209
- client = HttpExecutorClient(endpoint, timeout)
210
- status: dict[str, Any] = {
211
- "node_id": node_id,
212
- "endpoint": client.endpoint, # Use the normalized endpoint from client
213
- "healthy": False,
214
- "sessions": [],
215
- "error": None,
216
- }
217
-
218
- try:
219
- # Check node health
220
- status["healthy"] = await client.health_check()
221
-
222
- if status["healthy"]:
223
- # Get sessions on this node
224
- sessions = await client.list_sessions()
225
- status["sessions"] = sessions
226
-
227
- # Get detailed session info based on verbosity level
228
- # details=1 (-v): show session names and basic counts
229
- # details=2 (-vv): show full computation and symbol lists
230
- if details >= 1:
231
- session_details = []
232
- for session_name in sessions:
233
- try:
234
- # Get computations and symbols for each session
235
- computations = await client.list_computations(session_name)
236
- symbols = await client.list_symbols(session_name)
237
- session_info = {
238
- "name": session_name,
239
- "computations": len(computations),
240
- "symbols": len(symbols),
241
- }
242
- # Include full lists only at -vv level
243
- if details >= 2:
244
- session_info["computation_list"] = computations
245
- session_info["symbol_list"] = symbols
246
- session_details.append(session_info)
247
- except Exception as e:
248
- session_details.append({
249
- "name": session_name,
250
- "error": str(e),
251
- })
252
- status["session_details"] = session_details
253
-
254
- except Exception as e:
255
- status["error"] = str(e)
256
-
257
- finally:
258
- await client.close()
259
-
260
- return status
261
-
262
- async def _collect_cluster_status(
263
- nodes: dict[str, str], details: int = 0
264
- ) -> list[dict[str, Any] | BaseException]:
265
- """Collect status from all nodes concurrently.
266
-
267
- Args:
268
- nodes: Dictionary mapping node IDs to their HTTP endpoints
269
- details: Verbosity level (0=basic, 1=-v, 2=-vv)
270
-
271
- Returns:
272
- List of status dictionaries or exceptions for each node
273
- """
274
- tasks = [
275
- _get_node_status(node_id, endpoint, details)
276
- for node_id, endpoint in nodes.items()
277
- ]
278
- return await asyncio.gather(*tasks, return_exceptions=True)
279
-
280
- try:
281
- # Load configuration
282
- cluster_spec = load_config(args.config)
283
- nodes = cluster_spec.nodes
284
-
285
- if not nodes:
286
- print("No nodes defined in configuration")
287
- return 1
288
-
289
- node_addrs = {node_id: node.endpoint for node_id, node in nodes.items()}
290
-
291
- # Collect status from all nodes
292
- verbosity = getattr(args, "verbose", 0)
293
- cluster_status = asyncio.run(_collect_cluster_status(node_addrs, verbosity))
294
-
295
- # Basic node health check
296
- print("Node Status:")
297
- print("-" * 50)
298
- all_healthy = True
299
-
300
- valid_statuses = []
301
- for status in cluster_status:
302
- if isinstance(status, BaseException):
303
- print(f"{'UNKNOWN':<15} {'UNKNOWN':<20} ERROR - {status}")
304
- all_healthy = False
305
- continue
306
-
307
- valid_statuses.append(status)
308
- node_id = status["node_id"]
309
- endpoint = status["endpoint"]
310
-
311
- if status["error"]:
312
- print(f"{node_id:<15} {endpoint:<20} ERROR - {status['error']}")
313
- all_healthy = False
314
- elif status["healthy"]:
315
- session_count = len(status["sessions"])
316
- print(
317
- f"{node_id:<15} {endpoint:<20} HEALTHY ({session_count} sessions)"
318
- )
319
- else:
320
- print(f"{node_id:<15} {endpoint:<20} UNHEALTHY")
321
- all_healthy = False
322
-
323
- # If verbose mode is enabled, show detailed information
324
- if verbosity >= 1 and valid_statuses:
325
- print("\nDetailed Runtime Status:")
326
- print("-" * 50)
327
-
328
- for status in valid_statuses:
329
- node_id = status["node_id"]
330
-
331
- if status["error"]:
332
- print(f"{node_id}: Error - {status['error']}")
333
- continue
334
-
335
- if not status["healthy"]:
336
- print(f"{node_id}: Node is unhealthy")
337
- continue
338
-
339
- sessions = status.get("session_details", status["sessions"])
340
- print(f"{node_id}: {len(sessions)} session(s)")
341
-
342
- if isinstance(sessions, list) and sessions:
343
- for session in sessions:
344
- if isinstance(session, str):
345
- # Simple session name only
346
- print(f" - Session '{session}'")
347
- elif isinstance(session, dict):
348
- # Detailed session info
349
- session_name = session["name"]
350
- if "error" in session:
351
- print(
352
- f" - Session '{session_name}': Error - {session['error']}"
353
- )
354
- else:
355
- computations = session.get("computations", 0)
356
- symbols = session.get("symbols", 0)
357
- print(
358
- f" - Session '{session_name}': {computations} computations, {symbols} symbols"
359
- )
360
- # At -vv level, show the actual lists
361
- if verbosity >= 2:
362
- comp_list = session.get("computation_list", [])
363
- symbol_list = session.get("symbol_list", [])
364
- if comp_list:
365
- print(f" Computations: {comp_list}")
366
- if symbol_list:
367
- print(f" Symbols: {symbol_list}")
368
- elif not sessions:
369
- print(" - No active sessions")
370
-
371
- return 0 if all_healthy else 1
372
- except Exception as e:
373
- print(f"Error checking status: {e}")
374
- return 1
375
-
376
-
377
- def main() -> int:
378
- """Main entry point for the CLI."""
379
- parser = argparse.ArgumentParser(
380
- prog="mplang-cli",
381
- description="Command-line interface for managing MPLang clusters",
382
- )
383
-
384
- # Add subcommands
385
- subparsers = parser.add_subparsers(dest="command", help="Available commands")
386
-
387
- # Help command
388
- subparsers.add_parser("help", help="Show this help message and exit")
389
-
390
- # Status command
391
- status_parser = subparsers.add_parser(
392
- "status", help="Check status of nodes in the cluster"
393
- )
394
- status_parser.add_argument(
395
- "--config", "-c", required=True, help="Path to the YAML configuration file"
396
- )
397
- status_parser.add_argument(
398
- "--verbose",
399
- "-v",
400
- action="count",
401
- default=0,
402
- help="Increase verbosity: -v for session details, -vv for full lists",
403
- )
404
- status_parser.set_defaults(func=status_command)
405
-
406
- # Start command
407
- start_parser = subparsers.add_parser("start", help="Start a single MPC node")
408
- start_parser.add_argument(
409
- "--config", "-c", required=True, help="Path to the YAML configuration file"
410
- )
411
- start_parser.add_argument(
412
- "--node-id", "-n", required=True, type=str, help="ID of the node to start"
413
- )
414
- start_parser.set_defaults(func=start_command)
415
-
416
- # Start cluster command
417
- start_cluster_parser = subparsers.add_parser(
418
- "start-cluster", help="Start all MPC nodes in the cluster"
419
- )
420
- start_cluster_parser.add_argument(
421
- "--config", "-c", required=True, help="Path to the YAML configuration file"
422
- )
423
- start_cluster_parser.set_defaults(func=start_cluster_command)
424
-
425
- # Up command (alias for start-cluster)
426
- up_parser = subparsers.add_parser(
427
- "up", help="Start all MPC nodes in the cluster (alias for start-cluster)"
428
- )
429
- up_parser.add_argument(
430
- "--config", "-c", required=True, help="Path to the YAML configuration file"
431
- )
432
- up_parser.set_defaults(func=start_cluster_command)
433
-
434
- # Parse arguments
435
- args = parser.parse_args()
436
-
437
- # Handle help command
438
- if args.command == "help" or args.command is None:
439
- parser.print_help()
440
- return 0
441
-
442
- # Handle subcommands
443
- if hasattr(args, "func"):
444
- result = args.func(args)
445
- return int(result)
446
-
447
- return 0
448
-
449
-
450
- if __name__ == "__main__":
451
- sys.exit(main())