qlever 0.5.8__py3-none-any.whl → 0.5.10__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.
Potentially problematic release.
This version of qlever might be problematic. Click here for more details.
- qlever/Qleverfiles/Qleverfile.dblp +13 -9
- qlever/Qleverfiles/Qleverfile.dblp-plus +2 -2
- qlever/Qleverfiles/Qleverfile.default +1 -1
- qlever/Qleverfiles/Qleverfile.fbeasy +4 -4
- qlever/Qleverfiles/Qleverfile.freebase +2 -2
- qlever/Qleverfiles/Qleverfile.imdb +1 -1
- qlever/Qleverfiles/Qleverfile.orkg +30 -0
- qlever/Qleverfiles/Qleverfile.osm-planet +1 -1
- qlever/Qleverfiles/Qleverfile.vvz +3 -3
- qlever/Qleverfiles/Qleverfile.wikidata +28 -17
- qlever/Qleverfiles/Qleverfile.yago-4 +4 -4
- qlever/commands/example_queries.py +250 -150
- qlever/commands/index.py +98 -8
- qlever/commands/setup_config.py +47 -31
- qlever/commands/system_info.py +126 -0
- qlever/commands/ui.py +50 -23
- qlever/containerize.py +67 -33
- qlever/qleverfile.py +243 -125
- qlever/util.py +55 -30
- {qlever-0.5.8.dist-info → qlever-0.5.10.dist-info}/METADATA +1 -1
- {qlever-0.5.8.dist-info → qlever-0.5.10.dist-info}/RECORD +25 -24
- {qlever-0.5.8.dist-info → qlever-0.5.10.dist-info}/WHEEL +1 -1
- qlever/__main__.py +0 -1476
- {qlever-0.5.8.dist-info → qlever-0.5.10.dist-info}/LICENSE +0 -0
- {qlever-0.5.8.dist-info → qlever-0.5.10.dist-info}/entry_points.txt +0 -0
- {qlever-0.5.8.dist-info → qlever-0.5.10.dist-info}/top_level.txt +0 -0
qlever/qleverfile.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
-
import socket
|
|
5
4
|
import subprocess
|
|
6
5
|
from configparser import ConfigParser, ExtendedInterpolation
|
|
7
6
|
|
|
@@ -41,162 +40,277 @@ class Qleverfile:
|
|
|
41
40
|
ui_args = all_args["ui"] = {}
|
|
42
41
|
|
|
43
42
|
data_args["name"] = arg(
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
"--name", type=str, required=True, help="The name of the dataset"
|
|
44
|
+
)
|
|
46
45
|
data_args["get_data_cmd"] = arg(
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
"--get-data-cmd",
|
|
47
|
+
type=str,
|
|
48
|
+
required=True,
|
|
49
|
+
help="The command to get the data",
|
|
50
|
+
)
|
|
49
51
|
data_args["description"] = arg(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
"--description",
|
|
53
|
+
type=str,
|
|
54
|
+
required=True,
|
|
55
|
+
help="A concise description of the dataset",
|
|
56
|
+
)
|
|
52
57
|
data_args["text_description"] = arg(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
"--text-description",
|
|
59
|
+
type=str,
|
|
60
|
+
default=None,
|
|
61
|
+
help="A concise description of the additional text data" " if any",
|
|
62
|
+
)
|
|
56
63
|
data_args["format"] = arg(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
"--format",
|
|
65
|
+
type=str,
|
|
66
|
+
default="ttl",
|
|
67
|
+
choices=["ttl", "nt", "nq"],
|
|
68
|
+
help="The format of the data",
|
|
69
|
+
)
|
|
60
70
|
|
|
61
71
|
index_args["input_files"] = arg(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
72
|
+
"--input-files",
|
|
73
|
+
type=str,
|
|
74
|
+
required=True,
|
|
75
|
+
help="A space-separated list of patterns that match "
|
|
76
|
+
"all the files of the dataset",
|
|
77
|
+
)
|
|
65
78
|
index_args["cat_input_files"] = arg(
|
|
66
|
-
|
|
67
|
-
|
|
79
|
+
"--cat-input-files", type=str, help="The command that produces the input"
|
|
80
|
+
)
|
|
81
|
+
index_args["multi_input_json"] = arg(
|
|
82
|
+
"--multi-input-json",
|
|
83
|
+
type=str,
|
|
84
|
+
default=None,
|
|
85
|
+
help="JSON to specify multiple input files, each with a "
|
|
86
|
+
"`cmd` (command that writes the triples to stdout), "
|
|
87
|
+
"`format` (format like for the `--format` option), "
|
|
88
|
+
"`graph` (name of the graph, use `-` for the default graph), "
|
|
89
|
+
"`parallel` (parallel parsing for large files, where all "
|
|
90
|
+
"prefix declaration are at the beginning)",
|
|
91
|
+
)
|
|
92
|
+
index_args["parallel_parsing"] = arg(
|
|
93
|
+
"--parallel-parsing",
|
|
94
|
+
type=str,
|
|
95
|
+
choices=["true", "false"],
|
|
96
|
+
help="Use parallel parsing (recommended for large files, "
|
|
97
|
+
"but it requires that all prefix declarations are at the "
|
|
98
|
+
"beginning of the file)",
|
|
99
|
+
)
|
|
68
100
|
index_args["settings_json"] = arg(
|
|
69
|
-
|
|
70
|
-
|
|
101
|
+
"--settings-json",
|
|
102
|
+
type=str,
|
|
103
|
+
default="{}",
|
|
104
|
+
help="The `.settings.json` file for the index",
|
|
105
|
+
)
|
|
71
106
|
index_args["index_binary"] = arg(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
107
|
+
"--index-binary",
|
|
108
|
+
type=str,
|
|
109
|
+
default="IndexBuilderMain",
|
|
110
|
+
help="The binary for building the index (this requires "
|
|
111
|
+
"that you have compiled QLever on your machine)",
|
|
112
|
+
)
|
|
75
113
|
index_args["stxxl_memory"] = arg(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
114
|
+
"--stxxl-memory",
|
|
115
|
+
type=str,
|
|
116
|
+
default="5G",
|
|
117
|
+
help="The amount of memory to use for the index build "
|
|
118
|
+
"(the name of the option has historical reasons)",
|
|
119
|
+
)
|
|
79
120
|
index_args["only_pso_and_pos_permutations"] = arg(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
121
|
+
"--only-pso-and-pos-permutations",
|
|
122
|
+
action="store_true",
|
|
123
|
+
default=False,
|
|
124
|
+
help="Only create the PSO and POS permutations",
|
|
125
|
+
)
|
|
83
126
|
index_args["use_patterns"] = arg(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
127
|
+
"--use-patterns",
|
|
128
|
+
action="store_true",
|
|
129
|
+
default=True,
|
|
130
|
+
help="Precompute so-called patterns needed for fast processing"
|
|
131
|
+
" of queries like SELECT ?p (COUNT(DISTINCT ?s) AS ?c) "
|
|
132
|
+
"WHERE { ?s ?p [] ... } GROUP BY ?p",
|
|
133
|
+
)
|
|
88
134
|
index_args["text_index"] = arg(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
135
|
+
"--text-index",
|
|
136
|
+
choices=[
|
|
137
|
+
"none",
|
|
138
|
+
"from_text_records",
|
|
139
|
+
"from_literals",
|
|
140
|
+
"from_text_records_and_literals",
|
|
141
|
+
],
|
|
142
|
+
default="none",
|
|
143
|
+
help="Whether to also build an index for text search" "and for which texts",
|
|
144
|
+
)
|
|
95
145
|
index_args["text_words_file"] = arg(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
146
|
+
"--text-words-file",
|
|
147
|
+
type=str,
|
|
148
|
+
default=None,
|
|
149
|
+
help="File with the words for the text index (one line "
|
|
150
|
+
"per word, format: `word or IRI\t0 or 1\tdoc id\t1`)",
|
|
151
|
+
)
|
|
99
152
|
index_args["text_docs_file"] = arg(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
153
|
+
"--text-docs-file",
|
|
154
|
+
type=str,
|
|
155
|
+
default=None,
|
|
156
|
+
help="File with the documents for the text index (one line "
|
|
157
|
+
"per document, format: `id\tdocument text`)",
|
|
158
|
+
)
|
|
103
159
|
|
|
104
160
|
server_args["server_binary"] = arg(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
161
|
+
"--server-binary",
|
|
162
|
+
type=str,
|
|
163
|
+
default="ServerMain",
|
|
164
|
+
help="The binary for starting the server (this requires "
|
|
165
|
+
"that you have compiled QLever on your machine)",
|
|
166
|
+
)
|
|
108
167
|
server_args["host_name"] = arg(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
168
|
+
"--host-name",
|
|
169
|
+
type=str,
|
|
170
|
+
default="localhost",
|
|
171
|
+
help="The name of the host on which the server listens for " "requests",
|
|
172
|
+
)
|
|
112
173
|
server_args["port"] = arg(
|
|
113
|
-
|
|
114
|
-
|
|
174
|
+
"--port", type=int, help="The port on which the server listens for requests"
|
|
175
|
+
)
|
|
115
176
|
server_args["access_token"] = arg(
|
|
116
|
-
|
|
117
|
-
|
|
177
|
+
"--access-token",
|
|
178
|
+
type=str,
|
|
179
|
+
default=None,
|
|
180
|
+
help="The access token for privileged operations",
|
|
181
|
+
)
|
|
118
182
|
server_args["memory_for_queries"] = arg(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
183
|
+
"--memory-for-queries",
|
|
184
|
+
type=str,
|
|
185
|
+
default="5G",
|
|
186
|
+
help="The maximal amount of memory used for query processing"
|
|
187
|
+
" (if a query needs more than what is available, the "
|
|
188
|
+
"query will not be processed)",
|
|
189
|
+
)
|
|
123
190
|
server_args["cache_max_size"] = arg(
|
|
124
|
-
|
|
125
|
-
|
|
191
|
+
"--cache-max-size",
|
|
192
|
+
type=str,
|
|
193
|
+
default="2G",
|
|
194
|
+
help="The maximal amount of memory used for caching",
|
|
195
|
+
)
|
|
126
196
|
server_args["cache_max_size_single_entry"] = arg(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
197
|
+
"--cache-max-size-single-entry",
|
|
198
|
+
type=str,
|
|
199
|
+
default="1G",
|
|
200
|
+
help="The maximal amount of memory used for caching a single "
|
|
201
|
+
"query result",
|
|
202
|
+
)
|
|
130
203
|
server_args["cache_max_num_entries"] = arg(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
204
|
+
"--cache-max-num-entries",
|
|
205
|
+
type=int,
|
|
206
|
+
default=200,
|
|
207
|
+
help="The maximal number of entries in the cache"
|
|
208
|
+
" (the eviction policy when the cache is full is LRU)",
|
|
209
|
+
)
|
|
134
210
|
server_args["timeout"] = arg(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
211
|
+
"--timeout",
|
|
212
|
+
type=str,
|
|
213
|
+
default="30s",
|
|
214
|
+
help="The maximal time in seconds a query is allowed to run"
|
|
215
|
+
" (can be increased per query with the URL parameters "
|
|
216
|
+
"`timeout` and `access_token`)",
|
|
217
|
+
)
|
|
139
218
|
server_args["num_threads"] = arg(
|
|
140
|
-
|
|
141
|
-
|
|
219
|
+
"--num-threads",
|
|
220
|
+
type=int,
|
|
221
|
+
default=8,
|
|
222
|
+
help="The number of threads used for query processing",
|
|
223
|
+
)
|
|
142
224
|
server_args["only_pso_and_pos_permutations"] = arg(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
225
|
+
"--only-pso-and-pos-permutations",
|
|
226
|
+
action="store_true",
|
|
227
|
+
default=False,
|
|
228
|
+
help="Only use the PSO and POS permutations (then each "
|
|
229
|
+
"triple pattern must have a fixed predicate)",
|
|
230
|
+
)
|
|
147
231
|
server_args["use_patterns"] = arg(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
232
|
+
"--use-patterns",
|
|
233
|
+
action="store_true",
|
|
234
|
+
default=True,
|
|
235
|
+
help="Use the patterns precomputed during the index build"
|
|
236
|
+
" (see `qlever index --help` for their utility)",
|
|
237
|
+
)
|
|
151
238
|
server_args["use_text_index"] = arg(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
239
|
+
"--use-text-index",
|
|
240
|
+
choices=["yes", "no"],
|
|
241
|
+
default="no",
|
|
242
|
+
help="Whether to use the text index (requires that one was "
|
|
243
|
+
"built, see `qlever index`)",
|
|
244
|
+
)
|
|
155
245
|
server_args["warmup_cmd"] = arg(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
246
|
+
"--warmup-cmd",
|
|
247
|
+
type=str,
|
|
248
|
+
help="Command executed after the server has started "
|
|
249
|
+
" (executed as part of `qlever start` unless "
|
|
250
|
+
" `--no-warmup` is specified, or with `qlever warmup`)",
|
|
251
|
+
)
|
|
160
252
|
|
|
161
253
|
runtime_args["system"] = arg(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
254
|
+
"--system",
|
|
255
|
+
type=str,
|
|
256
|
+
choices=Containerize.supported_systems() + ["native"],
|
|
257
|
+
default="docker",
|
|
258
|
+
help=(
|
|
259
|
+
"Whether to run commands like `index` or `start` "
|
|
260
|
+
"natively or in a container, and if in a container, "
|
|
261
|
+
"which system to use"
|
|
262
|
+
),
|
|
263
|
+
)
|
|
168
264
|
runtime_args["image"] = arg(
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
265
|
+
"--image",
|
|
266
|
+
type=str,
|
|
267
|
+
default="docker.io/adfreiburg/qlever",
|
|
268
|
+
help="The name of the image when running in a container",
|
|
269
|
+
)
|
|
172
270
|
runtime_args["index_container"] = arg(
|
|
173
|
-
|
|
174
|
-
|
|
271
|
+
"--index-container",
|
|
272
|
+
type=str,
|
|
273
|
+
help="The name of the container used by `qlever index`",
|
|
274
|
+
)
|
|
175
275
|
runtime_args["server_container"] = arg(
|
|
176
|
-
|
|
177
|
-
|
|
276
|
+
"--server-container",
|
|
277
|
+
type=str,
|
|
278
|
+
help="The name of the container used by `qlever start`",
|
|
279
|
+
)
|
|
178
280
|
|
|
179
281
|
ui_args["ui_port"] = arg(
|
|
180
|
-
|
|
181
|
-
|
|
282
|
+
"--ui-port",
|
|
283
|
+
type=int,
|
|
284
|
+
default=8176,
|
|
285
|
+
help="The port of the Qlever UI when running `qlever ui`",
|
|
286
|
+
)
|
|
182
287
|
ui_args["ui_config"] = arg(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
288
|
+
"--ui-config",
|
|
289
|
+
type=str,
|
|
290
|
+
default="default",
|
|
291
|
+
help="The name of the backend configuration for the QLever UI"
|
|
292
|
+
" (this determines AC queries and example queries)",
|
|
293
|
+
)
|
|
186
294
|
ui_args["ui_system"] = arg(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
295
|
+
"--ui-system",
|
|
296
|
+
type=str,
|
|
297
|
+
choices=Containerize.supported_systems(),
|
|
298
|
+
default="docker",
|
|
299
|
+
help="Which container system to use for `qlever ui`"
|
|
300
|
+
" (unlike for `qlever index` and `qlever start`, "
|
|
301
|
+
' "native" is not yet supported here)',
|
|
302
|
+
)
|
|
193
303
|
ui_args["ui_image"] = arg(
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
304
|
+
"--ui-image",
|
|
305
|
+
type=str,
|
|
306
|
+
default="docker.io/adfreiburg/qlever-ui",
|
|
307
|
+
help="The name of the image used for `qlever ui`",
|
|
308
|
+
)
|
|
197
309
|
ui_args["ui_container"] = arg(
|
|
198
|
-
|
|
199
|
-
|
|
310
|
+
"--ui-container",
|
|
311
|
+
type=str,
|
|
312
|
+
help="The name of the container used for `qlever ui`",
|
|
313
|
+
)
|
|
200
314
|
|
|
201
315
|
return all_args
|
|
202
316
|
|
|
@@ -214,8 +328,7 @@ class Qleverfile:
|
|
|
214
328
|
|
|
215
329
|
# Read the Qleverfile.
|
|
216
330
|
defaults = {"random": "83724324hztz", "version": "01.01.01"}
|
|
217
|
-
config = ConfigParser(interpolation=ExtendedInterpolation(),
|
|
218
|
-
defaults=defaults)
|
|
331
|
+
config = ConfigParser(interpolation=ExtendedInterpolation(), defaults=defaults)
|
|
219
332
|
try:
|
|
220
333
|
config.read(qleverfile_path)
|
|
221
334
|
except Exception as e:
|
|
@@ -230,13 +343,18 @@ class Qleverfile:
|
|
|
230
343
|
if match:
|
|
231
344
|
try:
|
|
232
345
|
value = subprocess.check_output(
|
|
233
|
-
|
|
234
|
-
|
|
346
|
+
match.group(1),
|
|
347
|
+
shell=True,
|
|
348
|
+
text=True,
|
|
349
|
+
stderr=subprocess.STDOUT,
|
|
350
|
+
).strip()
|
|
235
351
|
except Exception as e:
|
|
236
352
|
log.info("")
|
|
237
|
-
log.error(
|
|
238
|
-
|
|
239
|
-
|
|
353
|
+
log.error(
|
|
354
|
+
f"Error evaluating {value} for option "
|
|
355
|
+
f"{section}.{option.upper()} in "
|
|
356
|
+
f"{qleverfile_path}:"
|
|
357
|
+
)
|
|
240
358
|
log.info("")
|
|
241
359
|
log.info(e.output if hasattr(e, "output") else e)
|
|
242
360
|
exit(1)
|
|
@@ -263,8 +381,8 @@ class Qleverfile:
|
|
|
263
381
|
if "text_docs_file" not in index:
|
|
264
382
|
index["text_docs_file"] = f"{name}.docsfile.tsv"
|
|
265
383
|
server = config["server"]
|
|
266
|
-
|
|
267
|
-
|
|
384
|
+
if index.get("text_index", "none") != "none":
|
|
385
|
+
server["use_text_index"] = "yes"
|
|
268
386
|
|
|
269
387
|
# Return the parsed Qleverfile with the added inherited values.
|
|
270
388
|
return config
|
qlever/util.py
CHANGED
|
@@ -29,8 +29,9 @@ def get_total_file_size(patterns: list[str]) -> int:
|
|
|
29
29
|
return total_size
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def run_command(
|
|
33
|
-
|
|
32
|
+
def run_command(
|
|
33
|
+
cmd: str, return_output: bool = False, show_output: bool = False
|
|
34
|
+
) -> Optional[str]:
|
|
34
35
|
"""
|
|
35
36
|
Run the given command and throw an exception if the exit code is non-zero.
|
|
36
37
|
If `return_output` is `True`, return what the command wrote to `stdout`.
|
|
@@ -45,7 +46,7 @@ def run_command(cmd: str, return_output: bool = False,
|
|
|
45
46
|
"shell": True,
|
|
46
47
|
"text": True,
|
|
47
48
|
"stdout": None if show_output else subprocess.PIPE,
|
|
48
|
-
"stderr": subprocess.PIPE
|
|
49
|
+
"stderr": subprocess.PIPE,
|
|
49
50
|
}
|
|
50
51
|
result = subprocess.run(f"set -o pipefail; {cmd}", **subprocess_args)
|
|
51
52
|
# If the exit code is non-zero, throw an exception. If something was
|
|
@@ -63,17 +64,20 @@ def run_command(cmd: str, return_output: bool = False,
|
|
|
63
64
|
raise Exception(result.stderr.replace("\n", " ").strip())
|
|
64
65
|
else:
|
|
65
66
|
raise Exception(
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
f"Command failed with exit code {result.returncode}"
|
|
68
|
+
f" but nothing written to stderr"
|
|
69
|
+
)
|
|
68
70
|
# Optionally, return what was written to `stdout`.
|
|
69
71
|
if return_output:
|
|
70
72
|
return result.stdout
|
|
71
73
|
|
|
72
74
|
|
|
73
|
-
def run_curl_command(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
def run_curl_command(
|
|
76
|
+
url: str,
|
|
77
|
+
headers: dict[str, str] = {},
|
|
78
|
+
params: dict[str, str] = {},
|
|
79
|
+
result_file: Optional[str] = None,
|
|
80
|
+
) -> str:
|
|
77
81
|
"""
|
|
78
82
|
Run `curl` with the given `url`, `headers`, and `params`. If `result_file`
|
|
79
83
|
is `None`, return the output, otherwise, write the output to the given file
|
|
@@ -83,22 +87,29 @@ def run_curl_command(url: str,
|
|
|
83
87
|
# Construct and run the `curl` command.
|
|
84
88
|
default_result_file = "/tmp/qlever.curl.result"
|
|
85
89
|
actual_result_file = result_file if result_file else default_result_file
|
|
86
|
-
curl_cmd = (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
curl_cmd = (
|
|
91
|
+
f'curl -s -o "{actual_result_file}"'
|
|
92
|
+
f' -w "%{{http_code}}\n" {url}'
|
|
93
|
+
+ "".join([f' -H "{key}: {value}"' for key, value in headers.items()])
|
|
94
|
+
+ "".join(
|
|
95
|
+
[
|
|
96
|
+
f" --data-urlencode {key}={shlex.quote(value)}"
|
|
97
|
+
for key, value in params.items()
|
|
98
|
+
]
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
result = subprocess.run(
|
|
102
|
+
curl_cmd, shell=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
|
103
|
+
)
|
|
95
104
|
# Case 1: An error occurred, raise an exception.
|
|
96
105
|
if result.returncode != 0:
|
|
97
106
|
if len(result.stderr) > 0:
|
|
98
107
|
raise Exception(result.stderr)
|
|
99
108
|
else:
|
|
100
|
-
raise Exception(
|
|
101
|
-
|
|
109
|
+
raise Exception(
|
|
110
|
+
f"curl command failed with exit code "
|
|
111
|
+
f"{result.returncode}, stderr is empty"
|
|
112
|
+
)
|
|
102
113
|
# Case 2: Return output (read from `default_result_file`).
|
|
103
114
|
if result_file is None:
|
|
104
115
|
result_file_path = Path(default_result_file)
|
|
@@ -117,9 +128,9 @@ def is_qlever_server_alive(port: str) -> bool:
|
|
|
117
128
|
|
|
118
129
|
message = "from the qlever script".replace(" ", "%20")
|
|
119
130
|
curl_cmd = f"curl -s http://localhost:{port}/ping?msg={message}"
|
|
120
|
-
exit_code = subprocess.call(
|
|
121
|
-
|
|
122
|
-
|
|
131
|
+
exit_code = subprocess.call(
|
|
132
|
+
curl_cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
|
|
133
|
+
)
|
|
123
134
|
return exit_code == 0
|
|
124
135
|
|
|
125
136
|
|
|
@@ -152,15 +163,15 @@ def show_process_info(psutil_process, cmdline_regex, show_heading=True):
|
|
|
152
163
|
|
|
153
164
|
try:
|
|
154
165
|
pinfo = psutil_process.as_dict(
|
|
155
|
-
|
|
156
|
-
|
|
166
|
+
attrs=["pid", "username", "create_time", "memory_info", "cmdline"]
|
|
167
|
+
)
|
|
157
168
|
# Note: pinfo[`cmdline`] is `None` if the process is a zombie.
|
|
158
|
-
cmdline = " ".join(pinfo[
|
|
169
|
+
cmdline = " ".join(pinfo["cmdline"] or [])
|
|
159
170
|
if len(cmdline) == 0 or not re.search(cmdline_regex, cmdline):
|
|
160
171
|
return False
|
|
161
|
-
pid = pinfo[
|
|
162
|
-
user = pinfo[
|
|
163
|
-
start_time = datetime.fromtimestamp(pinfo[
|
|
172
|
+
pid = pinfo["pid"]
|
|
173
|
+
user = pinfo["username"] if pinfo["username"] else ""
|
|
174
|
+
start_time = datetime.fromtimestamp(pinfo["create_time"])
|
|
164
175
|
if start_time.date() == date.today():
|
|
165
176
|
start_time = start_time.strftime("%H:%M")
|
|
166
177
|
else:
|
|
@@ -193,10 +204,24 @@ def is_port_used(port: int) -> bool:
|
|
|
193
204
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
194
205
|
# Ensure that the port is not blocked after the check.
|
|
195
206
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
196
|
-
sock.bind((
|
|
207
|
+
sock.bind(("", port))
|
|
197
208
|
sock.close()
|
|
198
209
|
return False
|
|
199
210
|
except OSError as err:
|
|
200
211
|
if err.errno != errno.EADDRINUSE:
|
|
201
212
|
log.warning(f"Failed to determine if port is used: {err}")
|
|
202
213
|
return True
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def format_size(bytes, suffix="B"):
|
|
217
|
+
"""
|
|
218
|
+
Scale bytes to its proper format
|
|
219
|
+
e.g:
|
|
220
|
+
1253656 => '1.20MB'
|
|
221
|
+
1253656678 => '1.17GB'
|
|
222
|
+
"""
|
|
223
|
+
factor = 1024
|
|
224
|
+
for unit in ["", "K", "M", "G", "T", "P"]:
|
|
225
|
+
if bytes < factor:
|
|
226
|
+
return f"{bytes:.2f} {unit}{suffix}"
|
|
227
|
+
bytes /= factor
|