asp-chef-cli 0.5.4__tar.gz → 0.5.6__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: asp-chef-cli
3
- Version: 0.5.4
3
+ Version: 0.5.6
4
4
  Summary: A simple CLI to run ASP Chef recipes
5
5
  Author: Mario Alviano
6
6
  Author-email: mario.alviano@gmail.com
@@ -1,7 +1,9 @@
1
1
  import json as json_module
2
2
  import os
3
+ import re
3
4
  import shutil
4
5
  import subprocess
6
+ import tempfile
5
7
  from collections import defaultdict
6
8
  from typing import Optional, Dict, Final
7
9
 
@@ -18,6 +20,12 @@ from ..dependencies import *
18
20
  router = APIRouter()
19
21
 
20
22
 
23
+ def strip_ansi_codes(text):
24
+ # This regex matches standard ANSI escape sequences
25
+ ansi_regex = re.compile(r'\x1b\[[0-9;]*[a-zA-Z]')
26
+ return ansi_regex.sub('', text)
27
+
28
+
21
29
  @endpoint(router, "/to-zero-simplification-version/")
22
30
  async def _(json):
23
31
  program = SymbolicProgram.parse(json["program"])
@@ -228,6 +236,78 @@ async def _(json):
228
236
  return {"models": models}
229
237
 
230
238
 
239
+ pasta_process: Final[Dict[str, Optional[subprocess.Popen]]] = defaultdict(lambda: None)
240
+ pasta_path: Final[str | None] = shutil.which("pastasolver")
241
+
242
+
243
+ def pasta_terminate(uuid):
244
+ if pasta_process[uuid] is not None:
245
+ pasta_process[uuid].kill()
246
+
247
+
248
+ @endpoint(router, "/pasta/")
249
+ async def _(json):
250
+ global pasta_process
251
+
252
+ uuid = json["uuid"]
253
+ program = json["program"]
254
+ output_predicate = json["output_predicate"] or "__bounds__"
255
+ bound_multiplier = 0
256
+ try:
257
+ bound_multiplier = int(json["bound_multiplier"])
258
+ bound_multiplier = min(max(bound_multiplier, 0), 1_000_000)
259
+ except ValueError:
260
+ bound_multiplier = 0
261
+
262
+ timeout = json["timeout"]
263
+ if type(timeout) is not int or timeout < 1 or timeout >= 24 * 60 * 60:
264
+ timeout = 5
265
+
266
+ pasta_terminate(uuid)
267
+
268
+ with tempfile.NamedTemporaryFile(mode='w', delete=True) as temp_file:
269
+ temp_file.write(program)
270
+ temp_file.flush()
271
+
272
+ cmd = ["/bin/timeout", str(timeout), pasta_path, temp_file.name]
273
+ pasta_process[uuid] = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
274
+ out, err = pasta_process[uuid].communicate()
275
+
276
+ timeout_reached: Final = pasta_process[uuid].returncode == 124
277
+ pasta_process[uuid] = None
278
+
279
+ # report errors
280
+ output = out.decode()
281
+ lines = output.split('\n')
282
+ lines = [strip_ansi_codes(line) for line in lines]
283
+ if any(line.startswith("Error") for line in lines):
284
+ raise ValueError('\n' + '\n'.join(lines))
285
+ if timeout_reached:
286
+ lines = [line for line in lines if not line.startswith("Sig term")]
287
+
288
+ lines = [line for line in lines if line]
289
+ lb, ub = None, None
290
+ if len(lines) == 1:
291
+ lb = ub = float(lines[0].split("Lower probability == upper probability for the query: ")[1])
292
+ elif len(lines) == 2:
293
+ lb = float(lines[0].split("Lower probability for the query: ")[1])
294
+ ub = float(lines[1].split("Upper probability for the query: ")[1])
295
+
296
+ if lb is None or ub is None:
297
+ raise ValueError("Could not parse output from PASTA solver:\n" + '\n'.join(lines))
298
+
299
+ if bound_multiplier:
300
+ lb = round(lb * bound_multiplier)
301
+ ub = round(ub * bound_multiplier)
302
+ else:
303
+ lb = f'real("{lb}")'
304
+ ub = f'real("{ub}")'
305
+
306
+ return {"models": [
307
+ [f'{output_predicate}({lb},{ub})']
308
+ ]}
309
+
310
+
231
311
  @endpoint(router, "/template/core-template/")
232
312
  async def _(json):
233
313
  if not json:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "asp-chef-cli"
3
- version = "0.5.4"
3
+ version = "0.5.6"
4
4
  description = "A simple CLI to run ASP Chef recipes"
5
5
  authors = ["Mario Alviano <mario.alviano@gmail.com>"]
6
6
  readme = "README.md"
File without changes
File without changes