fm-weck 0.2.1__py3-none-any.whl → 1.1__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.
fm_weck/__init__.py CHANGED
@@ -8,4 +8,4 @@
8
8
  from .config import Config # noqa: F401
9
9
  from .image_mgr import ImageMgr # noqa: F401
10
10
 
11
- __version__ = "0.2.1"
11
+ __version__ = "1.1"
fm_weck/cli.py CHANGED
@@ -12,7 +12,7 @@ from argparse import Namespace
12
12
  from dataclasses import dataclass
13
13
  from functools import cache
14
14
  from pathlib import Path
15
- from typing import Any, Callable, Optional, Tuple, Union, cast
15
+ from typing import Any, Callable, Optional, Tuple, Union
16
16
 
17
17
  from fm_tools.benchexec_helper import DataModel
18
18
 
@@ -22,7 +22,7 @@ from fm_weck.resources import iter_fm_data, iter_properties
22
22
 
23
23
  from . import __version__
24
24
  from .engine import Engine, NoImageError
25
- from .serve import run_guided, run_manual
25
+ from .serve import run_guided, run_manual, setup_fm_tool
26
26
 
27
27
 
28
28
  @dataclass
@@ -45,9 +45,30 @@ class ToolQualifier:
45
45
  return
46
46
 
47
47
 
48
- def add_shared_arguments(
49
- parser: argparse.ArgumentParser, require_manual=False
50
- ) -> Tuple[argparse.ArgumentParser, argparse.ArgumentParser, Any]:
48
+ def add_tool_arg(parser, nargs="?"):
49
+ parser.add_argument(
50
+ "TOOL",
51
+ help="The tool to obtain the container from. Can be the form <tool>:<version>. "
52
+ "The TOOL is either the name of a bundled tool (c.f. fm-weck --list) or "
53
+ "the path to a fm-tools yaml file.",
54
+ type=ToolQualifier,
55
+ nargs=nargs,
56
+ )
57
+
58
+
59
+ def add_shared_args_for_run_modes(parser):
60
+ parser.add_argument(
61
+ "--skip-download",
62
+ action="store_true",
63
+ help="Do not download the fm-tool, even if it is not available in the cache.",
64
+ )
65
+
66
+ add_tool_arg(parser, nargs=None)
67
+
68
+
69
+ def parse(raw_args: list[str]) -> Tuple[Callable[[], None], Namespace]:
70
+ parser = argparse.ArgumentParser(description="fm-weck")
71
+
51
72
  parser.add_argument(
52
73
  "--version",
53
74
  action="version",
@@ -78,55 +99,8 @@ def add_shared_arguments(
78
99
  )
79
100
 
80
101
  subparsers = parser.add_subparsers()
81
- run = subparsers.add_parser("run", help="Run a verifier inside a container.")
82
-
83
- run.add_argument(
84
- "-m",
85
- "--manual",
86
- action="store_true",
87
- required=require_manual,
88
- help="Enable manual mode. All args past <tool>:<version> are passed verbatim to the tool.",
89
- )
90
-
91
- run.add_argument(
92
- "--skip-download",
93
- action="store_true",
94
- help="Do not download the fm-tool, even if it is not available in the cache.",
95
- )
96
-
97
- run.add_argument(
98
- "TOOL",
99
- help="The tool to use. Can be the form <tool>:<version>. "
100
- "The TOOL is either the name of a bundled tool (c.f. fm-weck --list) or "
101
- "the path to a fm-tools yaml file.",
102
- type=ToolQualifier,
103
- )
104
102
 
105
- return parser, run, subparsers
106
-
107
-
108
- class MayFailParserError(Exception):
109
- pass
110
-
111
-
112
- class MayFailParser(argparse.ArgumentParser):
113
- def error(self, message):
114
- raise MayFailParserError
115
-
116
- def format_help(self):
117
- raise MayFailParserError
118
-
119
-
120
- def parse(raw_args: list[str]) -> tuple[Callable[[], None], Namespace]:
121
- manual_parser = MayFailParser(description="fm-weck", exit_on_error=False)
122
- normal_parser = argparse.ArgumentParser(description="fm-weck")
123
-
124
- manual_parser, run, _ = add_shared_arguments(manual_parser, require_manual=True)
125
- # manual mode
126
- run.add_argument("argument_list", metavar="args", nargs="*", help="Arguments for the fm-tool")
127
- run.set_defaults(main=main_manual)
128
-
129
- normal_parser, run, subparsers = add_shared_arguments(normal_parser)
103
+ run = subparsers.add_parser("run", aliases=["r"], help="Run a verifier inside a container.")
130
104
 
131
105
  # guided mode
132
106
  run.add_argument(
@@ -163,6 +137,8 @@ def parse(raw_args: list[str]) -> tuple[Callable[[], None], Namespace]:
163
137
  default=None,
164
138
  )
165
139
 
140
+ add_shared_args_for_run_modes(run)
141
+
166
142
  run.add_argument("files", metavar="FILES", nargs="+", help="Files to pass to the tool")
167
143
  run.add_argument(
168
144
  "argument_list",
@@ -172,40 +148,48 @@ def parse(raw_args: list[str]) -> tuple[Callable[[], None], Namespace]:
172
148
  )
173
149
  run.set_defaults(main=main_run)
174
150
 
151
+ expert = subparsers.add_parser(
152
+ "expert",
153
+ aliases=["e", "m"],
154
+ help="Manually run a verifier inside a container."
155
+ "Arguments are passed verbatim to the tool, so expert-ise about it's command line is required.",
156
+ )
157
+
158
+ add_shared_args_for_run_modes(expert)
159
+
160
+ expert.add_argument("argument_list", metavar="args", nargs="*", help="Arguments for the fm-tool")
161
+ expert.set_defaults(main=main_manual)
162
+
175
163
  shell = subparsers.add_parser("shell", help="Start an interactive shell inside the container.")
176
- shell = cast(argparse.ArgumentParser, shell)
164
+
177
165
  shell.add_argument("--entry", action="store", help="The entry point of the shell.", default="/bin/bash")
178
- shell.add_argument(
179
- "TOOL",
180
- help="The tool to obtain the container from. Can be the form <tool>:<version>. "
181
- "The TOOL is either the name of a bundled tool (c.f. fm-weck --list) or "
182
- "the path to a fm-tools yaml file.",
183
- type=ToolQualifier,
184
- nargs="?",
185
- )
166
+
167
+ add_tool_arg(shell)
186
168
  shell.set_defaults(main=main_shell)
187
169
 
170
+ install = subparsers.add_parser("install", aliases=["i"], help="Download and unpack a TOOL for later use.")
171
+ add_tool_arg(install, nargs="+")
172
+ install.set_defaults(main=main_install)
173
+
188
174
  def help_callback():
189
- normal_parser.print_help()
175
+ parser.print_help()
190
176
 
191
177
  try:
192
- first_pass, remain = manual_parser.parse_known_args(raw_args)
193
- if remain:
194
- i = raw_args.index(remain[0])
195
- args = raw_args.copy()
196
- args.insert(i, "--")
197
- # retry parsing
198
- args = manual_parser.parse_args(args)
199
- else:
200
- args = first_pass
201
- except MayFailParserError:
202
- args = normal_parser.parse_args(raw_args)
203
- except argparse.ArgumentError:
204
- # Either: Parse faulty args again to display nice help message
205
- # Or: shell was called: proceed normally
206
- args = normal_parser.parse_args(raw_args)
178
+ parser.parse_args(raw_args)
179
+ except SystemExit as e:
180
+ _, left_over = parser.parse_known_args(raw_args)
181
+
182
+ if not left_over:
183
+ # Some unrecoverable error occurred
184
+ raise e
185
+
186
+ # Find the first offending argument and insert "--" before it
187
+ # We do this to allow the user to pass arguments to the fm-tool without
188
+ # having to specify the pseudo argument "--"
189
+ idx = raw_args.index(left_over[0])
190
+ raw_args.insert(idx, "--")
207
191
 
208
- return help_callback, args
192
+ return help_callback, parser.parse_args(raw_args)
209
193
 
210
194
 
211
195
  @cache
@@ -300,6 +284,21 @@ def main_manual(args: argparse.Namespace):
300
284
  )
301
285
 
302
286
 
287
+ def main_install(args: argparse.Namespace):
288
+ for tool in args.TOOL:
289
+ try:
290
+ fm_data = resolve_tool(tool)
291
+ except KeyError:
292
+ logging.error("Unknown tool %s. Skipping installation...", tool)
293
+ continue
294
+
295
+ setup_fm_tool(
296
+ fm_tool=fm_data,
297
+ version=tool.version,
298
+ configuration=Config(),
299
+ )
300
+
301
+
303
302
  def main_shell(args: argparse.Namespace):
304
303
  if not args.TOOL:
305
304
  engine = Engine.from_config(Config())
@@ -315,14 +314,13 @@ def main_shell(args: argparse.Namespace):
315
314
 
316
315
 
317
316
  def log_no_image_error(tool, config):
318
-
319
317
  order = []
320
318
  for path in _SEARCH_ORDER:
321
319
  if path.is_relative_to(Path.cwd()):
322
320
  order.append(str(path.relative_to(Path.cwd())))
323
321
  else:
324
322
  order.append(str(path))
325
-
323
+
326
324
  text = ""
327
325
  if tool:
328
326
  text = f"{os.linesep}No image specified in the fm-tool yml file for {tool.tool}."
@@ -372,6 +370,8 @@ def cli(raw_args: list[str]):
372
370
  print(f" - {prop}")
373
371
  return
374
372
 
373
+ print(args)
374
+
375
375
  if not hasattr(args, "TOOL"):
376
376
  return help_callback()
377
377
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fm-weck
3
- Version: 0.2.1
3
+ Version: 1.1
4
4
  Author-email: Henrik Wachowitz <henrik.wachowitz@ifi.lmu.de>
5
5
  Maintainer-email: Henrik Wachowitz <henrik.wachowitz@ifi.lmu.de>
6
6
  Classifier: Development Status :: 4 - Beta
@@ -24,9 +24,12 @@ SPDX-FileCopyrightText: 2024 Dirk Beyer <https://www.sosy-lab.org>
24
24
  SPDX-License-Identifier: Apache-2.0
25
25
  -->
26
26
 
27
- # fm-weck - Warp runExec in a container and conserve fm-tools
27
+ # fm-weck: Run formal methods tools in containerized environments
28
28
 
29
- This project builds on Podman. To develop, you need to install Podman.
29
+ fm-weck is a command line tool and library that makes the execution of formal methods tools easy. fm-weck downloads the tools and caches them for later use.
30
+
31
+ <!-- To get an impression check out the corresponding [FM '24 Paper](https://www.sosy-lab.org/research/pub/2024/). -->
32
+ We provide a tutorial on how to use fm-weck [here](doc/Tutorial.md).
30
33
 
31
34
  ## Install dependencies
32
35
 
@@ -36,19 +39,19 @@ This project builds on Podman. To develop, you need to install Podman.
36
39
  sudo apt install podman
37
40
  ```
38
41
 
39
- ## Core principal of the Project
42
+ ## Modes of Operation
40
43
 
41
- There are three modes of operation: `run`, `shell` and `serve`.
44
+ There are three modes of operation: `run`, `shell` and `expert`.
42
45
 
43
- - `run`: executes a single command in the containerized environment of a given verifier, specified through the
44
- corresponding fm-data YAML file
45
- - `shell`: enters an interactive shell inside of the container specified by the given verifier
46
- - `serve`: enables plug-and-play execution of formal methods tools: it
46
+ - `expert`: executes a tool in it's containerized environment specified through the
47
+ corresponding fm-tools YAML file: All arguments are passed verbatim to the tool.
48
+ - `shell`: enters an interactive shell inside of the container specified by the given tool
49
+ - `run`: enables plug-and-play execution of formal methods tools: it
47
50
  downloads and unpacks a tool from the fm-tools metadata file into a user-specified cache directory on the host system and then runs the tool in the containerized environment
48
51
 
49
52
  ## Development and Testing
50
53
 
51
- When using any command with the `fm-weck toolname ...` syntax, the tool name is searched in `src/fm_weck/resources/fm_tools`.
54
+ When using any command with the `fm-weck <cmd> toolname ...` syntax, the tool name is searched in `src/fm_weck/resources/fm_tools`.
52
55
  During the build process of the `.whl` file for `fm-weck`, the `fm_tools/data` directory is copied to that location.
53
56
  When running or developing `fm-weck` from the git repository, the user must make sure that the contents of `fm_tools/data` directory are
54
57
  available in the `src/fm_weck/resources/fm_tools` directory.
@@ -1,6 +1,6 @@
1
- fm_weck/__init__.py,sha256=m3otRQif1qQDymVSbyncWjztSFA--ZqbxOXchpro4ZA,351
1
+ fm_weck/__init__.py,sha256=nN88NCpdZVISleeiEKZNzQIEqfhYGseFqAKRwEWWboo,349
2
2
  fm_weck/__main__.py,sha256=E7z4-9t6To3hbIPjRPu6iW17YCrtqpDSbFSpd9pX4NA,350
3
- fm_weck/cli.py,sha256=op4qCAIWgALLZ0V04X-2-8-zeipKDOGDP3_XmpxB2XM,10821
3
+ fm_weck/cli.py,sha256=b0xU_GBs_7ETRzNfcFBSRfCarVT1Ix8sR0Q7LDLJ0S4,10598
4
4
  fm_weck/config.py,sha256=E3TZbUv9za6XkuLTBGeuxUjLqYKW6IIz2i_N-N47DVI,3872
5
5
  fm_weck/engine.py,sha256=TIeyCevSjB_PQ5DiYfi7xNjeIRh2CJ636EX5kAY3gKs,7507
6
6
  fm_weck/image_mgr.py,sha256=1lddYSVd4-dILfhMjDo87S5wfW7qeefInJpyV0Jao_4,1375
@@ -123,7 +123,7 @@ fm_weck/resources/fm_tools/wasp-c.yml,sha256=NWEb2vpIBu75kZJdEq0am8Mpi2HFu5nhDI1
123
123
  fm_weck/resources/fm_tools/wit4java.yml,sha256=SukwwE46DsDmZouAwHhr_aaOjxIaeOrIS7o7P4eDWX0,1243
124
124
  fm_weck/resources/fm_tools/witch.yml,sha256=1NtUf5SlXtCTqJZHjENcjqZMMqnKGlb4awSUwBDEvWw,913
125
125
  fm_weck/resources/fm_tools/witnesslint.yml,sha256=Y6A2TXPyjVxZ9Fhmyd7GOKY7x1_jXjshvmrIM4uW96A,3085
126
- fm_weck-0.2.1.dist-info/METADATA,sha256=qFYneg9B4vni0CujuLUsu3wh87ifM-fOItQ2mgn4RNk,2453
127
- fm_weck-0.2.1.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
128
- fm_weck-0.2.1.dist-info/entry_points.txt,sha256=toWpKCSY1u593MPnI_xW5gnwlnkerP4AvmPQ1s2nPgY,50
129
- fm_weck-0.2.1.dist-info/RECORD,,
126
+ fm_weck-1.1.dist-info/METADATA,sha256=SRWhnPT1nNJfhZAYyv9XoI2OtRzSlUe2aNVV4P3wExY,2742
127
+ fm_weck-1.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
128
+ fm_weck-1.1.dist-info/entry_points.txt,sha256=toWpKCSY1u593MPnI_xW5gnwlnkerP4AvmPQ1s2nPgY,50
129
+ fm_weck-1.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.24.2
2
+ Generator: hatchling 1.25.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any