yuclid 0.1.0__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.
- yuclid/__init__.py +1 -0
- yuclid/cli.py +229 -0
- yuclid/log.py +56 -0
- yuclid/plot.py +1009 -0
- yuclid/run.py +1239 -0
- yuclid/spread.py +152 -0
- yuclid-0.1.0.dist-info/METADATA +15 -0
- yuclid-0.1.0.dist-info/RECORD +11 -0
- yuclid-0.1.0.dist-info/WHEEL +5 -0
- yuclid-0.1.0.dist-info/entry_points.txt +2 -0
- yuclid-0.1.0.dist-info/top_level.txt +1 -0
yuclid/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.1.0"
|
yuclid/cli.py
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
from yuclid import __version__
|
2
|
+
import yuclid.spread
|
3
|
+
import yuclid.plot
|
4
|
+
import yuclid.run
|
5
|
+
import yuclid.log
|
6
|
+
import argparse
|
7
|
+
|
8
|
+
|
9
|
+
def get_parser():
|
10
|
+
parser = argparse.ArgumentParser(prog="yuclid", description="Yuclid CLI tool")
|
11
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
12
|
+
|
13
|
+
parser.add_argument(
|
14
|
+
"--ignore-errors",
|
15
|
+
default=False,
|
16
|
+
action="store_true",
|
17
|
+
help="Yuclid will not abort on any errors unless fatal",
|
18
|
+
)
|
19
|
+
|
20
|
+
# run subcommand
|
21
|
+
run_parser = subparsers.add_parser("run", help="Run experiments and collect data")
|
22
|
+
run_parser.add_argument(
|
23
|
+
"-i",
|
24
|
+
"--inputs",
|
25
|
+
default=["yuclid.json"],
|
26
|
+
nargs="*",
|
27
|
+
help="Specify one or more configuration files. Default is 'yuclid.json'",
|
28
|
+
)
|
29
|
+
run_parser.add_argument(
|
30
|
+
"-r",
|
31
|
+
"--order",
|
32
|
+
nargs="*",
|
33
|
+
default=[],
|
34
|
+
help="List of dimensions to override the order of experiments",
|
35
|
+
)
|
36
|
+
run_parser.add_argument(
|
37
|
+
"-o",
|
38
|
+
"--output",
|
39
|
+
default=None,
|
40
|
+
help="JSON output file path for the generated data",
|
41
|
+
)
|
42
|
+
run_parser.add_argument(
|
43
|
+
"--output-dir",
|
44
|
+
default=None,
|
45
|
+
help="Directory path where the generated data will be saved",
|
46
|
+
)
|
47
|
+
run_parser.add_argument(
|
48
|
+
"--temp-dir",
|
49
|
+
default=".yuclid",
|
50
|
+
help="Directory where temporary file will be saved",
|
51
|
+
)
|
52
|
+
run_parser.add_argument(
|
53
|
+
"-p",
|
54
|
+
"--presets",
|
55
|
+
nargs="*",
|
56
|
+
default=[],
|
57
|
+
help="Specify a list of preset names to run",
|
58
|
+
)
|
59
|
+
run_parser.add_argument(
|
60
|
+
"-s",
|
61
|
+
"--select",
|
62
|
+
nargs="*",
|
63
|
+
default=[],
|
64
|
+
help="Select a list of name=csv_values pairs for each dimension. E.g. dim1=val1,val2 dim2=val3,val4",
|
65
|
+
)
|
66
|
+
run_parser.add_argument(
|
67
|
+
"--fold",
|
68
|
+
default=False,
|
69
|
+
action="store_true",
|
70
|
+
help="Stores values produced by a metric in an array",
|
71
|
+
)
|
72
|
+
run_parser.add_argument(
|
73
|
+
"--dry-run",
|
74
|
+
default=False,
|
75
|
+
action="store_true",
|
76
|
+
help="Show experiment that would run",
|
77
|
+
)
|
78
|
+
run_parser.add_argument(
|
79
|
+
"-m",
|
80
|
+
"--metrics",
|
81
|
+
nargs="*",
|
82
|
+
default=None,
|
83
|
+
help="Specify a list of metrics to compute among the registered ones. If empty, all metrics will be computed.",
|
84
|
+
)
|
85
|
+
|
86
|
+
# plot subcommand
|
87
|
+
plot_parser = subparsers.add_parser("plot", help="Plot data in a GUI")
|
88
|
+
plot_parser.add_argument(
|
89
|
+
"files", metavar="FILES", type=str, nargs="+", help="JSON Lines or CSV files"
|
90
|
+
)
|
91
|
+
plot_parser.add_argument("-x", required=True, help="X-axis column name")
|
92
|
+
plot_parser.add_argument("-y", nargs="*", help="Y-axis column names")
|
93
|
+
plot_parser.add_argument("-z", help="Grouping column name")
|
94
|
+
plot_parser.add_argument(
|
95
|
+
"-X",
|
96
|
+
"--x-norm",
|
97
|
+
nargs="*",
|
98
|
+
help="Normalize each x-group w.r.t. a value per group",
|
99
|
+
)
|
100
|
+
plot_parser.add_argument(
|
101
|
+
"-Z",
|
102
|
+
"--z-norm",
|
103
|
+
nargs="*",
|
104
|
+
help="Normalize each z-group w.r.t. a value per group",
|
105
|
+
)
|
106
|
+
plot_parser.add_argument(
|
107
|
+
"-R",
|
108
|
+
"--ref-norm",
|
109
|
+
nargs="*",
|
110
|
+
help="Normalize all values w.r.t. a single reference",
|
111
|
+
)
|
112
|
+
# plot_parser.add_argument(
|
113
|
+
# "-S",
|
114
|
+
# "--norm-scope",
|
115
|
+
# choices=["global", "local"],
|
116
|
+
# default="local",
|
117
|
+
# help="Normalization scope",
|
118
|
+
# )
|
119
|
+
plot_parser.add_argument(
|
120
|
+
"-r",
|
121
|
+
"--norm-reverse",
|
122
|
+
action="store_true",
|
123
|
+
default=False,
|
124
|
+
help="Reverse normalization. E.g. a/x instead of x/a",
|
125
|
+
)
|
126
|
+
plot_parser.add_argument(
|
127
|
+
"-m",
|
128
|
+
"--spread-measure",
|
129
|
+
default="pi,95",
|
130
|
+
help="Measure of dispersion. Default: pi,95. Available: none or {}".format(
|
131
|
+
" - ".join(yuclid.spread.available)
|
132
|
+
),
|
133
|
+
)
|
134
|
+
plot_parser.add_argument(
|
135
|
+
"--rsync-interval",
|
136
|
+
metavar="S",
|
137
|
+
type=float,
|
138
|
+
default=5,
|
139
|
+
help="[seconds] Remote synchronization interval",
|
140
|
+
)
|
141
|
+
plot_parser.add_argument(
|
142
|
+
"-l",
|
143
|
+
"--lines",
|
144
|
+
action="store_true",
|
145
|
+
default=False,
|
146
|
+
help="Plot with lines instead of bars",
|
147
|
+
)
|
148
|
+
plot_parser.add_argument(
|
149
|
+
"-g",
|
150
|
+
"--geomean",
|
151
|
+
action="store_true",
|
152
|
+
default=False,
|
153
|
+
help="Include a geomean summary",
|
154
|
+
)
|
155
|
+
plot_parser.add_argument(
|
156
|
+
"-f",
|
157
|
+
"--filter",
|
158
|
+
nargs="*",
|
159
|
+
default=None,
|
160
|
+
help="Filter dimension with explicit values. E.g. -f a=1 b=value",
|
161
|
+
)
|
162
|
+
plot_parser.add_argument(
|
163
|
+
"-u",
|
164
|
+
"--unit",
|
165
|
+
default=None,
|
166
|
+
help="Unit of measurement for the Y-axis",
|
167
|
+
)
|
168
|
+
plot_parser.add_argument(
|
169
|
+
"--colorblind",
|
170
|
+
action="store_true",
|
171
|
+
default=False,
|
172
|
+
help="Enable colorblind palette",
|
173
|
+
)
|
174
|
+
plot_parser.add_argument(
|
175
|
+
"--show-missing",
|
176
|
+
action="store_true",
|
177
|
+
default=False,
|
178
|
+
help="Show missing experiments if any",
|
179
|
+
)
|
180
|
+
plot_parser.add_argument(
|
181
|
+
"--rescale",
|
182
|
+
type=float,
|
183
|
+
default=1.0,
|
184
|
+
help="Rescale Y-axis values by multiplying by this number",
|
185
|
+
)
|
186
|
+
plot_parser.add_argument(
|
187
|
+
"-A",
|
188
|
+
"--annotate",
|
189
|
+
action="store_true",
|
190
|
+
default=False,
|
191
|
+
help="Annotate Y values on each bar or point in the plot",
|
192
|
+
)
|
193
|
+
plot_parser.add_argument(
|
194
|
+
"--annotate-max",
|
195
|
+
action="store_true",
|
196
|
+
default=False,
|
197
|
+
help="Annotate only the maximum Y value in each group",
|
198
|
+
)
|
199
|
+
plot_parser.add_argument(
|
200
|
+
"--annotate-min",
|
201
|
+
action="store_true",
|
202
|
+
default=False,
|
203
|
+
help="Annotate only the minimum Y value in each group",
|
204
|
+
)
|
205
|
+
plot_parser.add_argument(
|
206
|
+
"--no-merge-inputs",
|
207
|
+
action="store_true",
|
208
|
+
default=False,
|
209
|
+
help="Treat each input file separately instead of merging them (default: merged). A new index column 'file' will be created for each input file.",
|
210
|
+
)
|
211
|
+
|
212
|
+
parser.add_argument("--version", action="version", version="yuclid " + __version__)
|
213
|
+
|
214
|
+
return parser
|
215
|
+
|
216
|
+
|
217
|
+
def main():
|
218
|
+
parser = get_parser()
|
219
|
+
args = parser.parse_args()
|
220
|
+
yuclid.log.init(ignore_errors=args.ignore_errors)
|
221
|
+
|
222
|
+
if args.command == "run":
|
223
|
+
yuclid.run.launch(args)
|
224
|
+
elif args.command == "plot":
|
225
|
+
yuclid.plot.launch(args)
|
226
|
+
|
227
|
+
|
228
|
+
if __name__ == "__main__":
|
229
|
+
main()
|
yuclid/log.py
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
import sys
|
3
|
+
|
4
|
+
_state = {}
|
5
|
+
|
6
|
+
|
7
|
+
class LogLevel:
|
8
|
+
INFO = 1
|
9
|
+
WARNING = 2
|
10
|
+
ERROR = 3
|
11
|
+
FATAL = 4
|
12
|
+
HINT = 5
|
13
|
+
|
14
|
+
|
15
|
+
def init(ignore_errors):
|
16
|
+
_state["style"] = {
|
17
|
+
"none": "\033[0m",
|
18
|
+
"yellow": "\033[93m",
|
19
|
+
"green": "\033[92m",
|
20
|
+
"red": "\033[91m",
|
21
|
+
"bold": "\033[1;97m",
|
22
|
+
"purple": "\033[95m",
|
23
|
+
}
|
24
|
+
if not sys.stdout.isatty():
|
25
|
+
for k, v in _state["style"].items():
|
26
|
+
_state["style"][k] = ""
|
27
|
+
|
28
|
+
_state["ignore_errors"] = ignore_errors
|
29
|
+
style = _state["style"]
|
30
|
+
_state["level_prefix"] = {
|
31
|
+
LogLevel.INFO: "{}INFO{}".format(style["green"], style["none"]),
|
32
|
+
LogLevel.WARNING: "{}WARNING{}".format(style["yellow"], style["none"]),
|
33
|
+
LogLevel.ERROR: "{}ERROR{}".format(style["red"], style["none"]),
|
34
|
+
LogLevel.FATAL: "{}FATAL{}".format(style["red"], style["none"]),
|
35
|
+
LogLevel.HINT: "{}HINT{}".format(style.get("purple", ""), style["none"]),
|
36
|
+
}
|
37
|
+
|
38
|
+
|
39
|
+
def yprint(level, *args, **kwargs):
|
40
|
+
style = _state["style"]
|
41
|
+
yuclid_prefix = "{}yuclid{}".format(style["bold"], style["none"])
|
42
|
+
timestamp = "{:%Y-%m-%d %H:%M:%S}".format(datetime.now())
|
43
|
+
level_prefix = _state["level_prefix"].get(level, "UNKNOWN")
|
44
|
+
kwargs["sep"] = kwargs.get("sep", ": ")
|
45
|
+
print(yuclid_prefix, timestamp, level_prefix, *args, **kwargs)
|
46
|
+
|
47
|
+
|
48
|
+
def report(level, *args, **kwargs):
|
49
|
+
hint = kwargs.pop("hint", None)
|
50
|
+
yprint(level, *args, **kwargs)
|
51
|
+
if hint is not None:
|
52
|
+
yprint(LogLevel.HINT, hint)
|
53
|
+
if level == LogLevel.FATAL:
|
54
|
+
sys.exit(2)
|
55
|
+
if not _state["ignore_errors"] and level == LogLevel.ERROR:
|
56
|
+
sys.exit(1)
|