hardpy 0.18.3__py3-none-any.whl → 0.19.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.
Files changed (26) hide show
  1. hardpy/common/config.py +45 -2
  2. hardpy/hardpy_panel/api.py +100 -11
  3. hardpy/hardpy_panel/frontend/dist/assets/{allPaths-31ulJ0tA.js → allPaths-C_-7WXHD.js} +1 -1
  4. hardpy/hardpy_panel/frontend/dist/assets/{allPathsLoader-HPn4WHWu.js → allPathsLoader-DgH0Xily.js} +2 -2
  5. hardpy/hardpy_panel/frontend/dist/assets/{browser-ponyfill-BQ1ipruI.js → browser-ponyfill-BbOvdqIF.js} +1 -1
  6. hardpy/hardpy_panel/frontend/dist/assets/index-DEJb2W0B.js +4679 -0
  7. hardpy/hardpy_panel/frontend/dist/assets/{splitPathsBySizeLoader-ev1ZiRR9.js → splitPathsBySizeLoader-o5HCcdVL.js} +1 -1
  8. hardpy/hardpy_panel/frontend/dist/index.html +1 -1
  9. hardpy/hardpy_panel/frontend/dist/locales/cs/translation.json +85 -0
  10. hardpy/hardpy_panel/frontend/dist/locales/de/translation.json +11 -1
  11. hardpy/hardpy_panel/frontend/dist/locales/en/translation.json +11 -1
  12. hardpy/hardpy_panel/frontend/dist/locales/es/translation.json +11 -1
  13. hardpy/hardpy_panel/frontend/dist/locales/fr/translation.json +11 -1
  14. hardpy/hardpy_panel/frontend/dist/locales/ja/translation.json +11 -1
  15. hardpy/hardpy_panel/frontend/dist/locales/ru/translation.json +11 -1
  16. hardpy/hardpy_panel/frontend/dist/locales/zh/translation.json +11 -1
  17. hardpy/pytest_hardpy/plugin.py +24 -0
  18. hardpy/pytest_hardpy/pytest_wrapper.py +91 -5
  19. hardpy/pytest_hardpy/reporter/base.py +5 -0
  20. hardpy/pytest_hardpy/reporter/hook_reporter.py +19 -2
  21. {hardpy-0.18.3.dist-info → hardpy-0.19.1.dist-info}/METADATA +2 -1
  22. {hardpy-0.18.3.dist-info → hardpy-0.19.1.dist-info}/RECORD +25 -24
  23. hardpy/hardpy_panel/frontend/dist/assets/index-BK2y65ib.js +0 -4673
  24. {hardpy-0.18.3.dist-info → hardpy-0.19.1.dist-info}/WHEEL +0 -0
  25. {hardpy-0.18.3.dist-info → hardpy-0.19.1.dist-info}/entry_points.txt +0 -0
  26. {hardpy-0.18.3.dist-info → hardpy-0.19.1.dist-info}/licenses/LICENSE +0 -0
@@ -1 +1 @@
1
- import{_ as o,a as _,b as i,p as c,I as u}from"./index-BK2y65ib.js";var p=function(n,s){return o(void 0,void 0,void 0,function(){var a,r;return _(this,function(e){switch(e.label){case 0:return a=c(n),s!==u.STANDARD?[3,2]:[4,i(()=>import("./index-DLOviMB1.js").then(t=>t.I),[])];case 1:return r=e.sent(),[3,4];case 2:return[4,i(()=>import("./index-B-fsa5Ru.js").then(t=>t.I),[])];case 3:r=e.sent(),e.label=4;case 4:return[2,r[a]]}})})};export{p as splitPathsBySizeLoader};
1
+ import{_ as o,a as _,b as i,p as c,I as u}from"./index-DEJb2W0B.js";var p=function(n,s){return o(void 0,void 0,void 0,function(){var a,r;return _(this,function(e){switch(e.label){case 0:return a=c(n),s!==u.STANDARD?[3,2]:[4,i(()=>import("./index-DLOviMB1.js").then(t=>t.I),[])];case 1:return r=e.sent(),[3,4];case 2:return[4,i(()=>import("./index-B-fsa5Ru.js").then(t=>t.I),[])];case 3:r=e.sent(),e.label=4;case 4:return[2,r[a]]}})})};export{p as splitPathsBySizeLoader};
@@ -25,7 +25,7 @@
25
25
  Learn how to configure a non-root public URL by running `npm run build`.
26
26
  -->
27
27
  <title>HardPy Operator Panel</title>
28
- <script type="module" crossorigin src="/assets/index-BK2y65ib.js"></script>
28
+ <script type="module" crossorigin src="/assets/index-DEJb2W0B.js"></script>
29
29
  <link rel="stylesheet" crossorigin href="/assets/index-B7T9xvaW.css">
30
30
  </head>
31
31
  <body>
@@ -0,0 +1,85 @@
1
+ {
2
+ "app": {
3
+ "title": "HardPy Panel operátora",
4
+ "lastLaunch": "Poslední běh:",
5
+ "duration": "Doba trvání",
6
+ "seconds": "s",
7
+ "soundOn": "Zapnout zvuk",
8
+ "soundOff": "Vypnout zvuk",
9
+ "debugOn": "Zapnout režim ladění",
10
+ "debugOff": "Vypnout režim ladění",
11
+ "connection": "Navazuji spojení... 🧐🔎",
12
+ "dbError": "Chyba připojení k databázi. 🙅🏽‍♀️🚫",
13
+ "noEntries": "Žádné záznamy v databázi 🙅🏽‍♀️🚫",
14
+ "stoppedTestCase": "Zastavený test",
15
+ "failedTestCases": "Testy selhaly",
16
+ "modalResultDismissHint": "Klikněte kamkoliv nebo stiskněte libovolnou klávesu pro zavření",
17
+ "modalResultAutoDismissHint": "Automaticky zmizí za {{seconds}} sekund...",
18
+ "manualCollectOn": "Zapnout manuální výběr testů",
19
+ "manualCollectOff": "Vypnout manuální výběr testů",
20
+ "testConfigurationSelector": "Vyberte testovací konfiguraci",
21
+ "status": {
22
+ "ready": "Připraveno",
23
+ "run": "Běží",
24
+ "passed": "Uspěl",
25
+ "failed": "Neuspěl",
26
+ "stopped": "Zastaveno",
27
+ "unknown": "Neznámý"
28
+ }
29
+ },
30
+ "button": {
31
+ "start": "Začít",
32
+ "stop": "Zastavit",
33
+ "confirm": "Potvrdit",
34
+ "pass": "OK",
35
+ "fail": "Zrušit"
36
+ },
37
+ "error": {
38
+ "dbConnectionTitle": "Chyba připojení k databázi",
39
+ "dbConnectionMessage": "Nepodařilo se navázat spojení s databází"
40
+ },
41
+ "chart": {
42
+ "dataChart": "Grafy",
43
+ "xAxis": "Osa X",
44
+ "yAxis": "Osa Y",
45
+ "chart": "Graf",
46
+ "showChart": "Zobrazit graf {{title}}",
47
+ "fullscreenButton": "Otevřít graf na celé obrazovce",
48
+ "series": "Řada {{number}}"
49
+ },
50
+ "operatorDialog": {
51
+ "defaultTitle": "Zpráva",
52
+ "imageAlt": "Obrázek pro operátora",
53
+ "htmlCodeTitle": "HTML kód",
54
+ "htmlLinkTitle": "HTML odkaz",
55
+ "enterAnswer": "Zadejte odpověď",
56
+ "fieldNotEmpty": "Pole nesmí být prázdné",
57
+ "notificationTitle": "Oznámení",
58
+ "notificationDesc": "Okno bylo uzavřeno. Testy byly zastaveny.",
59
+ "numericInputError": "Zadejte prosím číslo",
60
+ "radioButtonError": "Vyberte prosím jednu možnost",
61
+ "checkboxError": "Vyberte prosím alespoň jednu možnost"
62
+ },
63
+ "suiteList": {
64
+ "loadingTests": "Načítání testů... 🤔",
65
+ "refreshHint": "Zkuste aktualizovat stránku.",
66
+ "standName": "Název stanoviště",
67
+ "status": "Stav",
68
+ "startTime": "Čas zahájení",
69
+ "finishTime": "Čas dokončení",
70
+ "alert": "Upozornění"
71
+ },
72
+ "testSuite": {
73
+ "nameColumn": "Název",
74
+ "dataColumn": "Údaje",
75
+ "loading": "Načítám...",
76
+ "stubName": "Sada testů",
77
+ "runSelectedTests": "Spustit {{count}} vybrané testy",
78
+ "noTestsSelected": "Nebyly vybrány žádné testy",
79
+ "testsStarted": "Zahájené testy {{count}}",
80
+ "startError": "Chyba při spouštění testů",
81
+ "connectionError": "Chyba připojení",
82
+ "selectionColumn": "Vybrat",
83
+ "skipped": "Přeskočeno"
84
+ }
85
+ }
@@ -15,6 +15,9 @@
15
15
  "failedTestCases": "Fehlgeschlagene Testfälle",
16
16
  "modalResultDismissHint": "Klicken Sie irgendwo oder drücken Sie eine Taste, um zu schließen",
17
17
  "modalResultAutoDismissHint": "Automatisches Schließen in {{seconds}} Sekunden...",
18
+ "manualCollectOn": "Manuelle Sammlung ein",
19
+ "manualCollectOff": "Manuelle Sammlung aus",
20
+ "testConfigurationSelector": "Testkonfiguration auswählen",
18
21
  "status": {
19
22
  "ready": "Bereit",
20
23
  "run": "Läuft",
@@ -70,6 +73,13 @@
70
73
  "nameColumn": "Name",
71
74
  "dataColumn": "Daten",
72
75
  "loading": "Wird geladen...",
73
- "stubName": "Testgruppe"
76
+ "stubName": "Testgruppe",
77
+ "runSelectedTests": "{{count}} ausgewählte Tests ausführen",
78
+ "noTestsSelected": "Keine Tests ausgewählt",
79
+ "testsStarted": "{{count}} Tests gestartet",
80
+ "startError": "Fehler beim Starten der Tests",
81
+ "connectionError": "Verbindungsfehler",
82
+ "selectionColumn": "Auswählen",
83
+ "skipped": "Übersprungen"
74
84
  }
75
85
  }
@@ -15,6 +15,9 @@
15
15
  "failedTestCases": "Failed Test Cases",
16
16
  "modalResultDismissHint": "Click anywhere or press any key to dismiss",
17
17
  "modalResultAutoDismissHint": "Auto-dismissing in {{seconds}} seconds...",
18
+ "manualCollectOn": "Manual collect on",
19
+ "manualCollectOff": "Manual collect off",
20
+ "testConfigurationSelector": "Select test configuration",
18
21
  "status": {
19
22
  "ready": "Ready",
20
23
  "run": "Run",
@@ -70,6 +73,13 @@
70
73
  "nameColumn": "Name",
71
74
  "dataColumn": "Data",
72
75
  "loading": "Loading...",
73
- "stubName": "Test Suite"
76
+ "stubName": "Test Suite",
77
+ "runSelectedTests": "Run {{count}} selected tests",
78
+ "noTestsSelected": "No tests selected",
79
+ "testsStarted": "Started {{count}} tests",
80
+ "startError": "Error starting tests",
81
+ "connectionError": "Connection error",
82
+ "selectionColumn": "Select",
83
+ "skipped": "Skipped"
74
84
  }
75
85
  }
@@ -15,6 +15,9 @@
15
15
  "failedTestCases": "Casos de prueba fallidos",
16
16
  "modalResultDismissHint": "Haga clic en cualquier lugar o presione cualquier tecla para cerrar",
17
17
  "modalResultAutoDismissHint": "Cierre automático en {{seconds}} segundos...",
18
+ "manualCollectOn": "Recolección manual activada",
19
+ "manualCollectOff": "Recolección manual desactivada",
20
+ "testConfigurationSelector": "Seleccionar configuración de prueba",
18
21
  "status": {
19
22
  "ready": "Listo",
20
23
  "run": "Ejecutando",
@@ -70,6 +73,13 @@
70
73
  "nameColumn": "Nombre",
71
74
  "dataColumn": "Datos",
72
75
  "loading": "Cargando...",
73
- "stubName": "Conjunto de pruebas"
76
+ "stubName": "Conjunto de pruebas",
77
+ "runSelectedTests": "Ejecutar {{count}} pruebas seleccionadas",
78
+ "noTestsSelected": "No hay pruebas seleccionadas",
79
+ "testsStarted": "{{count}} pruebas iniciadas",
80
+ "startError": "Error al iniciar las pruebas",
81
+ "connectionError": "Error de conexión",
82
+ "selectionColumn": "Seleccionar",
83
+ "skipped": "Omitido"
74
84
  }
75
85
  }
@@ -15,6 +15,9 @@
15
15
  "failedTestCases": "Cas de test échoués",
16
16
  "modalResultDismissHint": "Cliquez n'importe où ou appuyez sur n'importe quelle touche pour fermer",
17
17
  "modalResultAutoDismissHint": "Fermeture automatique dans {{seconds}} secondes...",
18
+ "manualCollectOn": "Collecte manuelle activée",
19
+ "manualCollectOff": "Collecte manuelle désactivée",
20
+ "testConfigurationSelector": "Sélectionner la configuration de test",
18
21
  "status": {
19
22
  "ready": "Prêt",
20
23
  "run": "En cours",
@@ -70,6 +73,13 @@
70
73
  "nameColumn": "Nom",
71
74
  "dataColumn": "Données",
72
75
  "loading": "Chargement...",
73
- "stubName": "Suite de tests"
76
+ "stubName": "Suite de tests",
77
+ "runSelectedTests": "Exécuter {{count}} tests sélectionnés",
78
+ "noTestsSelected": "Aucun test sélectionné",
79
+ "testsStarted": "{{count}} tests démarrés",
80
+ "startError": "Erreur de démarrage des tests",
81
+ "connectionError": "Erreur de connexion",
82
+ "selectionColumn": "Sélectionner",
83
+ "skipped": "Ignoré"
74
84
  }
75
85
  }
@@ -15,6 +15,9 @@
15
15
  "failedTestCases": "失敗したテストケース",
16
16
  "modalResultDismissHint": "どこかをクリックするか、任意のキーを押して閉じます",
17
17
  "modalResultAutoDismissHint": "{{seconds}}秒後に自動的に閉じます...",
18
+ "manualCollectOn": "手動収集オン",
19
+ "manualCollectOff": "手動収集オフ",
20
+ "testConfigurationSelector": "テスト構成を選択する",
18
21
  "status": {
19
22
  "ready": "準備完了",
20
23
  "run": "実行中",
@@ -70,6 +73,13 @@
70
73
  "nameColumn": "名前",
71
74
  "dataColumn": "データ",
72
75
  "loading": "読み込み中...",
73
- "stubName": "テストスイート"
76
+ "stubName": "テストスイート",
77
+ "runSelectedTests": "選択した{{count}}個のテストを実行",
78
+ "noTestsSelected": "テストが選択されていません",
79
+ "testsStarted": "{{count}}個のテストを開始しました",
80
+ "startError": "テストの開始エラー",
81
+ "connectionError": "接続エラー",
82
+ "selectionColumn": "選択",
83
+ "skipped": "スキップ済み"
74
84
  }
75
85
  }
@@ -15,6 +15,9 @@
15
15
  "failedTestCases": "Проваленные тестовые случаи",
16
16
  "modalResultDismissHint": "Нажмите на любое место на экране или нажмите любую клавишу для закрытия",
17
17
  "modalResultAutoDismissHint": "Автоматическое закрытие через {{seconds}} секунд...",
18
+ "manualCollectOn": "Ручной сбор включен",
19
+ "manualCollectOff": "Ручной сбор выключен",
20
+ "testConfigurationSelector": "Выберите конфигурацию теста",
18
21
  "status": {
19
22
  "ready": "Готов",
20
23
  "run": "Выполнение",
@@ -70,6 +73,13 @@
70
73
  "nameColumn": "Название",
71
74
  "dataColumn": "Данные",
72
75
  "loading": "Загрузка...",
73
- "stubName": "Тестовый набор"
76
+ "stubName": "Тестовый набор",
77
+ "runSelectedTests": "Запустить {{count}} выбранных тестов",
78
+ "noTestsSelected": "Тесты не выбраны",
79
+ "testsStarted": "Запущено {{count}} тестов",
80
+ "startError": "Ошибка запуска тестов",
81
+ "connectionError": "Ошибка соединения",
82
+ "selectionColumn": "Выбрать",
83
+ "skipped": "Пропущен"
74
84
  }
75
85
  }
@@ -15,6 +15,9 @@
15
15
  "failedTestCases": "失败的测试用例",
16
16
  "modalResultDismissHint": "点击任意位置或按任意键关闭",
17
17
  "modalResultAutoDismissHint": "{{seconds}}秒后自动关闭...",
18
+ "manualCollectOn": "手动收集开启",
19
+ "manualCollectOff": "手动收集关闭",
20
+ "testConfigurationSelector": "选择测试配置",
18
21
  "status": {
19
22
  "ready": "就绪",
20
23
  "run": "运行中",
@@ -70,6 +73,13 @@
70
73
  "nameColumn": "名称",
71
74
  "dataColumn": "数据",
72
75
  "loading": "加载中...",
73
- "stubName": "测试套件"
76
+ "stubName": "测试套件",
77
+ "runSelectedTests": "运行 {{count}} 个选中的测试",
78
+ "noTestsSelected": "未选择任何测试",
79
+ "testsStarted": "已启动 {{count}} 个测试",
80
+ "startError": "启动测试时出错",
81
+ "connectionError": "连接错误",
82
+ "selectionColumn": "选择",
83
+ "skipped": "已跳过"
74
84
  }
75
85
  }
@@ -205,6 +205,7 @@ class HardpyPlugin:
205
205
  status = self._get_run_status(exitstatus)
206
206
  if status == TestStatus.STOPPED:
207
207
  self._stop_tests()
208
+ self._validate_stop_time()
208
209
  self._reporter.finish(status)
209
210
  self._reporter.update_db_by_doc()
210
211
  self._reporter.compact_all()
@@ -483,6 +484,29 @@ class HardpyPlugin:
483
484
  case _:
484
485
  return TestStatus.FAILED
485
486
 
487
+ def _validate_stop_time(self) -> None:
488
+ """Update module and case stop times if they are not set.
489
+
490
+ If module start time is set but module stop time is not set,
491
+ set module stop time to module start time.
492
+ If case start time is set but case stop time is not set, set
493
+ case stop time to case start time.
494
+ """
495
+ for module_id, module_data in self._results.items():
496
+ module_start_time = self._reporter.get_module_start_time(module_id)
497
+ module_stop_time = self._reporter.get_module_stop_time(module_id)
498
+ if module_start_time and not module_stop_time:
499
+ self._reporter.set_module_stop_time(module_start_time)
500
+ for module_data_key in module_data:
501
+ # skip module status
502
+ if module_data_key == "module_status":
503
+ continue
504
+ case_id = module_data_key
505
+ case_start_time = self._reporter.get_case_start_time(module_id, case_id)
506
+ case_stop_time = self._reporter.get_case_stop_time(module_id, case_id)
507
+ if case_start_time and not case_stop_time:
508
+ self._reporter.set_case_stop_time(case_start_time)
509
+
486
510
  def _stop_tests(self) -> None:
487
511
  """Update module and case statuses to stopped and skipped."""
488
512
  is_module_stopped = False
@@ -2,6 +2,7 @@
2
2
  # GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
  from __future__ import annotations
4
4
 
5
+ import logging
5
6
  import signal
6
7
  import subprocess
7
8
  import sys
@@ -11,6 +12,9 @@ from hardpy.common.config import ConfigManager
11
12
  from hardpy.pytest_hardpy.db import DatabaseField as DF # noqa: N817
12
13
  from hardpy.pytest_hardpy.reporter import RunnerReporter
13
14
 
15
+ logging.basicConfig(level=logging.INFO)
16
+ logger = logging.getLogger(__name__)
17
+
14
18
 
15
19
  class PyTestWrapper:
16
20
  """Wrapper for pytest subprocess."""
@@ -24,11 +28,35 @@ class PyTestWrapper:
24
28
  # before clients come in
25
29
  self._config_manager = ConfigManager()
26
30
  self.config = self._config_manager.config
27
- self.collect(is_clear_database=True)
28
31
 
29
- def start(self, start_args: dict | None = None) -> bool:
32
+ # Check to see if there are any test configs defined in the TOML file
33
+ if not self.config.test_configs:
34
+ self.collect(is_clear_database=True)
35
+ else:
36
+ self._reporter.clear_database()
37
+ # Check if there's a current test config selected in statestore
38
+ config_name = self.config.current_test_config
39
+ if config_name:
40
+ try:
41
+ self.collect(is_clear_database=True)
42
+ except Exception:
43
+ # No existing test configs in statestore, will be initialized later
44
+ msg = "Error retrieving current test config from statestore."
45
+ logger.exception(msg)
46
+ else:
47
+ logger.info("No existing test config selection found.")
48
+
49
+ def start(
50
+ self,
51
+ start_args: dict | None = None,
52
+ selected_tests: list[str] | None = None,
53
+ ) -> bool:
30
54
  """Start pytest subprocess.
31
55
 
56
+ Args:
57
+ start_args: Additional start arguments
58
+ selected_tests: List of selected tests
59
+
32
60
  Returns:
33
61
  bool: True if pytest was started
34
62
  """
@@ -45,15 +73,23 @@ class PyTestWrapper:
45
73
  "--hardpy-db-url",
46
74
  self.config.database.url,
47
75
  "--hardpy-tests-name",
48
- self.config.tests_name,
76
+ self._tests_name(),
49
77
  "--sc-address",
50
78
  self.config.stand_cloud.address,
51
79
  ]
80
+
81
+ if selected_tests:
82
+ selected_test_cases = self._select_test_cases(selected_tests)
83
+ cmd.extend(selected_test_cases)
84
+
85
+ self._add_config_file(cmd)
86
+
52
87
  if self.config.stand_cloud.connection_only:
53
88
  cmd.append("--sc-connection-only")
54
89
  if self.config.stand_cloud.autosync:
55
90
  cmd.append("--sc-autosync")
56
91
  cmd.append("--hardpy-pt")
92
+
57
93
  if start_args:
58
94
  for key, value in start_args.items():
59
95
  arg_str = f"{key}={value}"
@@ -87,12 +123,18 @@ class PyTestWrapper:
87
123
  return True
88
124
  return False
89
125
 
90
- def collect(self, *, is_clear_database: bool = False) -> bool:
126
+ def collect(
127
+ self,
128
+ *,
129
+ is_clear_database: bool = False,
130
+ selected_tests: list[str] | None = None,
131
+ ) -> bool:
91
132
  """Perform pytest collection.
92
133
 
93
134
  Args:
94
135
  is_clear_database (bool): indicates whether database
95
136
  should be cleared. Defaults to False.
137
+ selected_tests (list[str]): list of selected tests
96
138
 
97
139
  Returns:
98
140
  bool: True if collection was started
@@ -110,13 +152,19 @@ class PyTestWrapper:
110
152
  "--hardpy-db-url",
111
153
  self.config.database.url,
112
154
  "--hardpy-tests-name",
113
- self.config.tests_name,
155
+ self._tests_name(),
114
156
  "--hardpy-pt",
115
157
  ]
116
158
 
117
159
  if is_clear_database:
118
160
  args.append("--hardpy-clear-database")
119
161
 
162
+ self._add_config_file(args)
163
+
164
+ if selected_tests:
165
+ selected_test_cases = self._select_test_cases(selected_tests)
166
+ args.extend(selected_test_cases)
167
+
120
168
  subprocess.Popen( # noqa: S603
121
169
  [self.python_executable, *args],
122
170
  cwd=self._config_manager.tests_path,
@@ -158,3 +206,41 @@ class PyTestWrapper:
158
206
  """
159
207
  config_manager = ConfigManager()
160
208
  return config_manager.config.model_dump()
209
+
210
+ def _tests_name(self) -> str:
211
+ manual_str = ""
212
+ if self.config.frontend.manual_collect:
213
+ manual_str = " Manual mode"
214
+
215
+ tests_name = (
216
+ self.config.tests_name + f" {self.config.current_test_config}"
217
+ if self.config.current_test_config
218
+ else self.config.tests_name
219
+ )
220
+ return tests_name + manual_str
221
+
222
+ def _add_config_file(self, cmd: list) -> None:
223
+ """Add test configuration file if specified."""
224
+ config_name = self.config.current_test_config
225
+ test_config_file = None
226
+
227
+ if self.config.test_configs:
228
+ for config in self.config.test_configs:
229
+ if config.name == config_name:
230
+ test_config_file = config.file
231
+ break
232
+
233
+ if test_config_file:
234
+ logging.info(f"Using test configuration file: {test_config_file}")
235
+ cmd.extend(["--config-file", test_config_file])
236
+
237
+ def _select_test_cases(self, selected_tests: list[str]) -> list[str]:
238
+ test_cases = []
239
+ for test_path in selected_tests:
240
+ if "::" in test_path:
241
+ module_name, case_name = test_path.split("::", 1)
242
+ case_path = f"{module_name}.py::{case_name}"
243
+ test_cases.append(case_path)
244
+ else:
245
+ test_cases.append(f"{test_path}.py")
246
+ return test_cases
@@ -116,3 +116,8 @@ class BaseReporter:
116
116
  DF.ATTEMPT,
117
117
  )
118
118
  return self._statestore.get_field(key)
119
+
120
+ def clear_database(self) -> None:
121
+ """Clear both statestore and runstore databases directly."""
122
+ self._statestore.clear()
123
+ self._runstore.clear()
@@ -20,8 +20,7 @@ class HookReporter(BaseReporter):
20
20
  def __init__(self, is_clear_database: bool = False) -> None:
21
21
  super().__init__()
22
22
  if is_clear_database:
23
- self._statestore.clear()
24
- self._runstore.clear()
23
+ self.clear_database()
25
24
  self._log = getLogger(__name__)
26
25
 
27
26
  def init_doc(self, doc_name: str) -> None:
@@ -232,6 +231,15 @@ class HookReporter(BaseReporter):
232
231
  key = self.generate_key(DF.MODULES, module_id, DF.START_TIME)
233
232
  return self._statestore.get_field(key)
234
233
 
234
+ def get_module_stop_time(self, module_id: str) -> int:
235
+ """Get module stop time.
236
+
237
+ Returns:
238
+ int: module time
239
+ """
240
+ key = self.generate_key(DF.MODULES, module_id, DF.STOP_TIME)
241
+ return self._statestore.get_field(key)
242
+
235
243
  def get_case_start_time(self, module_id: str, case_id: str) -> int:
236
244
  """Get case start time.
237
245
 
@@ -241,6 +249,15 @@ class HookReporter(BaseReporter):
241
249
  key = self.generate_key(DF.MODULES, module_id, DF.CASES, case_id, DF.START_TIME)
242
250
  return self._statestore.get_field(key)
243
251
 
252
+ def get_case_stop_time(self, module_id: str, case_id: str) -> int:
253
+ """Get case stop time.
254
+
255
+ Returns:
256
+ int: module time
257
+ """
258
+ key = self.generate_key(DF.MODULES, module_id, DF.CASES, case_id, DF.STOP_TIME)
259
+ return self._statestore.get_field(key)
260
+
244
261
  def set_caused_dut_failure_id(self, module_id: str, case_id: str) -> None:
245
262
  """Set caused DUT failure id.
246
263
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hardpy
3
- Version: 0.18.3
3
+ Version: 0.19.1
4
4
  Summary: HardPy library for device testing
5
5
  Project-URL: Homepage, https://github.com/everypinio/hardpy/
6
6
  Project-URL: Documentation, https://everypinio.github.io/hardpy/
@@ -69,6 +69,7 @@ HardPy is a python library for creating a test bench for devices.
69
69
  [![pytest versions](https://img.shields.io/badge/pytest-%3E%3D7.0-blue)](https://docs.pytest.org/en/latest/)
70
70
  [![Documentation](https://img.shields.io/badge/Documentation%20-Overview%20-%20%23007ec6)](https://everypinio.github.io/hardpy/)
71
71
  [![Reddit](https://img.shields.io/badge/-Reddit-FF4500?style=flat&logo=reddit&logoColor=white)](https://www.reddit.com/r/HardPy)
72
+ [![Discord](https://img.shields.io/discord/1304494076799877172?color=7389D8&label&logo=discord&logoColor=ffffff)]()
72
73
  [![Telegram](https://img.shields.io/badge/-Telegram-2CA5E0?style=flat&logo=telegram&logoColor=white)](https://t.me/everypin)
73
74
 
74
75
  </div>
@@ -3,7 +3,7 @@ hardpy/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  hardpy/cli/cli.py,sha256=eg89XAcPSosykXyeWitcTigE-ZYiDeCknPWp9TpXxeA,11359
4
4
  hardpy/cli/template.py,sha256=kOl8hsj6iBTFIDUli_dzHkH8mlnoJzOlr9muLpTEayg,6230
5
5
  hardpy/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- hardpy/common/config.py,sha256=t1ij_-PiIuhIgXD0PP2fZeRJF-gQGGxthYsu1PQmDGQ,6430
6
+ hardpy/common/config.py,sha256=cgs4rGgRbKsDasM1NupmdERK2XaHZin3lLn346WRnKk,7730
7
7
  hardpy/common/singleton.py,sha256=RVMqbluN-mhlJ4QOYcRzQLA68Hs8t83XNyihyUwhYGo,948
8
8
  hardpy/common/stand_cloud/__init__.py,sha256=fezdiYAehtT2H-GAef-xZU12CbmCRe64XHA9UB3kJDU,456
9
9
  hardpy/common/stand_cloud/connector.py,sha256=PD1Gr1QOuFUmCsnlPY2zb_WF9Nrr8BGTlbRC2_LTKFE,8147
@@ -13,14 +13,14 @@ hardpy/common/stand_cloud/registration.py,sha256=UW-JGcvON5CMQQ-s2Mb4Ee3u_jmdQfS
13
13
  hardpy/common/stand_cloud/token_manager.py,sha256=oHLDip0a-0mmAiRQN5IuypTSNyOnSB43TSWlprOLRI0,4843
14
14
  hardpy/common/stand_cloud/utils.py,sha256=GN3wzbrmF-Xe5iUXf_HurGO-YKltqd3Gc_7vG2eEL7c,692
15
15
  hardpy/hardpy_panel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- hardpy/hardpy_panel/api.py,sha256=KNT4z5WNgpOjujAtBSmrPXsDmA5hUJKVeLZ6Ah9u_nk,8007
16
+ hardpy/hardpy_panel/api.py,sha256=F4wSHiE5kiFvthR_TdrcmXSbfq-gP00uZKC0Pnoyq-4,10744
17
17
  hardpy/hardpy_panel/frontend/dist/favicon.ico,sha256=sgIk5PKUKEKBDpkSrc8dJgjpObp0iF82Mec0GpfKId4,15406
18
- hardpy/hardpy_panel/frontend/dist/index.html,sha256=TOZiLD7WXiBB5W0GPF50u5zQtG0-gQ4Gd7n2757k-hU,1851
18
+ hardpy/hardpy_panel/frontend/dist/index.html,sha256=Hhb9wXuzSNSaG5KgX_63fvg0XEzwkp80jc-g-uobwqQ,1851
19
19
  hardpy/hardpy_panel/frontend/dist/logo192.png,sha256=E4K7drvhJCg9HcTpRihOXZhVJVBZ7-W97Se-3tDb46o,14485
20
20
  hardpy/hardpy_panel/frontend/dist/logo512.png,sha256=-fIMbqX7PYUpheK4kX1C1erRTe_hHZwFQYDLrAbhFRU,34188
21
21
  hardpy/hardpy_panel/frontend/dist/manifest.json,sha256=PfmJlN2JMJtHS6OnhU4b4X5wPQC_yRBdjesjoirObSA,502
22
- hardpy/hardpy_panel/frontend/dist/assets/allPaths-31ulJ0tA.js,sha256=6aCDALhkvoqh_BkyemOBKdzLPJOhj18DEGp4U7VYW5s,309
23
- hardpy/hardpy_panel/frontend/dist/assets/allPathsLoader-HPn4WHWu.js,sha256=8UGKsW3Y3J2koazg_rbu37B9r0t46FpctZmXpLbyLL0,550
22
+ hardpy/hardpy_panel/frontend/dist/assets/allPaths-C_-7WXHD.js,sha256=g19yyAeijLh7WccMXT8_tuk1S-uWTOyPFzWHpyUZLQc,309
23
+ hardpy/hardpy_panel/frontend/dist/assets/allPathsLoader-DgH0Xily.js,sha256=CRNnNN2zycYIwYtzHnBbPj5EbtZSGVhLGfvbOswm4SM,550
24
24
  hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-16-B2twAPZE.ttf,sha256=OcrUHPBAaLvJxb2DOethXFXg8PClDcyvpsh0mToLFPM,136248
25
25
  hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-16-C0Unyq1d.eot,sha256=Bl93LjY8pyBj0Iip1lUxMM-0l1zLrRjoGmKPPnAQIgw,136456
26
26
  hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-16-CVy9qFng.svg,sha256=57jlcc-NFRVJNJ3t-1fOnJvgdbYhcrF5a06LJLhWc5A,601027
@@ -31,24 +31,25 @@ hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-CjKGIKxE.woff,sha256
31
31
  hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-DQ09GSQq.svg,sha256=3gLRYNxd_Y4iz6pspH4Bf7Ql4F6LH5haZzbTfxA53HQ,638634
32
32
  hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-DmR755bS.ttf,sha256=yr5g5Jw9ZnxJJ7e1quOv977VE3NU2GRB60BMRrOJrcI,139424
33
33
  hardpy/hardpy_panel/frontend/dist/assets/blueprint-icons-20-p9MhBXD8.eot,sha256=CFx8t8ONhB4INIrK860N56_t1dmS7FuRF7i0HKKo58k,139632
34
- hardpy/hardpy_panel/frontend/dist/assets/browser-ponyfill-BQ1ipruI.js,sha256=sdj30Rkv2EtP1NuDSPy76SFDtb5ygKg4SpWu00g1sPk,10294
34
+ hardpy/hardpy_panel/frontend/dist/assets/browser-ponyfill-BbOvdqIF.js,sha256=ga4pi7C6UzfwyVTi8QiAL0rpgvlXPi37PXqlLP8A-Ug,10294
35
35
  hardpy/hardpy_panel/frontend/dist/assets/index-B-fsa5Ru.js,sha256=IonL7d7ppdDr-_FRJZQPWI4HHFTiygYvZGVlUxHY9R8,294235
36
36
  hardpy/hardpy_panel/frontend/dist/assets/index-B7T9xvaW.css,sha256=5m7QXWbthqi_Va8qlvnTZeuRzSN_ZJUdhyeb3JD6ZME,315862
37
- hardpy/hardpy_panel/frontend/dist/assets/index-BK2y65ib.js,sha256=Qu8WIJU1p-6KmwXRihdpyKcgjb-yz-INSmkYM5KSeM8,5952407
37
+ hardpy/hardpy_panel/frontend/dist/assets/index-DEJb2W0B.js,sha256=TVKRBm2PplF8vsQM_bEiA7VNhUKZHMDpD5Il33haQ40,6026022
38
38
  hardpy/hardpy_panel/frontend/dist/assets/index-DLOviMB1.js,sha256=sI0W1vvwqvIwKP2_jglrwOhej3n5rJD72-d4ZhlUHqM,285612
39
39
  hardpy/hardpy_panel/frontend/dist/assets/logo_smol-CK3jE85c.png,sha256=E4K7drvhJCg9HcTpRihOXZhVJVBZ7-W97Se-3tDb46o,14485
40
- hardpy/hardpy_panel/frontend/dist/assets/splitPathsBySizeLoader-ev1ZiRR9.js,sha256=l_5r-kXzX37BmRmog1OcIzqWxU1KMjRagQcTGQu9sPU,472
41
- hardpy/hardpy_panel/frontend/dist/locales/de/translation.json,sha256=vYVYRpSrpGZi7s8tPoAZxtVCeuPqhlwK1qC_lm52Pzc,2575
42
- hardpy/hardpy_panel/frontend/dist/locales/en/translation.json,sha256=jJ1DEY6-fx--a5VQW6SOYCvPLQXfizs-JtsRf1rohiI,2333
43
- hardpy/hardpy_panel/frontend/dist/locales/es/translation.json,sha256=_biD1ve2CpvFDeRO7dzoFyvbeFcz-572UzhUzn002Z8,2628
44
- hardpy/hardpy_panel/frontend/dist/locales/fr/translation.json,sha256=YC8aL1tDx8LjmfC2pjfJ_rjl_mSDGnUIxCa80ZqxLus,2635
45
- hardpy/hardpy_panel/frontend/dist/locales/ja/translation.json,sha256=kGBJmHlhnduRPLOIoSU1UoRy5RfJURGdg1YckIchA9w,2845
46
- hardpy/hardpy_panel/frontend/dist/locales/ru/translation.json,sha256=81pqFajGhSwPwZV4j0HpziB1oX2iJ5Ud12cLiAaX8J0,3467
47
- hardpy/hardpy_panel/frontend/dist/locales/zh/translation.json,sha256=9W61N2MA15J5Zj6UqBqPmUDZXaRAH2HWm9m51BgvzJw,2322
40
+ hardpy/hardpy_panel/frontend/dist/assets/splitPathsBySizeLoader-o5HCcdVL.js,sha256=ZvdGFd8j0qHvEPUqfpcCFtwRg2ptF-uPZCoJMUUK2Ac,472
41
+ hardpy/hardpy_panel/frontend/dist/locales/cs/translation.json,sha256=kCSbBWfQQ6lrVKlOeByXAhAoG5bBxrxf7-PTvvQgR2M,2964
42
+ hardpy/hardpy_panel/frontend/dist/locales/de/translation.json,sha256=wZRO5iz8VvaEjACSWHJNjjKerd8YcPo7gpziCpjfF1Q,3073
43
+ hardpy/hardpy_panel/frontend/dist/locales/en/translation.json,sha256=_vsAG4aOto5C-xiCQK0zip02u6f9wHr-T_BRr_DUdTo,2776
44
+ hardpy/hardpy_panel/frontend/dist/locales/es/translation.json,sha256=vkXYntVaRnl-aEZZpPFlQE7qJXC2rAuDvbAcXMwQ9V8,3154
45
+ hardpy/hardpy_panel/frontend/dist/locales/fr/translation.json,sha256=eZuiKx9s1Nz3E9xJ6o7HwRbofQzdOxF6WL9gzu8iMYs,3160
46
+ hardpy/hardpy_panel/frontend/dist/locales/ja/translation.json,sha256=4_MrBUHCneXgvGuWexs0a_viOxcEt40CWCKCgLHQHgU,3378
47
+ hardpy/hardpy_panel/frontend/dist/locales/ru/translation.json,sha256=LvJavIT8_HdrIMIvgGtRBoGOCs3DeBNyYg0BHALwmEg,4097
48
+ hardpy/hardpy_panel/frontend/dist/locales/zh/translation.json,sha256=ZmoqrndiAtatXSVDpz6looKb_2U_XnJdIidfK9o-uXY,2781
48
49
  hardpy/pytest_hardpy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
- hardpy/pytest_hardpy/plugin.py,sha256=RqBZeIjdrV7szq0tShjqq6TkpWWBhzQN89KcCHSYhEo,23335
50
+ hardpy/pytest_hardpy/plugin.py,sha256=m8vbDAA_cuxOlraJ2V_DvQ81E_06zJaTLF771nLLQMI,24591
50
51
  hardpy/pytest_hardpy/pytest_call.py,sha256=qUDrK1iUjhGEs4bmBFTk9E0YfFzsePoHhVDRY6ngRV8,22878
51
- hardpy/pytest_hardpy/pytest_wrapper.py,sha256=U-tguwJsyW_lDAbFcEOgutc6G__PmWnhuHA6fCgePUc,4792
52
+ hardpy/pytest_hardpy/pytest_wrapper.py,sha256=TS-Ysm1ou-bkkc50A0tdJWXCNx51sB1EOkUUYxQ64GA,7737
52
53
  hardpy/pytest_hardpy/db/__init__.py,sha256=nat_tUO2cxPIp9e6U8Fvg6V4NcZ9TVg27u0GHoKelD4,865
53
54
  hardpy/pytest_hardpy/db/base_store.py,sha256=d1lkTB7CpHTKysD2yuuGQFai44OtOmtTbq-WaBYojhw,5545
54
55
  hardpy/pytest_hardpy/db/const.py,sha256=E_A0IKGeS3qyPX4fTfUE5ksARsrTKSVWqUkdmh8S_fo,1414
@@ -59,8 +60,8 @@ hardpy/pytest_hardpy/db/tempstore.py,sha256=WKIykL_4A9j8n-F7pIy_9fj4BNOfzqWkUwg0
59
60
  hardpy/pytest_hardpy/db/schema/__init__.py,sha256=1S73W3PLQt8gX5Y33nbX1JdwLvnrtlKH4cElID3pwuc,263
60
61
  hardpy/pytest_hardpy/db/schema/v1.py,sha256=0RGZP-2lDeA3r8-simEEnjlHOAyziYSMXb9BINQyVbM,6377
61
62
  hardpy/pytest_hardpy/reporter/__init__.py,sha256=rztpM2HlLUpMOvad0JHbZU4Mk8PDDQyCFXLhpLktGQI,322
62
- hardpy/pytest_hardpy/reporter/base.py,sha256=Nz5cMTWfrVvn9sAQwRLAh_KXBP6zQoqEMpOkXCVpUCE,3494
63
- hardpy/pytest_hardpy/reporter/hook_reporter.py,sha256=IAseKoQcZWlgS3NLYNnBOC5aGsJUgzyZLqljpd8Tfsg,15672
63
+ hardpy/pytest_hardpy/reporter/base.py,sha256=hUt0UTzZOa9KdHj66cOnqgDVakYh4GncE1YkCFqwCBs,3666
64
+ hardpy/pytest_hardpy/reporter/hook_reporter.py,sha256=Et312HLWQ-WUSjRSNa4Yg392HbRRbCNfzRQWvcCC11c,16199
64
65
  hardpy/pytest_hardpy/reporter/runner_reporter.py,sha256=d9hyThq0tywelPnIIHVED2SyztavE5LbgcBSejXfnhA,787
65
66
  hardpy/pytest_hardpy/result/__init__.py,sha256=2afpuEuOcxYfIEOwWzsGZe960iQaPVCmsbYujijQg1s,592
66
67
  hardpy/pytest_hardpy/result/couchdb_config.py,sha256=ujxyJYM2pdZzi3GZ2Zysbz2_ZeTRN5sQc8AGuzRJm_0,3243
@@ -79,8 +80,8 @@ hardpy/pytest_hardpy/utils/exception.py,sha256=1l2VBZLUnjPDoOs744MtaP7Y9FuXUq7ko
79
80
  hardpy/pytest_hardpy/utils/machineid.py,sha256=6JAzUt7KtjTYn8kL9hSMaCQ20U8liH-zDT9v-5Ch7Q8,296
80
81
  hardpy/pytest_hardpy/utils/node_info.py,sha256=DaW566WvsyWR66CThuZ38UoHwQa-pu-4WRLg61OXDnE,7134
81
82
  hardpy/pytest_hardpy/utils/progress_calculator.py,sha256=TPl2gG0ZSvMe8otPythhF9hkD6fa6-mJAhy9yI83-yE,1071
82
- hardpy-0.18.3.dist-info/METADATA,sha256=rTmqFIGlh2GjKn6DceKb8MbIwj7ztnZTLLjCJymMuq0,4971
83
- hardpy-0.18.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
84
- hardpy-0.18.3.dist-info/entry_points.txt,sha256=nL2sMkKMScNaOE0IPkYnu9Yr-BUswZvGSrwY-SxHY3E,102
85
- hardpy-0.18.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
86
- hardpy-0.18.3.dist-info/RECORD,,
83
+ hardpy-0.19.1.dist-info/METADATA,sha256=nuj7JBfKBLgOYLW8ENRaflRnbGPZ0NesNnjjdKqGL7Y,5087
84
+ hardpy-0.19.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
85
+ hardpy-0.19.1.dist-info/entry_points.txt,sha256=nL2sMkKMScNaOE0IPkYnu9Yr-BUswZvGSrwY-SxHY3E,102
86
+ hardpy-0.19.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
87
+ hardpy-0.19.1.dist-info/RECORD,,