turingdb 1.16.1.dev7__cp311-cp311-manylinux_2_35_x86_64.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 (52) hide show
  1. bin/turing-import +0 -0
  2. bin/turingdb +0 -0
  3. lib/cmake/tabulate/tabulateConfig.cmake +31 -0
  4. lib/cmake/tabulate/tabulateConfigVersion.cmake +43 -0
  5. lib/cmake/tabulate/tabulateTargets.cmake +107 -0
  6. lib/cmake/termcolor/termcolor-config.cmake +28 -0
  7. lib/cmake/termcolor/termcolor-targets.cmake +107 -0
  8. turingdb/__init__.py +92 -0
  9. turingdb/_version.py +34 -0
  10. turingdb/exceptions.py +3 -0
  11. turingdb/path.py +16 -0
  12. turingdb/protocol.py +7 -0
  13. turingdb/s3.py +137 -0
  14. turingdb/turingdb.py +242 -0
  15. turingdb/turingsh/__init__.py +3 -0
  16. turingdb/turingsh/command.py +24 -0
  17. turingdb/turingsh/greeter.py +42 -0
  18. turingdb/turingsh/turingsh.py +367 -0
  19. turingdb-1.16.1.dev7.dist-info/METADATA +19 -0
  20. turingdb-1.16.1.dev7.dist-info/RECORD +52 -0
  21. turingdb-1.16.1.dev7.dist-info/WHEEL +5 -0
  22. turingdb-1.16.1.dev7.dist-info/entry_points.txt +3 -0
  23. turingdb-1.16.1.dev7.dist-info/licenses/LICENSE +5 -0
  24. turingdb-1.16.1.dev7.dist-info/sboms/auditwheel.cdx.json +1 -0
  25. turingdb.libs/libbrotlicommon-abf86ae9.so.1.0.9 +0 -0
  26. turingdb.libs/libbrotlidec-db9dbda7.so.1.0.9 +0 -0
  27. turingdb.libs/libcom_err-f196091d.so.2.1 +0 -0
  28. turingdb.libs/libcrypto-ef58def3.so.3 +0 -0
  29. turingdb.libs/libcurl-ef05c8ea.so.4.7.0 +0 -0
  30. turingdb.libs/libffi-247da4d5.so.8.1.0 +0 -0
  31. turingdb.libs/libgmp-4dc20a90.so.10.4.1 +0 -0
  32. turingdb.libs/libgnutls-a1c10edc.so.30.31.0 +0 -0
  33. turingdb.libs/libgssapi_krb5-74c938dc.so.2.2 +0 -0
  34. turingdb.libs/libhogweed-47d56894.so.6.4 +0 -0
  35. turingdb.libs/libidn2-1420c60a.so.0.3.7 +0 -0
  36. turingdb.libs/libk5crypto-43d6a714.so.3.1 +0 -0
  37. turingdb.libs/libkeyutils-ad20d5fb.so.1.9 +0 -0
  38. turingdb.libs/libkrb5-7ccebba4.so.3.3 +0 -0
  39. turingdb.libs/libkrb5support-134342ea.so.0.1 +0 -0
  40. turingdb.libs/liblber-2-ff904533.5.so.0.1.14 +0 -0
  41. turingdb.libs/libldap-2-22fb2ed0.5.so.0.1.14 +0 -0
  42. turingdb.libs/libnettle-2d3bda6c.so.8.4 +0 -0
  43. turingdb.libs/libnghttp2-1cc16764.so.14.20.1 +0 -0
  44. turingdb.libs/libp11-kit-d2b01eaa.so.0.3.0 +0 -0
  45. turingdb.libs/libpsl-95ca960e.so.5.3.2 +0 -0
  46. turingdb.libs/librtmp-2401c4fc.so.1 +0 -0
  47. turingdb.libs/libsasl2-344870a9.so.2.0.25 +0 -0
  48. turingdb.libs/libssh-f4c6722f.so.4.8.7 +0 -0
  49. turingdb.libs/libssl-660a6abe.so.3 +0 -0
  50. turingdb.libs/libtasn1-5982aae4.so.6.6.2 +0 -0
  51. turingdb.libs/libunistring-9c28d595.so.2.2.0 +0 -0
  52. turingdb.libs/libzstd-5df4f4df.so.1.4.8 +0 -0
turingdb/turingdb.py ADDED
@@ -0,0 +1,242 @@
1
+ import time
2
+ from typing import Literal, Optional
3
+
4
+ from .exceptions import TuringDBException
5
+ from .s3 import S3Client
6
+
7
+
8
+ class TuringDB:
9
+ DEFAULT_HEADERS = {
10
+ "Accept": "application/json",
11
+ "Content-Type": "application/json",
12
+ }
13
+
14
+ def __init__(
15
+ self,
16
+ instance_id: str = "",
17
+ auth_token: str = "",
18
+ host: str = "http://localhost:6666",
19
+ timeout: Optional[int] = None,
20
+ ):
21
+ import copy
22
+
23
+ import httpx
24
+
25
+ self.host = host
26
+ self._client = httpx.Client(
27
+ auth=None,
28
+ verify=False,
29
+ timeout=timeout,
30
+ )
31
+ self._s3_client: Optional[S3Client] = None
32
+ self._query_exec_time: Optional[float] = None
33
+ self._total_exec_time: Optional[float] = None
34
+ self._t0: float = 0
35
+ self._t1: float = 0
36
+ self._timeout = timeout
37
+
38
+ self._params = {
39
+ "graph": "default",
40
+ }
41
+
42
+ self._headers = copy.deepcopy(TuringDB.DEFAULT_HEADERS)
43
+
44
+ if instance_id != "":
45
+ self._headers["Turing-Instance-Id"] = instance_id
46
+
47
+ if auth_token != "":
48
+ self._headers["Authorization"] = f"Bearer {auth_token}"
49
+
50
+ def try_reach(self, timeout: int = 5):
51
+ self._client.timeout = timeout
52
+ self.list_available_graphs()
53
+ self._client.timeout = self._timeout
54
+
55
+ def warmup(self, timeout: int = 5):
56
+ self._client.timeout = timeout
57
+ self.query("LIST GRAPH")
58
+ self._client.timeout = self._timeout
59
+
60
+ def list_available_graphs(self) -> list[str]:
61
+ return self._send_request("list_avail_graphs")["data"]
62
+
63
+ def list_loaded_graphs(self) -> list[str]:
64
+ return self._send_request("list_loaded_graphs")["data"][0][0]
65
+
66
+ def is_graph_loaded(self) -> bool:
67
+ return self._send_request(
68
+ "is_graph_loaded", params={"graph": self.get_graph()}
69
+ )["data"]
70
+
71
+ def load_graph(self, graph_name: str, raise_if_loaded: bool = True):
72
+ try:
73
+ return self._send_request("load_graph", params={"graph": graph_name})
74
+ except TuringDBException as e:
75
+ if raise_if_loaded or e.__str__() != "GRAPH_ALREADY_EXISTS":
76
+ raise e
77
+
78
+ def create_graph(self, graph_name: str):
79
+ return self.query(f"create graph {graph_name}")
80
+
81
+ def query(self, query: str):
82
+ json = self._send_request("query", data=query, params=self._params)
83
+
84
+ if not isinstance(json, dict):
85
+ raise TuringDBException("Invalid response from the server")
86
+
87
+ return self._parse_chunks(json)
88
+
89
+ def set_commit(self, commit: str):
90
+ self._params["commit"] = commit
91
+
92
+ def set_change(self, change: int | str):
93
+ if isinstance(change, int):
94
+ change = f"{change:x}"
95
+ self._params["change"] = change
96
+
97
+ def checkout(self, change: int | Literal["main"] = "main", commit: str = "HEAD"):
98
+ if change == "main":
99
+ if "change" in self._params:
100
+ del self._params["change"]
101
+ else:
102
+ self.set_change(change)
103
+
104
+ if commit == "HEAD":
105
+ if "commit" in self._params:
106
+ del self._params["commit"]
107
+ else:
108
+ self.set_commit(commit)
109
+
110
+ def new_change(self) -> int:
111
+ if self._params.get("change") is not None:
112
+ raise TuringDBException("Cannot create a new change while working on one")
113
+
114
+ if self._params.get("commit") is not None:
115
+ raise TuringDBException("Cannot create a new change while working on a commit")
116
+
117
+ res = self.query("CHANGE NEW")
118
+ self._params["change"] = res.loc[0, "changeID"]
119
+ change_id = int(self._params["change"])
120
+ return change_id
121
+
122
+
123
+ def set_graph(self, graph_name: str):
124
+ self._params["graph"] = graph_name
125
+
126
+ def get_graph(self) -> str:
127
+ return self._params["graph"]
128
+
129
+ def s3_connect(
130
+ self,
131
+ bucket_name: str,
132
+ access_key: Optional[str] = None,
133
+ secret_key: Optional[str] = None,
134
+ region: Optional[str] = None,
135
+ use_scratch: bool = True,
136
+ ):
137
+ from .s3 import S3Client
138
+
139
+ self._s3_client = S3Client(
140
+ bucket_name, access_key, secret_key, region, use_scratch
141
+ )
142
+ self._s3_client.connect(self)
143
+
144
+ def transfer(self, src: str, dst: str):
145
+ if self._s3_client is None:
146
+ raise TuringDBException("S3 client is not connected")
147
+
148
+ self._s3_client.transfer(src, dst)
149
+
150
+ def _send_request(
151
+ self,
152
+ path: str,
153
+ data: Optional[dict | str] = None,
154
+ params: Optional[dict] = None,
155
+ ):
156
+ import orjson
157
+
158
+ self._query_exec_time = None
159
+ self._total_exec_time = None
160
+ self._t0 = time.time()
161
+
162
+ if data is None:
163
+ data = ""
164
+
165
+ url = f"{self.host}/{path}"
166
+
167
+ if isinstance(data, dict):
168
+ response = self._client.post(
169
+ url, json=data, params=params, headers=self._headers
170
+ )
171
+ else:
172
+ response = self._client.post(
173
+ url, content=data, params=params, headers=self._headers
174
+ )
175
+ response.raise_for_status()
176
+
177
+ json = orjson.loads(response.text)
178
+
179
+ if isinstance(json, dict):
180
+ err = json.get("error")
181
+ if err is not None:
182
+ details = json.get("error_details")
183
+ if details is not None:
184
+ err = f"{err}: {details}"
185
+ raise TuringDBException(err)
186
+
187
+ self._t1 = time.time()
188
+ self._total_exec_time = (self._t1 - self._t0) * 1000
189
+
190
+ return json
191
+
192
+ def _parse_chunks(self, json: dict):
193
+ import pandas as pd
194
+
195
+ self._query_exec_time = json["time"]
196
+
197
+ header = json["header"]
198
+ column_names = header["column_names"]
199
+ column_types = header["column_types"]
200
+
201
+ if len(column_names) != len(column_types):
202
+ raise Exception("Query response column names and types do not match")
203
+
204
+ dtype_map = {
205
+ "String": "string",
206
+ "Int64": "Int64",
207
+ "UInt64": "UInt64",
208
+ "Double": "float64",
209
+ "Bool": "boolean",
210
+ }
211
+
212
+ df = pd.DataFrame()
213
+
214
+ for chunk in json["data"]:
215
+ df_chunk = pd.DataFrame({
216
+ cname: pd.Series(col, dtype=dtype_map.get(ctype, "object"))
217
+ for (cname, ctype), col in zip(zip(column_names, column_types), chunk)
218
+ })
219
+ df = pd.concat([df, df_chunk], ignore_index=True)
220
+
221
+ self._t1 = time.time()
222
+ self._total_exec_time = (self._t1 - self._t0) * 1000
223
+
224
+ return df
225
+
226
+ def get_query_exec_time(self) -> Optional[float]:
227
+ return self._query_exec_time
228
+
229
+ def get_total_exec_time(self) -> Optional[float]:
230
+ return self._total_exec_time
231
+
232
+ @property
233
+ def current_graph(self) -> str:
234
+ return self._params["graph"]
235
+
236
+ @property
237
+ def current_commit(self) -> str:
238
+ return self._params.get("commit") or "HEAD"
239
+
240
+ @property
241
+ def current_change(self) -> str:
242
+ return self._params.get("change") or "main"
@@ -0,0 +1,3 @@
1
+ from .turingsh import main
2
+
3
+ __all__ = ["main"]
@@ -0,0 +1,24 @@
1
+ from functools import wraps
2
+
3
+ from click import ClickException
4
+
5
+
6
+ def shell_command(click_cmd):
7
+ """
8
+ Decorator that wraps a Click command to be callable from a shell
9
+ with exception handling instead of sys.exit().
10
+ """
11
+
12
+ @wraps(click_cmd)
13
+ def wrapper(client, *args, **kwargs):
14
+ try:
15
+ return click_cmd.main(
16
+ args=list(args),
17
+ prog_name=click_cmd.name,
18
+ obj=client,
19
+ standalone_mode=False,
20
+ )
21
+ except ClickException as e:
22
+ raise RuntimeError(e.format_message()) from e
23
+
24
+ return wrapper
@@ -0,0 +1,42 @@
1
+ import re
2
+
3
+ from prompt_toolkit.formatted_text import HTML
4
+ from prompt_toolkit.shortcuts import print_formatted_text
5
+
6
+
7
+ def get_visible_width(text):
8
+ """Remove HTML-like tags and get actual visible character count"""
9
+ return len(re.sub(r"<[^>]*>", "", text)) - 2
10
+
11
+
12
+ def center_with_html(text, total_width):
13
+ """Center text accounting for HTML markup"""
14
+ visible_width = get_visible_width(text)
15
+ padding = (total_width - visible_width) // 2
16
+ return " " * padding + text + " " * (total_width - visible_width - padding)
17
+
18
+
19
+ def greet():
20
+
21
+ topbar = (
22
+ "<skyblue>╔═════════════════════════════════════════════════════╗</skyblue>\n"
23
+ )
24
+ botbar = (
25
+ "<skyblue>╚═════════════════════════════════════════════════════╝</skyblue>"
26
+ )
27
+ delimiter = "<skyblue>║</skyblue>"
28
+ title = "<b>TuringDB Interactive Shell</b>"
29
+ help_msg = "Type <i>help</i> for help"
30
+ quit_msg = "Type <i>quit</i> or press <i>Ctrl+D</i> to quit"
31
+
32
+ box_content_width = 51
33
+
34
+ print_formatted_text(
35
+ HTML(
36
+ f"{topbar}"
37
+ f"{delimiter}{center_with_html(title, box_content_width)}{delimiter}\n"
38
+ f"{delimiter}{center_with_html(help_msg, box_content_width)}{delimiter}\n"
39
+ f"{delimiter}{center_with_html(quit_msg, box_content_width)}{delimiter}\n"
40
+ f"{botbar}"
41
+ )
42
+ )
@@ -0,0 +1,367 @@
1
+ """
2
+ TuringDB Shell Client
3
+ """
4
+
5
+ import traceback
6
+ from html import escape
7
+
8
+ import click
9
+ from prompt_toolkit import prompt
10
+ from prompt_toolkit.completion import WordCompleter
11
+ from prompt_toolkit.formatted_text import HTML
12
+ from prompt_toolkit.history import InMemoryHistory
13
+ from prompt_toolkit.shortcuts import print_formatted_text
14
+
15
+ from turingdb import TuringDB, TuringDBException
16
+ from turingdb.turingsh.command import shell_command
17
+
18
+ from . import greeter
19
+
20
+ CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
21
+
22
+
23
+ class ShellException(Exception):
24
+ pass
25
+
26
+
27
+ def create_completer():
28
+ """Create command completer"""
29
+ commands = [
30
+ # Shell keywords
31
+ "cd",
32
+ "LIST_AVAIL_GRAPHS",
33
+ "LIST_LOADED_GRAPHS",
34
+ "help",
35
+ "quit",
36
+ "checkout",
37
+ # Query keywords
38
+ "DESCENDING",
39
+ "CONSTRAINT",
40
+ "MANDATORY",
41
+ "ASCENDING",
42
+ "OPTIONAL",
43
+ "CONTAINS",
44
+ "DISTINCT",
45
+ "EXTRACT",
46
+ "REQUIRE",
47
+ "COLLECT",
48
+ "STARTS",
49
+ "UNIQUE",
50
+ "FILTER",
51
+ "SINGLE",
52
+ "SCALAR",
53
+ "UNWIND",
54
+ "REMOVE",
55
+ "RETURN",
56
+ "CREATE",
57
+ "DELETE",
58
+ "DETACH",
59
+ "EXISTS",
60
+ "IS NOT",
61
+ "LIMIT",
62
+ "YIELD",
63
+ "MATCH",
64
+ "MERGE",
65
+ "ORDER",
66
+ "WHERE",
67
+ "UNION",
68
+ "FALSE",
69
+ "COUNT",
70
+ "DESC",
71
+ "CALL",
72
+ "NULL",
73
+ "TRUE",
74
+ "WHEN",
75
+ "NONE",
76
+ "THEN",
77
+ "ELSE",
78
+ "CASE",
79
+ "ENDS",
80
+ "DROP",
81
+ "SKIP",
82
+ "WITH",
83
+ "ANY",
84
+ "SET",
85
+ "ALL",
86
+ "ASC",
87
+ "NOT",
88
+ "END",
89
+ "XOR",
90
+ "FOR",
91
+ "ADD",
92
+ "AND",
93
+ "OR",
94
+ "IN",
95
+ "IS",
96
+ "BY",
97
+ "DO",
98
+ "OF",
99
+ "ON",
100
+ "IF",
101
+ "AS",
102
+ ]
103
+ return WordCompleter(commands, ignore_case=True)
104
+
105
+
106
+ @click.group(invoke_without_command=True, context_settings=CONTEXT_SETTINGS)
107
+ @click.option(
108
+ "--host",
109
+ "-l",
110
+ default="https://engines.turingdb.ai/sdk",
111
+ help="Change the address host",
112
+ )
113
+ @click.option("--local", "-L", is_flag=True, default=False, help="Use a local instance")
114
+ @click.option("--auth-token", "-p", default="", help="Authentication token")
115
+ @click.option("--instance-id", "-i", default="", help="Instance ID")
116
+ @click.pass_context
117
+ def main(ctx, host, local, auth_token, instance_id):
118
+ """TuringDB Shell - Interactive database client"""
119
+ if host == "https://engines.turingdb.ai/sdk":
120
+ # Host was not specified, use default
121
+ if local:
122
+ host = "http://localhost:6666"
123
+ else:
124
+ if auth_token == "" or instance_id == "":
125
+ print_formatted_text(
126
+ HTML("<red>✘ Missing authentication information</red>")
127
+ )
128
+ print_formatted_text(
129
+ HTML("<red>✘ Provide --auth-token and --instance-id</red>")
130
+ )
131
+ print()
132
+ exit(1)
133
+
134
+ client = TuringDB(
135
+ host=host,
136
+ auth_token=auth_token,
137
+ instance_id=instance_id,
138
+ )
139
+
140
+ start_shell(client)
141
+
142
+
143
+ def start_shell(client: TuringDB):
144
+ """Start the interactive shell"""
145
+ history = InMemoryHistory()
146
+ completer = create_completer()
147
+
148
+ # Welcome message
149
+ greeter.greet()
150
+
151
+ try:
152
+ client.try_reach()
153
+ client.warmup()
154
+ except Exception as e:
155
+ print_formatted_text(HTML(f"<red>✘ Could not connect to TuringDB.\n{e}</red>"))
156
+ print()
157
+ return
158
+
159
+ print_formatted_text(HTML("<green>✓ Connected to TuringDB</green>"))
160
+ print()
161
+
162
+ shell_commands = {
163
+ "cd": change_graph,
164
+ "list_avail_graphs": list_available_graphs,
165
+ "list_loaded_graphs": list_loaded_graphs,
166
+ "checkout": checkout,
167
+ }
168
+
169
+ while True:
170
+ graph = client.get_graph()
171
+ checkedout = ""
172
+
173
+ if client.current_commit != "HEAD":
174
+ checkedout = f"@{client.current_commit}"
175
+ elif client.current_change != "main":
176
+ checkedout = f"@change-{client.current_change}"
177
+
178
+ try:
179
+ # Get user input with styling
180
+ user_input = prompt(
181
+ HTML(
182
+ f"<b><cyan>turingdb:{graph}{checkedout}</cyan></b><gray>></gray> "
183
+ ),
184
+ completer=completer,
185
+ history=history,
186
+ multiline=False,
187
+ )
188
+
189
+ # Handle commands
190
+ cmd = user_input.strip()
191
+
192
+ if not cmd:
193
+ continue
194
+
195
+ cmd_lower = cmd.lower()
196
+ cmd_words = cmd_lower.split()
197
+
198
+ if len(cmd_words) == 0:
199
+ continue
200
+
201
+ if len(cmd_words) == 1:
202
+ match cmd_lower:
203
+ case "quit":
204
+ print_formatted_text(HTML("<yellow>Goodbye! 👋</yellow>"))
205
+ break
206
+ case "help":
207
+ show_help()
208
+ continue
209
+
210
+ if cmd_words[0] in shell_commands:
211
+ try:
212
+ shell_commands[cmd_words[0]](client, *cmd_words[1:])
213
+ except ShellException as e:
214
+ print_formatted_text(HTML(f"<red>✘ {e}</red>"))
215
+ except Exception as e:
216
+ content = f"{e}\n{traceback.format_exc()}"
217
+ print_formatted_text(
218
+ HTML(f"<red>✘ Fatal error: {escape(str(content))}</red>")
219
+ )
220
+ continue
221
+
222
+ # Execute query
223
+ try:
224
+ result = client.query(cmd)
225
+ print_formatted_text(HTML(f"<white>{escape(str(result))}</white>"))
226
+ except TuringDBException as e:
227
+ content = f"{e}"
228
+ print_formatted_text(HTML(f"<red>✘ {escape(str(content))}</red>"))
229
+ if "CHANGE_NOT_FOUND" in str(e):
230
+ print_formatted_text(
231
+ HTML("<yellow>⚠ Checking out to the latest commit...</yellow>")
232
+ )
233
+ checkout(client)
234
+
235
+ except Exception as e:
236
+ content = f"{e}\n{traceback.format_exc()}"
237
+ print_formatted_text(
238
+ HTML(f"<red>✘ Fatal error: {escape(str(content))}</red>")
239
+ )
240
+
241
+ exec_time = client.get_total_exec_time()
242
+ if exec_time is not None:
243
+ print_formatted_text(
244
+ HTML(
245
+ f"<white>Total execution time: <yellow>{exec_time:.3f}</yellow> milliseconds</white>"
246
+ )
247
+ )
248
+ query_time = client.get_query_exec_time()
249
+ if query_time is not None:
250
+ print_formatted_text(
251
+ HTML(
252
+ f"<white>Including query execution time: <yellow>{query_time:.3f}</yellow> milliseconds</white>"
253
+ )
254
+ )
255
+
256
+ print() # Add spacing
257
+
258
+ except KeyboardInterrupt:
259
+ print_formatted_text(
260
+ HTML('\n<yellow>Use "quit" or Ctrl+D to quit</yellow>')
261
+ )
262
+ continue
263
+ except EOFError:
264
+ print_formatted_text(HTML("\n<yellow>Goodbye! 👋</yellow>"))
265
+ break
266
+
267
+
268
+ def show_help():
269
+ """Display help information"""
270
+ help_text = """<b>Available Commands:</b>
271
+ <cyan>cd my_graph</cyan> - Change active graph
272
+ <cyan>checkout --change change-0</cyan> - Checkout to a specific change
273
+ <cyan>checkout --commit a2daef1f</cyan> - Checkout to a specific commit
274
+ <cyan>checkout</cyan> - Checkout to the latest commit
275
+ <cyan>LIST_AVAIL_GRAPHS</cyan> - List available graphs
276
+ <cyan>LIST_LOADED_GRAPHS</cyan> - List loaded graphs
277
+ <cyan>help</cyan> - Show this help
278
+ <cyan>EXIT</cyan> or <cyan>\\q</cyan> - Quit shell
279
+
280
+ <b>Example queries:</b>
281
+ <cyan>LOAD GRAPH my_graph</cyan> - Load graph
282
+ <cyan>MATCH (n) RETURN n.name</cyan> - Return all node names
283
+
284
+ <b>Tips:</b>
285
+ • Use <i>Tab</i> for command completion
286
+ • Use <i>↑/↓</i> arrows for command history"""
287
+
288
+ print_formatted_text(HTML(help_text))
289
+
290
+
291
+ @shell_command
292
+ @click.command()
293
+ @click.option("--commit", default="HEAD", help="Commit hash or 'HEAD'")
294
+ @click.option("--change", help="ID of the change")
295
+ @click.pass_obj
296
+ def checkout(client, commit: str, change: int):
297
+ """Checkout a commit or a change"""
298
+ try:
299
+ client.checkout(change=change or "main", commit=commit)
300
+ client.query("CALL db.history()")
301
+ except TuringDBException as e:
302
+ content = f"{e}"
303
+ print_formatted_text(HTML(f"<red>✘ {escape(str(content))}</red>"))
304
+ client.checkout()
305
+
306
+
307
+ @shell_command
308
+ @click.command()
309
+ @click.argument("graph-name", default="default")
310
+ @click.pass_obj
311
+ def change_graph(client: TuringDB, graph_name: str):
312
+ """Change the current graph"""
313
+
314
+ try:
315
+ client.set_graph(graph_name)
316
+ if not client.is_graph_loaded():
317
+ print_formatted_text(
318
+ HTML(
319
+ f"<red>✘ Graph {graph_name} needs to be loaded with 'load graph \"{graph_name}\"'</red>"
320
+ )
321
+ )
322
+ client.set_graph("default")
323
+ else:
324
+ print_formatted_text(
325
+ HTML(f"<green>✓ Changed graph to {graph_name}</green>")
326
+ )
327
+ except TuringDBException as e:
328
+ print_formatted_text(HTML(f"<red>✘ {e}</red>"))
329
+ except Exception as e:
330
+ content = f"{e}\n{traceback.format_exc()}"
331
+ print_formatted_text(HTML(f"<red>✘ Fatal error: {escape(str(content))}</red>"))
332
+
333
+
334
+ @shell_command
335
+ @click.command()
336
+ @click.pass_obj
337
+ def list_available_graphs(client: TuringDB):
338
+ """List available graphs"""
339
+
340
+ try:
341
+ graphs = client.list_available_graphs()
342
+ print_formatted_text(HTML(f"<white>{graphs}</white>"))
343
+ except TuringDBException as e:
344
+ content = f"{e}"
345
+ print_formatted_text(HTML(f"<red>✘ {escape(str(content))}</red>"))
346
+ except Exception as e:
347
+ content = f"{e}\n{traceback.format_exc()}"
348
+ print_formatted_text(HTML(f"<red>✘ Fatal error: {escape(str(content))}</red>"))
349
+
350
+
351
+ @shell_command
352
+ @click.command()
353
+ @click.pass_obj
354
+ def list_loaded_graphs(client: TuringDB):
355
+ """List loaded graphs"""
356
+
357
+ try:
358
+ graphs = client.list_loaded_graphs()
359
+ print_formatted_text(HTML(f"<white>{graphs}</white>"))
360
+ except TuringDBException as e:
361
+ print_formatted_text(HTML(f"<red>✘ {e}</red>"))
362
+ except Exception as e:
363
+ print_formatted_text(HTML(f"<red>✘ Fatal error: {e}</red>"))
364
+
365
+
366
+ if __name__ == "__main__":
367
+ main()
@@ -0,0 +1,19 @@
1
+ Metadata-Version: 2.2
2
+ Name: turingdb
3
+ Version: 1.16.1.dev7
4
+ Classifier: Operating System :: POSIX :: Linux
5
+ Project-URL: Homepage, https://github.com/turing-db/turingdb-python
6
+ Project-URL: Repository, https://github.com/turing-db/turingdb-python
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: auditwheel>=6.6.0
9
+ Requires-Dist: boto3>=1.42.22
10
+ Requires-Dist: boto3-stubs>=1.42.22
11
+ Requires-Dist: click>=8.3.1
12
+ Requires-Dist: httpx>=0.28.1
13
+ Requires-Dist: mypy>=1.19.1
14
+ Requires-Dist: orjson>=3.11.5
15
+ Requires-Dist: pandas>=2.3.3
16
+ Requires-Dist: pandas-stubs>=2.3.3.251219
17
+ Requires-Dist: patchelf>=0.17.2.4
18
+ Requires-Dist: prompt-toolkit>=3.0.52
19
+