diff --git a/src/components/tecna_marposs_provaset_t3.py b/src/components/tecna_marposs_provaset_t3.py index 201e681..cfba77b 100644 --- a/src/components/tecna_marposs_provaset_t3.py +++ b/src/components/tecna_marposs_provaset_t3.py @@ -1,4 +1,4 @@ -from lib.db import Recipes, Steps, db +from lib.db import Recipes, db from PyQt5.QtCore import QSemaphore, pyqtSignal from PyQt5.QtWidgets import QMessageBox @@ -333,7 +333,7 @@ class TecnaMarpossProvasetT3(ModbusComponent): recipes = [] for recipe in list(Recipes.select().order_by(Recipes.name.asc())): # if recipe.spec["leak_1"]: - recipes.append([recipe, Steps.get_by_id(recipe.spec["available_steps"]["leak_1"])]) + recipes.append([recipe, recipe.spec["steps"]["leak_1"]]) # reverve last for our recipe control if len(recipes) > max(self.max_program_number - 1, 0): self.log.warning(f"too many recipes ({len(recipes)}), saving only first {max(self.max_program_number - 1, 0)}") diff --git a/src/lib/db/__init__.py b/src/lib/db/__init__.py index d96896e..bad5971 100644 --- a/src/lib/db/__init__.py +++ b/src/lib/db/__init__.py @@ -12,7 +12,6 @@ models_reference = { "archive": Archive, "log": Log, "recipes": Recipes, - "steps": Steps, "users": Users, } @@ -49,57 +48,6 @@ def init_db(): except FileNotFoundError: pass - # try: - # with open("src/lib/db/imports/connectors.csv", "r") as f: - # log.info("importing connectors") - # reader = csv.DictReader(f) - # count = 0 - # for row in reader: - # steps = {} - # for step_type, step_spec in { - # "connector": {"connector": row["connector"]}, - # "barcodes": {"serial": ""}, - # "resistance": {"scale": 500, "expected": float(row["resistance_expected"]), "tolerance": float(row["resistance_tolerance"])}, - # "leak_1": {"pre_filling_time": 1, "pre_filling_pressure": 1000, "filling_time": 1, "settling_time": 1, "settling_pressure_min_percent": 5, "settling_pressure_max_percent": 5, "test_time": 5, "test_pressure_qneg": 100, "test_pressure": 1000, "test_pressure_qpos": 100, "flush_time": 1, "flush_pressure": 100}, - # "leak_2": {"pre_filling_time": 1, "pre_filling_pressure": 1000, "filling_time": 1, "settling_time": 1, "settling_pressure_min_percent": 5, "settling_pressure_max_percent": 5, "test_time": 5, "test_pressure_qneg": 100, "test_pressure": 1000, "test_pressure_qpos": 100, "flush_time": 1, "flush_pressure": 100}, - # "vision": {"recipe": "termorestringente_923578.ini"}, - # "print": {"template": "EtichettaR5.prn", }, - # }.items(): - # steps[step_type] = Steps( - # type=re.sub(r"^(.*)_[0-9]+$", r"\1", step_type), - # spec=step_spec, - # ) - # steps[step_type].save(force_insert=True) - # recipe = Recipes( - # name=row["name"], - # client=row["client"], - # part_number=row["part_number"], - # spec={ - # "connector": True, - # "barcodes": True, - # "resistance": True, - # "leak_1": False, - # "leak_2": False, - # "vision": False, - # "print": True, - # "steps": [steps["connector"].name, steps["resistance"].name, steps["print"].name, ], # pks of the enabled steps - # "available_steps": { - # "connector": steps["connector"].name, - # "barcodes": steps["barcodes"].name, - # "resistance": steps["resistance"].name, - # "leak_1": steps["leak_1"].name, - # "leak_2": steps["leak_2"].name, - # "vision": steps["vision"].name, - # "print": steps["print"].name, - # }, - # }, - # ) - # recipe.save(force_insert=True) - # count += 1 - # log.info(f"connectors: imported {count} rows.") - # except FileNotFoundError: - # pass - init_db() diff --git a/src/lib/db/models/__init__.py b/src/lib/db/models/__init__.py index ee3118a..d26cab3 100644 --- a/src/lib/db/models/__init__.py +++ b/src/lib/db/models/__init__.py @@ -2,5 +2,4 @@ from .archive import Archive from .base_model import db from .log import Log from .recipes import Recipes -from .steps import Steps from .users import Session, Users diff --git a/src/lib/helpers/step.py b/src/lib/helpers/step.py new file mode 100644 index 0000000..9429943 --- /dev/null +++ b/src/lib/helpers/step.py @@ -0,0 +1,8 @@ + + +class Step(object): + step_type = None + spec = {} + def __init__(self,step_type=None,spec=dict): + self.step_type = step_type + self.spec = spec diff --git a/src/main.py b/src/main.py index 45583be..78efe28 100644 --- a/src/main.py +++ b/src/main.py @@ -277,7 +277,7 @@ try: app = QApplication(sys.argv) with SingleProcess() as single_process_lock: - if not single_process_lock: + if not single_process_lock and "--no-lock" not in sys.argv: logging.error(f"Program already opened, exiting...") QMessageBox.critical(None, "ERRORE", "IL PROGRAMMA E' GIA' IN ESECUZIONE") exit(0) diff --git a/src/ui/crud/crud.py b/src/ui/crud/crud.py index 7f0d111..57b633c 100755 --- a/src/ui/crud/crud.py +++ b/src/ui/crud/crud.py @@ -270,7 +270,7 @@ class Crud(Widget): self.filter_delay = QTimer() self.filter_delay.setSingleShot(True) self.filter_delay.setInterval(500) - self.filter_delay.timeout.connect(lambda self=weakref.ref(self): self().do_filter(self().filter_cn)) + self.filter_delay.timeout.connect(lambda selfi=weakref.ref(self): selfi().do_filter(selfi().filter_cn)) self.db_tw.crud = self self.refresh("init") self.db_tw.horizontalHeader().sectionClicked.connect(self.toggle_sort) @@ -283,13 +283,13 @@ class Crud(Widget): else: self.db_tw.setSelectionMode(QAbstractItemView.ExtendedSelection) self.db_tw.itemSelectionChanged.connect(self.show_selection) - self.revert_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("revert")) + self.revert_b.clicked.connect(lambda checked, selfi=weakref.ref(self): selfi().refresh("revert")) if self.pagination is not False: - self.start_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("pagination", page=0)) - self.previous_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("pagination", page=max(self().page - 1, 0))) - self.page_n_sb.valueChanged.connect(lambda page, self=weakref.ref(self): self().refresh("pagination", page=page - 1)) - self.next_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("pagination", page=self().page + 1)) - self.end_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("pagination", page=-1)) + self.start_b.clicked.connect(lambda checked, selfi=weakref.ref(self): selfi().refresh("pagination", page=0)) + self.previous_b.clicked.connect(lambda checked, selfi=weakref.ref(self): selfi().refresh("pagination", page=max(selfi().page - 1, 0))) + self.page_n_sb.valueChanged.connect(lambda page, selfi=weakref.ref(self): selfi().refresh("pagination", page=page - 1)) + self.next_b.clicked.connect(lambda checked, selfi=weakref.ref(self): selfi().refresh("pagination", page=selfi().page + 1)) + self.end_b.clicked.connect(lambda checked, selfi=weakref.ref(self): selfi().refresh("pagination", page=-1)) else: self.next_b.setHidden(True) self.previous_b.setHidden(True) @@ -468,8 +468,8 @@ class Crud(Widget): if fn in self.db.table_fields: w.setPlaceholderText("Filtro") w.setText(self.filters.get(fn, None)) - w.editingFinished.connect(lambda cn=cn, self=weakref.ref(self): self().do_filter(cn)) - w.textChanged.connect(lambda text, cn=cn, self=weakref.ref(self): self().filter_edited(cn)) + w.editingFinished.connect(lambda cni=cn, selfi=weakref.ref(self): selfi().do_filter(cni)) + w.textChanged.connect(lambda text, cni=cn, selfi=weakref.ref(self): selfi().filter_edited(cni)) else: w.setPlaceholderText("Non filtrabile") w.setEnabled(False) diff --git a/src/ui/recipe_selection/recipe_selection.py b/src/ui/recipe_selection/recipe_selection.py index 766eaf8..98d6675 100755 --- a/src/ui/recipe_selection/recipe_selection.py +++ b/src/ui/recipe_selection/recipe_selection.py @@ -9,6 +9,8 @@ from lib.db import Recipes, Users, db from PyQt5.QtCore import QTimer, pyqtSignal from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QFileDialog, QMessageBox, QShortcut + +from lib.helpers.step import Step from ui.crud import Crud, Json_External_Dialog_Editor_Cell_Widget from ui.helpers import replace_widget from ui.recipe_spec_and_step_editor import Recipe_Spec_And_Step_Editor @@ -298,6 +300,8 @@ class Recipe_Selection(Widget): row = dict((k.lower(), v) for k, v in ucrow.items()) recipe_name = row.get(recipe_name_field, defaults["codice_ricetta"]) steps_specs = self.read_steps(row, defaults=defaults) + + # create recipe or update existing one in DB try: recipe = Recipes.get_by_id(recipe_name) steps = recipe.get_steps_map() @@ -305,14 +309,11 @@ class Recipe_Selection(Widget): except Recipes.DoesNotExist: recipe = Recipes(name=recipe_name, part_number="TEMPORARY") steps = {} - for step_type, step_spec in steps_specs.items(): - step = {} - steps[step_type] = step + for step_name, step_spec in steps_specs.items(): + if step_name not in self.unsupported_steps: + steps[step_name] = step_spec recipe_is_new = True - for step_name, step_spec in steps_specs.items(): - step = steps[step_name] - step.type = step_name - step.spec = step_spec + recipe.client = row.get("cliente", defaults["cliente"]) recipe.part_number = row.get(part_number_field, defaults["part_number"]) recipe.description = row.get(description_field, defaults["descrizione"]) @@ -329,23 +330,8 @@ class Recipe_Selection(Widget): "leak_2": len(row.get("prova_tenuta_abilitata_2", defaults["prova_tenuta_abilitata_2"])) and "leak_2" not in self.unsupported_steps, "vision": len(row.get("test_visione_abilitato", defaults["test_visione_abilitato"])) and "vision" not in self.unsupported_steps, "print": len(row.get("stampa_etichetta_abilitata", defaults["stampa_etichetta_abilitata"])) and "print" not in self.unsupported_steps, - "steps": [], # should be pks of the enabled steps - "available_steps": { - "count": steps["count"].get_id(), - "connector": steps["connector"].get_id(), - "barcodes": steps["barcodes"].get_id(), - "resistance": steps["resistance"].get_id(), - "screws": steps["screws"].get_id(), - "instruction": steps["instruction"].get_id(), - "leak_1": steps["leak_1"].get_id(), - "leak_2": steps["leak_2"].get_id(), - "vision": steps["vision"].get_id(), - "print": steps["print"].get_id(), - }, + "steps": steps, } - for step_name, step in recipe.spec["available_steps"].items(): - if recipe.spec[step_name]: - recipe.spec["steps"].append(step) if recipe_is_new: recipe.save(force_insert=True) else: diff --git a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py index e49bd66..40ee0e9 100644 --- a/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py +++ b/src/ui/recipe_spec_and_step_editor/recipe_spec_and_step_editor.py @@ -98,7 +98,6 @@ class Recipe_Spec_And_Step_Editor(Editor): self.steps_tw.setTabVisible(self.steps_tw.indexOf(map["tab"]), not map.get("hidden", False)) self.save_steps_b.clicked.connect(self.save_steps) self.reset_steps_b.clicked.connect(self.reset_steps) - self.available_steps = {} self.recipe = None def set_readonly(self, readonly=True): @@ -130,7 +129,6 @@ class Recipe_Spec_And_Step_Editor(Editor): def render(self, data, field_name=None, row_number=None, crud=None): super().render(data, field_name=field_name, row_number=row_number, crud=crud) - self.available_steps = data.get("available_steps", None) steps = set(data.get("steps", set())) for map in self.steps_map.values(): step = map.get("step", None) @@ -141,9 +139,7 @@ class Recipe_Spec_And_Step_Editor(Editor): def parse(self, action=None, row_number=None, crud=None): ret = super().parse(row_number=row_number, crud=crud) ret["steps"] = [] - ret["available_steps"] = {} for step_name, map in self.steps_map.items(): - ret["available_steps"][step_name] = map["step"].name if map["enable"].isChecked() and not map.get("hidden", False): ret["steps"].append(map["step"].name) return ret diff --git a/src/ui/test/test.py b/src/ui/test/test.py index b4a379c..616eeb6 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -7,8 +7,9 @@ from datetime import datetime, timedelta from components import ArchiveSynchronizer from PyQt5.QtCore import QTimer, pyqtSlot from PyQt5.QtWidgets import QMessageBox -from lib.db import Archive, Steps, Users +from lib.db import Archive, Recipes, Users from lib.helpers import get_shift +from lib.helpers.step import Step from playhouse.shortcuts import model_to_dict from ui.barcode_recipe_selection import Barcode_Recipe_Selection from ui.helpers import replace_widget @@ -259,7 +260,7 @@ class Test(Widget): if self.config["hardware_config"]["tecna_t3"] == "present" or self.config["hardware_config"]["furness_controls"] == "present": self.cycle_available_steps["leak_1"].widget.recipe_written = False self.cycle_available_steps["leak_2"].widget.recipe_written = False - self.step = Steps(type="select_recipe") + self.step = Step(step_type="select_recipe") self.cycle_index = -1 self.recipe = None self.cycle_steps = None @@ -269,7 +270,7 @@ class Test(Widget): elif action in ("fail", "abort"): self.log.info(f"cycle next: action: {action!r}") # FAIL AND RESTART TEST - self.step = Steps(type="fail") + self.step = Step(step_type="fail") self.cycle_index = -1 # COUNT FAIL if action == "fail": @@ -282,10 +283,10 @@ class Test(Widget): # if recipe not set: select_recipe if self.recipe_selection_mode == "barcode": self.log.info(f"returning to barcode recipe selection") - self.step = Steps(type="barcode_recipe_selection") + self.step = {"type":"barcode_recipe_selection","spec":{}} else: self.log.info(f"returning to recipe selection table") - self.step = Steps(type="select_recipe") + self.step = Step(step_type="select_recipe") elif action is None: if self.autotest_request is not False and self.autotest_cycle_steps is not None and not self.autotesting and (self.cycle_index == -1 or self.cycle_index + 1 >= len(self.cycle_steps)): # if autotest was requested @@ -324,25 +325,25 @@ class Test(Widget): else: self.cycle_index = -1 - self.step = Steps(type=None) + self.step = Step(step_type=None) # enable/disable cycle controls self.change_recipe_b.setEnabled(self.recipe is not None) - self.cancel_b.setEnabled(self.step.type is not None and self.step.type not in { + self.cancel_b.setEnabled(self.step.step_type is not None and self.step.step_type not in { "emergency", "fail", "select_recipe", "wait", }) - self.log.info(f"next cycle step: {model_to_dict(self.step)!r}") + self.log.info(f"next cycle step: {self.step.step_type!r}") # INIT TEST DATA IF STARTING CYCLE LOOP OR IF RESET IS NEEDED if self.cycle_index == 0: self.data = {"ok": True, "overridden": False} self.archived = None if self.recipe is not None and "recipe" not in self.data: self.data["recipe"] = model_to_dict(self.recipe) - w = self.cycle_available_steps[self.step.type] + w = self.cycle_available_steps[self.step.step_type] show = None - if self.step.type == "leak_2": + if self.step.step_type == "leak_2": self.setCentralWidget(w) # NEED TO PRESHOW UI if hasattr(w, "start"): show = w.start(recipe=self.recipe, step=self.step, pieces=self.pieces) @@ -350,16 +351,16 @@ class Test(Widget): self.setCentralWidget(w) elif show is False: self.next_timer.start(0) - if self.step.type == "done": + if self.step.step_type == "done": self.archived = self.done() self.last_label = copy.deepcopy(self.archived) self.next_timer.start(500) - elif self.step.type == "print": + elif self.step.step_type == "print": compiled_label = self.print(self.archived, self.step.spec.get("template", "EtichettaR5")) self.archived.label = compiled_label self.archived.save() self.next_timer.start(500) - elif self.step.type == "wait": + elif self.step.step_type == "wait": self.next_timer.start(500) # UPDATE COUNT DISPLAY self.update_count_display() @@ -387,7 +388,7 @@ class Test(Widget): # create step sequence list barcode_names = ['serial', 'barcode_input_2', 'barcode_input_3', 'barcode_input_4', 'barcode_input_5'] for i, step in enumerate(steps): - if step.type == "barcodes": + if step.step_type == "barcodes": n_pieces = int(step.spec.get("n_pieces", 1)) n_pieces_adapted = n_pieces if n_pieces_adapted == 1: @@ -401,47 +402,47 @@ class Test(Widget): steps.insert(i + 1, new_barcode_step) if i in skip: continue - if step.type == "vision": + if step.step_type == "vision": self.components["vision"].config_changed(vision_recipe=self.recipe.name) - if step.type == "count": + if step.step_type == "count": count_found = True if "warning_img" in step.spec: if step.spec["warning_img"]: - steps.insert(i, Steps(type="warning_img", spec={"warning_img": step.spec["warning_img"]})) + steps.insert(i, Step(step_type="warning_img", spec={"warning_img": step.spec["warning_img"]})) skip.add(i + 1) if "assembly" in step.spec: if step.spec["assembly"]: - steps.insert(i, Steps(type="instructions", spec={})) + steps.insert(i, Step(step_type="instructions", spec={})) skip.add(i + 1) if "require_discard_piece" in step.spec: if step.spec["require_discard_piece"]: self.require_discard_piece = True - if step.type == "resistance": # ADD STEP TO ENSURE REMOVAL OF CONNECTOR - steps.insert(i + 1, Steps(type="resistance", spec={ + if step.step_type == "resistance": # ADD STEP TO ENSURE REMOVAL OF CONNECTOR + steps.insert(i + 1, Step(step_type="resistance", spec={ "scale": 500, "expected": float("+inf"), "tolerance_pos": 0, "tolerance_neg": 0, })) skip.add(i + 1) - if step.type == "print": + if step.step_type == "print": if print_found: continue - steps.insert(i, Steps(type="done")) + steps.insert(i, Step(step_type="done")) print_found = True self.print_step = step if self.config["hardware_config"].get("enforce_piece_removal", "no") == "yes": - steps.append(Steps(type="piece_removal")) + steps.append(Step(step_type="piece_removal")) if count_found: - steps.append(Steps(type="count_end")) - if step.type in ("leak_1", "leak_2"): + steps.append(Step(step_type="count_end")) + if step.step_type in ("leak_1", "leak_2"): self.leak_step = step if not print_found: - steps.append(Steps(type="done")) + steps.append(Step(step_type="done")) if count_found: - steps.append(Steps(type="count_end")) - steps.append(Steps(type="wait")) + steps.append(Step(step_type="count_end")) + steps.append(Step(step_type="wait")) self.cycle_steps = steps self.check_steps_dependencies(self.cycle_steps) leak_autotest_steps = [] @@ -457,32 +458,32 @@ class Test(Widget): l_at_2["test_pressure_qneg"] = l_at_2["test_pressure_tt_qneg"] l_at_2["test_pressure_qpos"] = l_at_2["test_pressure_tt_qpos"] l_at_2["autotest"] = "ok_check" - leak_autotest_steps = [Steps(type="leak_1", spec=l_at_1), Steps(type="leak_1", spec=l_at_2)] + leak_autotest_steps = [Step(step_type="leak_1", spec=l_at_1), Step(step_type="leak_1", spec=l_at_2)] self.autotest_cycle_steps = [ *([ - Steps(type="resistance", spec={ + Step(step_type="resistance", spec={ "scale": 500, "expected": 1, "tolerance_pos": 5, "tolerance_neg": 5, "autotest": True, }), - Steps(type="resistance", spec={ + Step(step_type="resistance", spec={ "scale": 500, "expected": float("+inf"), "tolerance_pos": 0, "tolerance_neg": 0, "autotest": True, }), - Steps(type="resistance", spec={ + Step(step_type="resistance", spec={ "scale": 500, "expected": 10, "tolerance_pos": 1, "tolerance_neg": 1, "autotest": True, }), - Steps(type="resistance", spec={ + Step(step_type="resistance", spec={ "scale": 500, "expected": float("+inf"), "tolerance_pos": 0, @@ -491,8 +492,8 @@ class Test(Widget): }), ] if "resistance" not in self.unsupported_steps else []), *(leak_autotest_steps), - Steps(type="done"), - Steps(type="wait"), + Step(step_type="done"), + Step(step_type="wait"), ] for w in self.cycle_available_steps.values(): if hasattr(w, "reset"): @@ -513,13 +514,13 @@ class Test(Widget): unsupported_steps = set() missing_components = set() for step in steps: - if step.type in self.unsupported_steps or step.type not in self.cycle_available_steps: - unsupported_steps.add(step.type) + if step.step_type in self.unsupported_steps or step.step_type not in self.cycle_available_steps: + unsupported_steps.add(step.step_type) else: - for dependency in self.steps_dependencies.get(step.type, []): + for dependency in self.steps_dependencies.get(step.step_type, []): if isinstance(dependency, tuple): if all([d not in self.components for d in dependency]): - unsupported_steps.add(step.type) + unsupported_steps.add(step.step_type) else: unready = set() for d in dependency: @@ -534,7 +535,7 @@ class Test(Widget): missing_components.add(" or ".join(dependency)) else: if dependency not in self.components: - unsupported_steps.add(step.type) + unsupported_steps.add(step.step_type) else: if not self.components[dependency].ready: self.components[dependency].reconfigure() @@ -571,7 +572,6 @@ class Test(Widget): # remove useless info self.data.get("recipe", {}).get("spec", {}).pop("steps", None) - self.data.get("recipe", {}).get("spec", {}).pop("available_steps", None) for leak in ["leak_1", "leak_2"]: if leak in self.data.keys(): results = {k: self.data[leak]["results"][self.tester_component][k] for k in ["Running test: result"]} @@ -757,7 +757,7 @@ class Test(Widget): def load_recipe_from_rfid(self, data): if data not in(None,''): self.tag_loaded_recipe = data - if self.step.type == "barcode_recipe_selection": + if self.step.step_type == "barcode_recipe_selection": if data is not None: self.cycle_available_steps["barcode_recipe_selection"].widget.get(data) else: