petal-qc 0.0.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.

Potentially problematic release.


This version of petal-qc might be problematic. Click here for more details.

Files changed (51) hide show
  1. petal_qc/BTreport/CheckBTtests.py +321 -0
  2. petal_qc/BTreport/__init__.py +0 -0
  3. petal_qc/BTreport/bustapeReport.py +144 -0
  4. petal_qc/__init__.py +14 -0
  5. petal_qc/metrology/Cluster.py +90 -0
  6. petal_qc/metrology/DataFile.py +47 -0
  7. petal_qc/metrology/PetalMetrology.py +327 -0
  8. petal_qc/metrology/__init__.py +0 -0
  9. petal_qc/metrology/all2csv.py +57 -0
  10. petal_qc/metrology/analyze_locking_points.py +597 -0
  11. petal_qc/metrology/cold_noise.py +106 -0
  12. petal_qc/metrology/comparisonTable.py +59 -0
  13. petal_qc/metrology/convert_mitutoyo.py +175 -0
  14. petal_qc/metrology/convert_smartscope.py +145 -0
  15. petal_qc/metrology/coreMetrology.py +402 -0
  16. petal_qc/metrology/data2csv.py +63 -0
  17. petal_qc/metrology/do_Metrology.py +117 -0
  18. petal_qc/metrology/flatness4nigel.py +157 -0
  19. petal_qc/metrology/gtkutils.py +120 -0
  20. petal_qc/metrology/petal_flatness.py +353 -0
  21. petal_qc/metrology/show_data_file.py +118 -0
  22. petal_qc/metrology/testSummary.py +37 -0
  23. petal_qc/metrology/test_paralelism.py +71 -0
  24. petal_qc/thermal/CSVImage.py +69 -0
  25. petal_qc/thermal/DebugPlot.py +76 -0
  26. petal_qc/thermal/IRBFile.py +768 -0
  27. petal_qc/thermal/IRCore.py +110 -0
  28. petal_qc/thermal/IRDataGetter.py +359 -0
  29. petal_qc/thermal/IRPetal.py +1338 -0
  30. petal_qc/thermal/IRPetalParam.py +71 -0
  31. petal_qc/thermal/PetalColorMaps.py +62 -0
  32. petal_qc/thermal/Petal_IR_Analysis.py +142 -0
  33. petal_qc/thermal/PipeFit.py +598 -0
  34. petal_qc/thermal/__init__.py +0 -0
  35. petal_qc/thermal/analyze_IRCore.py +417 -0
  36. petal_qc/thermal/contours.py +378 -0
  37. petal_qc/thermal/create_IRCore.py +185 -0
  38. petal_qc/thermal/pipe_read.py +182 -0
  39. petal_qc/thermal/show_IR_petal.py +420 -0
  40. petal_qc/utils/Geometry.py +756 -0
  41. petal_qc/utils/Progress.py +182 -0
  42. petal_qc/utils/__init__.py +0 -0
  43. petal_qc/utils/all_files.py +35 -0
  44. petal_qc/utils/docx_utils.py +186 -0
  45. petal_qc/utils/fit_utils.py +188 -0
  46. petal_qc/utils/utils.py +180 -0
  47. petal_qc-0.0.0.dist-info/METADATA +29 -0
  48. petal_qc-0.0.0.dist-info/RECORD +51 -0
  49. petal_qc-0.0.0.dist-info/WHEEL +5 -0
  50. petal_qc-0.0.0.dist-info/entry_points.txt +3 -0
  51. petal_qc-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,402 @@
1
+ #!/usr/bin/env python3
2
+ """GUI to launch metrology analysis."""
3
+ from pathlib import Path
4
+ from argparse import Action
5
+ from argparse import ArgumentParser
6
+ import itkdb_gtk.ITkDButils
7
+ import itkdb_gtk.dbGtkUtils
8
+ import numpy as np
9
+ from contextlib import redirect_stdout
10
+ import itkdb_gtk
11
+ import itkdb_gtk.UploadTest
12
+
13
+ from petal_qc.metrology.do_Metrology import do_analysis
14
+
15
+ import gi
16
+ gi.require_version("Gtk", "3.0")
17
+ from gi.repository import Gtk, GObject, Gio, GLib
18
+
19
+
20
+
21
+ class CommaSeparatedListAction(Action):
22
+ """Create a list from the comma sepparated numbers at imput."""
23
+
24
+ def __call__(self, parser, namespace, values, option_string=None):
25
+ """The actual action."""
26
+ value = np.array(list(map(float, values.split(','))), dtype='float64')
27
+ if value.shape[0] < 3:
28
+ raise Exception("{} needs a 3D vector".format(self.dest))
29
+
30
+ setattr(namespace, self.dest, value)
31
+
32
+
33
+ class CoreMetrology(itkdb_gtk.dbGtkUtils.ITkDBWindow):
34
+ """Application window."""
35
+
36
+ def __init__(self, options, session=None, title="", panel_size=100):
37
+ """Initialization.
38
+
39
+ Args:
40
+ title: The title of the window.
41
+ pannel_size: size of message panel.
42
+
43
+ """
44
+ super().__init__(session=session, title=title)
45
+
46
+ self.data_file = None
47
+ self.folder = None
48
+ self.petal_SN = None
49
+ self.petal_prefix = None
50
+ self.options = options
51
+ self.alternativeID = None
52
+ self.outDB = None
53
+
54
+
55
+ # Active button in header
56
+ button = Gtk.Button()
57
+ icon = Gio.ThemedIcon(name="document-send-symbolic")
58
+ image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
59
+ button.add(image)
60
+ button.set_tooltip_text("Click to upload test")
61
+ button.connect("clicked", self.upload_test_gui)
62
+ self.hb.pack_end(button)
63
+
64
+ # JScon edit
65
+ button = Gtk.Button()
66
+ icon = Gio.ThemedIcon(name="accessories-text-editor-symbolic")
67
+ image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
68
+ button.add(image)
69
+ button.set_tooltip_text("Click to see the test data")
70
+ button.connect("clicked", self.show_test_gui)
71
+ self.hb.pack_end(button)
72
+
73
+ # The file chooser
74
+ self.btnData = Gtk.FileChooserButton()
75
+ self.btnData.connect("file-set", self.on_file_set)
76
+ if len(options.files) > 0 :
77
+ ifile = Path(options.files[0]).expanduser().resolve().as_posix()
78
+ self.btnData.set_filename(ifile)
79
+ self.on_file_set()
80
+
81
+ # the folder option
82
+ self.btnFolder = Gtk.FileChooserButton()
83
+ self.btnFolder.set_action(Gtk.FileChooserAction.SELECT_FOLDER)
84
+ self.btnFolder.connect("file-set", self.on_folder_set)
85
+ if options.folder and len(options.folder) > 0 :
86
+ ifile = Path(options.folder).expanduser().resolve().as_posix()
87
+ self.btnFolder.set_filename(ifile)
88
+
89
+ # The Serial number
90
+ self.SN = itkdb_gtk.dbGtkUtils.TextEntry()
91
+ self.SN.connect("text-changed", self.on_SN_changed)
92
+ if options.SN:
93
+ self.on_SN_changed(self.SN.entry, options.SN)
94
+
95
+ # The prefix
96
+ self.prefix = Gtk.Entry()
97
+ if options.prefix:
98
+ self.SN.set_text(options.prefix)
99
+
100
+ self.desy = Gtk.Switch()
101
+ self.desy.props.halign = Gtk.Align.START
102
+
103
+ self.back = Gtk.Switch()
104
+ self.back.props.halign = Gtk.Align.START
105
+ self.back.connect("state_set", self.change_to_back)
106
+
107
+ self.run = Gtk.Button(label="Run")
108
+ self.run.connect("clicked", self.run_analysis)
109
+
110
+ self.btn_state = Gtk.Button(label="Undef")
111
+ self.btn_state.set_name("btnState")
112
+ self.btn_state.connect("clicked", self.show_state)
113
+ self.btn_state.set_tooltip_text("If green all good. Click to see commnets and defects.")
114
+
115
+ if options.desy:
116
+ self.desy.set_active(True)
117
+
118
+ # Put the 3 objects in a Grid
119
+ grid = Gtk.Grid(column_spacing=5, row_spacing=5)
120
+ self.mainBox.pack_start(grid, False, True, 0)
121
+
122
+ grid.attach(Gtk.Label(label="Serial No."), 0, 0, 1, 1)
123
+ grid.attach(self.SN.entry, 1, 0, 1, 1)
124
+
125
+ grid.attach(self.btn_state, 2, 0, 1, 1)
126
+
127
+ grid.attach(Gtk.Label(label="DESY"), 3, 0, 1, 1)
128
+ grid.attach(self.desy, 4, 0, 1, 1)
129
+
130
+ grid.attach(Gtk.Label(label="Prefix"), 0, 1, 1, 1)
131
+ grid.attach(self.prefix, 1, 1, 1, 1)
132
+
133
+ grid.attach(Gtk.Label(label="Data File"), 0, 2, 1, 1)
134
+ grid.attach(self.btnData, 1, 2, 1, 1)
135
+
136
+ grid.attach(Gtk.Label(label="Back"), 2, 2, 1, 1)
137
+ grid.attach(self.back, 3, 2, 1, 1)
138
+ grid.attach(Gtk.Label(label="Front"), 4, 2, 1, 1)
139
+
140
+
141
+
142
+ grid.attach(Gtk.Label(label="Folder"), 0, 3, 1, 1)
143
+ grid.attach(self.btnFolder, 1, 3, 1, 1)
144
+
145
+ grid.attach(self.run, 0, 4, 5, 1)
146
+
147
+
148
+ self.mainBox.pack_start(self.message_panel.frame, True, True, 0)
149
+
150
+ def quit(self, *args):
151
+ """Quits the application."""
152
+ self.hide()
153
+ self.destroy()
154
+
155
+
156
+ def on_file_set(self, *args):
157
+ """File chosen from FileChooser."""
158
+ PSF = self.btnData.get_filename()
159
+ if PSF is None or not Path(PSF).exists():
160
+ itkdb_gtk.dbGtkUtils.complain("Could not find Data File", PSF, parent=self)
161
+ return
162
+
163
+ self.data_file = PSF
164
+
165
+ def on_folder_set(self, *args):
166
+ """Folder chosen."""
167
+ F = self.btnFolder.get_filename()
168
+ if F is None or not Path(F).exists():
169
+ itkdb_gtk.dbGtkUtils.complain("Could not find Output folder", F, parent=self)
170
+ return
171
+
172
+ self.folder = F
173
+ self.options.folder = F
174
+
175
+ def on_SN_changed(self, entry, value):
176
+ """New SN given. Ask in PDB,"""
177
+ if len(value) <= 0:
178
+ return None
179
+
180
+
181
+ obj = itkdb_gtk.ITkDButils.get_DB_component(self.session, value)
182
+ if obj is not None:
183
+ entry.set_text(obj["serialNumber"])
184
+ self.alternativeID = obj["alternativeIdentifier"]
185
+ self.change_to_back(None)
186
+
187
+ else:
188
+ itkdb_gtk.dbGtkUtils.complain("Invalid SN", value)
189
+
190
+ def change_to_back(self, *args):
191
+ """The front/back switch has changed."""
192
+ is_front = self.back.get_active()
193
+ if self.alternativeID is None:
194
+ return
195
+
196
+ if is_front:
197
+ txt = "{}-front".format(self.alternativeID)
198
+ else:
199
+ txt = "{}-back".format(self.alternativeID)
200
+
201
+ self.prefix.set_text(txt)
202
+
203
+ def check_SN(self, SN):
204
+ """Checks the serial number."""
205
+ if len(SN) <= 0:
206
+ return None
207
+
208
+ obj = itkdb_gtk.ITkDButils.get_DB_component(self.session, SN)
209
+ if obj is None:
210
+ return None
211
+
212
+ if self.alternativeID is None:
213
+ self.alternativeID = obj["alternativeIdentifier"]
214
+
215
+ self.change_to_back(None)
216
+ return obj["serialNumber"]
217
+
218
+ def show_state(self, *arg):
219
+ """Shows the status"""
220
+ if self.outDB is None:
221
+ dialog = Gtk.MessageDialog(
222
+ transient_for=self,
223
+ flags=0,
224
+ message_type=Gtk.MessageType.INFO,
225
+ buttons=Gtk.ButtonsType.OK,
226
+ text="State undefined",
227
+ )
228
+ dialog.format_secondary_text(
229
+ "No analysis data available yet."
230
+ )
231
+ dialog.run()
232
+ dialog.destroy()
233
+ return
234
+
235
+ ndef = len(self.outDB["defects"])
236
+ ncomm = len(self.outDB["comments"])
237
+
238
+ if ndef+ncomm == 0:
239
+ dialog = Gtk.MessageDialog(
240
+ transient_for=self,
241
+ flags=0,
242
+ message_type=Gtk.MessageType.INFO,
243
+ buttons=Gtk.ButtonsType.OK,
244
+ text="All good",
245
+ )
246
+ dialog.format_secondary_text(
247
+ "Petal core passed without problems."
248
+ )
249
+ dialog.run()
250
+ dialog.destroy()
251
+ return
252
+
253
+ msg = ""
254
+ if ndef:
255
+ msg += "Defects\n"
256
+ for D in self.outDB["defects"]:
257
+ msg += "{}: {}\n".format(D["name"], D["description"])
258
+
259
+ if ncomm:
260
+ msg += "Comments\n"
261
+ for C in self.outDB["comments"]:
262
+ msg += "{}\n".format(C)
263
+
264
+
265
+ dialog = Gtk.MessageDialog(
266
+ transient_for=self,
267
+ flags=0,
268
+ message_type=Gtk.MessageType.INFO,
269
+ buttons=Gtk.ButtonsType.OK,
270
+ text="Problems found",
271
+ )
272
+
273
+ dialog.format_secondary_text(msg)
274
+ dialog.run()
275
+ dialog.destroy()
276
+
277
+ def run_analysis(self, *args):
278
+ """Run metrology."""
279
+ if self.data_file is None:
280
+ itkdb_gtk.dbGtkUtils.complain("No data file set", "Select one", parent=self)
281
+ return
282
+
283
+ if self.desy.get_active():
284
+ self.options.desy = True
285
+
286
+ is_front = self.back.get_active()
287
+ suffix = "back"
288
+ if is_front:
289
+ suffix = "front"
290
+
291
+ self.petal_prefix = self.prefix.get_text().strip()
292
+ if len(self.petal_prefix) == 0:
293
+ self.petal_prefix = "{}-{}".format(self.alternativeID, suffix)
294
+ self.prefix.set_text(self.petal_prefix)
295
+
296
+ self.petal_SN = self.SN.get_text().strip()
297
+ if len(self.petal_SN) == 0 or self.petal_SN is None:
298
+ itkdb_gtk.dbGtkUtils.complain("Invalid SN", "SN: {}".format(self.petal_SN), parent=self)
299
+ return
300
+
301
+
302
+ with redirect_stdout(self.message_panel):
303
+ self.outDB = do_analysis(self.data_file, self.petal_prefix, self.petal_SN, self.options)
304
+
305
+ if len(self.outDB["defects"]) > 0:
306
+ itkdb_gtk.dbGtkUtils.set_button_color(self.btn_state, "red", "white")
307
+ self.btn_state.set_label("FAILED")
308
+ elif len(self.outDB["comments"]) > 0:
309
+ itkdb_gtk.dbGtkUtils.set_button_color(self.btn_state, "orange", "white")
310
+ self.btn_state.set_label("PROBLEMS")
311
+ else:
312
+ itkdb_gtk.dbGtkUtils.set_button_color(self.btn_state, "green", "white")
313
+ self.btn_state.set_label("PASSED")
314
+
315
+
316
+ def show_test_gui(self, *args):
317
+ """Show test data."""
318
+ if self.outDB is None:
319
+ return
320
+
321
+ values, rc = itkdb_gtk.dbGtkUtils.DictDialog.create_json_data_editor(self.outDB)
322
+ if rc == Gtk.ResponseType.OK:
323
+ self.outDB = values
324
+
325
+ def upload_test_gui(self, *args):
326
+ """Uploads test and attachments."""
327
+ self.upload_test()
328
+
329
+ def upload_test(self):
330
+ """Uploads test and attachments."""
331
+ if self.outDB is None:
332
+ return
333
+ uploadW = itkdb_gtk.UploadTest.UploadTest(self.session, payload=self.outDB)
334
+
335
+
336
+ def main():
337
+ """Entry point."""
338
+ parser = ArgumentParser()
339
+ parser.add_argument('files', nargs='*', help="Input files")
340
+ parser.add_argument("--prefix", dest='prefix', default=None)
341
+ parser.add_argument("--SN", dest='SN', default=None)
342
+ parser.add_argument("--save", dest='save', action="store_true", default=False)
343
+ parser.add_argument("--desy", dest='desy', action="store_true", default=False)
344
+ parser.add_argument("--out", dest="out", default="petal_flatness.docx",
345
+ type=str, help="The output fiel name")
346
+ parser.add_argument("--bottom-lp", dest='bLP', action=CommaSeparatedListAction, default=None,
347
+ help="Bottom locking point fiducial coordinates")
348
+ parser.add_argument("--upper-lp", dest='uLP', action=CommaSeparatedListAction, default=None,
349
+ help="upper locking point fiducials coordinates")
350
+
351
+ parser.add_argument("--title", dest="title", default=None,
352
+ type=str, help="Document title")
353
+ parser.add_argument("--nbins", dest="nbins", default=25,
354
+ type=int, help="Number of bins")
355
+ parser.add_argument("--folder", default=None, help="Folder to store output files. Superseeds folder in --out")
356
+ parser.add_argument("--locking_points", action="store_true", default=False)
357
+
358
+ # This is to convert a CMM file
359
+ parser.add_argument("--label", default="\\w+", help="The label to select")
360
+ parser.add_argument("--type", default="Punto", help="The class to select")
361
+
362
+ options = parser.parse_args()
363
+
364
+
365
+ # ITk PDB authentication
366
+ dlg = None
367
+ try:
368
+ # We use here the Gtk GUI
369
+ from itkdb_gtk import ITkDBlogin
370
+ dlg = ITkDBlogin.ITkDBlogin()
371
+ client = dlg.get_client()
372
+
373
+ except Exception:
374
+ # Login with "standard" if the above fails.
375
+ import itkdb
376
+ import getpass
377
+ client = itkdb.Client()
378
+ client.user._access_code1 = getpass.getpass("Access 1: ")
379
+ client.user._access_code2 = getpass.getpass("Access 2: ")
380
+ client.user.authenticate()
381
+ print("Hello {} !".format(client.user.name))
382
+
383
+ CM = CoreMetrology(options, session=client, title="Petal core metrology")
384
+ CM.write_message("Welcome !\n")
385
+ CM.connect("destroy", Gtk.main_quit)
386
+
387
+ CM.show_all()
388
+ try:
389
+ Gtk.main()
390
+
391
+ except KeyboardInterrupt:
392
+ print("Arrrgggg!!!")
393
+
394
+
395
+ try:
396
+ dlg.die()
397
+
398
+ except Exception:
399
+ print("Bye !")
400
+
401
+ if __name__ == "__main__":
402
+ main()
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env python3
2
+ """Convert IFIC raw data to CVS."""
3
+ import io
4
+ from metrology.convert_mitutoyo import mitutoyo2cvs
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+
8
+ def data2cvs(ifile, options):
9
+ """Read CMM file and convert to CSV.
10
+
11
+ Args:
12
+ ifile: Input file path
13
+ options: Program options
14
+
15
+ """
16
+ ofiles = []
17
+ odata = io.StringIO()
18
+ mitutoyo2cvs(ifile, odata, r"Punto[-|Vision-]\w", "Punto")
19
+
20
+ outfile = "{}-petal.csv".format(options.prefix)
21
+ with open(outfile, mode='w') as f:
22
+ f.write(odata.getvalue())
23
+
24
+ ofiles.append(outfile)
25
+
26
+ odata = io.StringIO()
27
+ mitutoyo2cvs(ifile, odata, "PuntoLocator", "Punto")
28
+
29
+ outfile = "{}-locators.csv".format(options.prefix)
30
+ with open(outfile, mode='w') as f:
31
+ f.write(odata.getvalue())
32
+
33
+ ofiles.append(outfile)
34
+ return ofiles
35
+
36
+ if __name__ == "__main__":
37
+ import argparse
38
+ import sys
39
+
40
+ parser = argparse.ArgumentParser()
41
+ parser.add_argument('files', nargs='*', help="Input files")
42
+ parser.add_argument("--prefix", default="out", help="Output file")
43
+ parser.add_argument("--show", action="store_true", default=False)
44
+
45
+ options = parser.parse_args()
46
+ if len(options.files) == 0:
47
+ print(sys.argv[0])
48
+ print("I need an input file")
49
+ sys.exit()
50
+
51
+ ofiles = data2cvs(options.files, options)
52
+
53
+ if options.show:
54
+ for outfile in ofiles:
55
+ x, y, z = np.loadtxt(outfile, unpack=True, skiprows=1, delimiter=',')
56
+ fig, ax = plt.subplots(subplot_kw={'projection': '3d'})
57
+ surf = ax.scatter(x, y, z, c=z, marker='.', cmap=plt.cm.jet)
58
+ ax.set_xlabel("X")
59
+ ax.set_ylabel("Y")
60
+ ax.set_zlabel("Z")
61
+ fig.colorbar(surf, shrink=0.5, aspect=5, location="left")
62
+
63
+ plt.show()
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env python3
2
+ """Does metrology of all files listed at input file.
3
+
4
+ Examples:
5
+
6
+ python3 ~/cernbox/workspace/Petal-QC/do_Metrology.py ~/Desktop/petal-metrology-files.txt
7
+ python3 ~/cernbox/workspace/Petal-QC/do_Metrology.py --desy ~/Desktop/DESY-petal-metrology.txt
8
+
9
+ """
10
+ import json
11
+ import sys
12
+ import traceback
13
+ from argparse import Action
14
+ from argparse import ArgumentParser
15
+ from pathlib import Path
16
+ import numpy as np
17
+ from petal_qc.utils.utils import output_folder
18
+
19
+ from petal_qc.metrology.PetalMetrology import petal_metrology
20
+
21
+
22
+ class CommaSeparatedListAction(Action):
23
+ """Create a list from the comma sepparated numbers at imput."""
24
+
25
+ def __call__(self, parser, namespace, values, option_string=None):
26
+ """The actual action."""
27
+ value = np.array(list(map(float, values.split(','))), dtype='float64')
28
+ if value.shape[0] < 3:
29
+ raise Exception("{} needs a 3D vector".format(self.dest))
30
+
31
+ setattr(namespace, self.dest, value)
32
+
33
+ def do_analysis(fnam, prefix, SN, options):
34
+ """Perform analysis of a file.
35
+
36
+ Args:
37
+ fnam (): Input data file
38
+ prefix (): Prefix telling if it is front or back
39
+ SN (): Core serial number
40
+ options (): Options.
41
+
42
+ """
43
+
44
+ is_front = prefix.lower().find("front") >= 0
45
+ print(fnam, prefix)
46
+ options.out = prefix + '.docx'
47
+ options.title = prefix
48
+ options.is_front = is_front
49
+ if not hasattr(options, "SN"):
50
+ options.SN = ""
51
+
52
+ options.SN = SN
53
+ outDB = petal_metrology(fnam, options)
54
+
55
+ ofile = output_folder(options.folder, prefix + '.json')
56
+ with open(ofile, 'w', encoding='UTF-8') as of:
57
+ json.dump(outDB, of, indent=3)
58
+
59
+ return outDB
60
+
61
+ def main(ifile, options):
62
+ """Main entry."""
63
+ with open(ifile, 'r', encoding='UTF-8') as inp:
64
+
65
+ for line in inp:
66
+ line = line.strip()
67
+ if len(line) == 0:
68
+ continue
69
+
70
+ if line[0] == '#':
71
+ continue
72
+
73
+ SN = ""
74
+ try:
75
+ fnam, prefix = line.split()
76
+ except Exception:
77
+ fnam, prefix, SN, *_ = line.split()
78
+
79
+ do_analysis(fnam, prefix, SN, options)
80
+
81
+
82
+ if __name__ == "__main__":
83
+ parser = ArgumentParser()
84
+ parser.add_argument('files', nargs='*', help="Input files")
85
+ parser.add_argument("--prefix", dest='prefix', default=None)
86
+ parser.add_argument("--SN", dest='SN', default=None)
87
+ parser.add_argument("--save", dest='save', action="store_true", default=False)
88
+ parser.add_argument("--desy", dest='desy', action="store_true", default=False)
89
+ parser.add_argument("--out", dest="out", default="petal_flatness.docx",
90
+ type=str, help="The output fiel name")
91
+ parser.add_argument("--bottom-lp", dest='bLP', action=CommaSeparatedListAction, default=None,
92
+ help="Bottom locking point fiducial coordinates")
93
+ parser.add_argument("--upper-lp", dest='uLP', action=CommaSeparatedListAction, default=None,
94
+ help="upper locking point fiducials coordinates")
95
+
96
+ parser.add_argument("--title", dest="title", default=None,
97
+ type=str, help="Document title")
98
+ parser.add_argument("--nbins", dest="nbins", default=25,
99
+ type=int, help="Number of bins")
100
+ parser.add_argument("--folder", default=None, help="Folder to store output files. Superseeds folder in --out")
101
+ parser.add_argument("--locking_points", action="store_true", default=False)
102
+
103
+ # This is to convert a CMM file
104
+ parser.add_argument("--label", default="\\w+", help="The label to select")
105
+ parser.add_argument("--type", default="Punto", help="The class to select")
106
+
107
+ options = parser.parse_args()
108
+ if len(options.files) == 0:
109
+ print(sys.argv[0])
110
+ print("I need an input file")
111
+ sys.exit()
112
+
113
+ try:
114
+ main(options.files[0], options)
115
+
116
+ except Exception:
117
+ print(traceback.format_exc())