pysfi 0.1.10__py3-none-any.whl → 0.1.12__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.
- {pysfi-0.1.10.dist-info → pysfi-0.1.12.dist-info}/METADATA +9 -7
- pysfi-0.1.12.dist-info/RECORD +62 -0
- {pysfi-0.1.10.dist-info → pysfi-0.1.12.dist-info}/entry_points.txt +13 -2
- sfi/__init__.py +1 -1
- sfi/alarmclock/alarmclock.py +40 -40
- sfi/bumpversion/__init__.py +1 -1
- sfi/cleanbuild/cleanbuild.py +155 -0
- sfi/condasetup/condasetup.py +116 -0
- sfi/docdiff/docdiff.py +238 -0
- sfi/docscan/__init__.py +1 -1
- sfi/docscan/docscan_gui.py +1 -1
- sfi/docscan/lang/eng.py +152 -152
- sfi/docscan/lang/zhcn.py +170 -170
- sfi/filedate/filedate.py +185 -112
- sfi/gittool/__init__.py +2 -0
- sfi/gittool/gittool.py +401 -0
- sfi/llmclient/llmclient.py +592 -0
- sfi/llmquantize/llmquantize.py +480 -0
- sfi/llmserver/llmserver.py +335 -0
- sfi/makepython/makepython.py +2 -2
- sfi/pdfsplit/pdfsplit.py +4 -4
- sfi/pyarchive/pyarchive.py +418 -0
- sfi/pyembedinstall/__init__.py +0 -0
- sfi/pyembedinstall/pyembedinstall.py +629 -0
- sfi/pylibpack/pylibpack.py +813 -269
- sfi/pylibpack/rules/numpy.json +22 -0
- sfi/pylibpack/rules/pymupdf.json +10 -0
- sfi/pylibpack/rules/pyqt5.json +19 -0
- sfi/pylibpack/rules/pyside2.json +23 -0
- sfi/pylibpack/rules/scipy.json +23 -0
- sfi/pylibpack/rules/shiboken2.json +24 -0
- sfi/pyloadergen/pyloadergen.py +271 -572
- sfi/pypack/pypack.py +822 -471
- sfi/pyprojectparse/__init__.py +0 -0
- sfi/pyprojectparse/pyprojectparse.py +500 -0
- sfi/pysourcepack/pysourcepack.py +308 -369
- sfi/quizbase/__init__.py +0 -0
- sfi/quizbase/quizbase.py +828 -0
- sfi/quizbase/quizbase_gui.py +987 -0
- sfi/regexvalidate/__init__.py +0 -0
- sfi/regexvalidate/regex_help.html +284 -0
- sfi/regexvalidate/regexvalidate.py +468 -0
- sfi/taskkill/taskkill.py +0 -2
- pysfi-0.1.10.dist-info/RECORD +0 -39
- sfi/embedinstall/embedinstall.py +0 -478
- sfi/projectparse/projectparse.py +0 -152
- {pysfi-0.1.10.dist-info → pysfi-0.1.12.dist-info}/WHEEL +0 -0
- /sfi/{embedinstall → llmclient}/__init__.py +0 -0
- /sfi/{projectparse → llmquantize}/__init__.py +0 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import re
|
|
6
|
+
import sys
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import PySide2
|
|
11
|
+
from PySide2.QtCore import Qt, QTimer
|
|
12
|
+
from PySide2.QtGui import QFont
|
|
13
|
+
from PySide2.QtWidgets import (
|
|
14
|
+
QApplication,
|
|
15
|
+
QCheckBox,
|
|
16
|
+
QComboBox,
|
|
17
|
+
QDialog,
|
|
18
|
+
QGroupBox,
|
|
19
|
+
QHBoxLayout,
|
|
20
|
+
QLabel,
|
|
21
|
+
QLineEdit,
|
|
22
|
+
QMainWindow,
|
|
23
|
+
QPushButton,
|
|
24
|
+
QSplitter,
|
|
25
|
+
QTextBrowser,
|
|
26
|
+
QTextEdit,
|
|
27
|
+
QVBoxLayout,
|
|
28
|
+
QWidget,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
qt_dir = Path(PySide2.__file__).parent
|
|
32
|
+
plugin_path = str(qt_dir / "plugins" / "platforms")
|
|
33
|
+
os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = plugin_path
|
|
34
|
+
|
|
35
|
+
# History file path
|
|
36
|
+
HISTORY_FILE = Path.home() / ".pysfi" / "regexvalidate" / ".regex_validator_history.json"
|
|
37
|
+
HISTORY_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
38
|
+
MAX_HISTORY_ITEMS = 20
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class RegexValidatorGUI(QMainWindow):
|
|
42
|
+
def __init__(self) -> None:
|
|
43
|
+
super().__init__()
|
|
44
|
+
self.setWindowTitle("Regex Validator Tool")
|
|
45
|
+
self.setGeometry(100, 100, 800, 600)
|
|
46
|
+
|
|
47
|
+
# Load history
|
|
48
|
+
self.history = self.load_history()
|
|
49
|
+
self.history_items = [] # Current list of history display items
|
|
50
|
+
|
|
51
|
+
# Timer for delayed history update to avoid focus loss
|
|
52
|
+
self.history_timer = QTimer()
|
|
53
|
+
self.history_timer.setSingleShot(True)
|
|
54
|
+
self.history_timer.setInterval(1000) # Wait 1 second after typing stops
|
|
55
|
+
self.history_timer.timeout.connect(self.add_to_history)
|
|
56
|
+
|
|
57
|
+
# Central widget
|
|
58
|
+
central_widget = QWidget()
|
|
59
|
+
self.setCentralWidget(central_widget)
|
|
60
|
+
|
|
61
|
+
# Main layout
|
|
62
|
+
main_layout = QVBoxLayout(central_widget)
|
|
63
|
+
|
|
64
|
+
# Title and help button
|
|
65
|
+
title_layout = QHBoxLayout()
|
|
66
|
+
title_label = QLabel("Regex Validator Tool")
|
|
67
|
+
title_label.setAlignment(Qt.AlignCenter)
|
|
68
|
+
title_label.setStyleSheet("font-size: 18px; font-weight: bold; margin: 10px;")
|
|
69
|
+
title_layout.addWidget(title_label)
|
|
70
|
+
|
|
71
|
+
help_button = QPushButton("Help")
|
|
72
|
+
help_button.setMaximumWidth(80)
|
|
73
|
+
help_button.clicked.connect(self.show_help)
|
|
74
|
+
title_layout.addWidget(help_button)
|
|
75
|
+
main_layout.addLayout(title_layout)
|
|
76
|
+
|
|
77
|
+
# Create splitter for flexible layout
|
|
78
|
+
splitter = QSplitter(Qt.Vertical)
|
|
79
|
+
main_layout.addWidget(splitter)
|
|
80
|
+
|
|
81
|
+
# Top group: Input settings
|
|
82
|
+
top_group = QGroupBox("Input Settings")
|
|
83
|
+
top_layout = QVBoxLayout(top_group)
|
|
84
|
+
|
|
85
|
+
# Regular expression input
|
|
86
|
+
regex_layout = QHBoxLayout()
|
|
87
|
+
regex_label = QLabel("Regular Expression:")
|
|
88
|
+
self.regex_input = QLineEdit()
|
|
89
|
+
self.regex_input.setPlaceholderText("Enter your regular expression...")
|
|
90
|
+
regex_layout.addWidget(regex_label)
|
|
91
|
+
regex_layout.addWidget(self.regex_input)
|
|
92
|
+
top_layout.addLayout(regex_layout)
|
|
93
|
+
|
|
94
|
+
# History selector
|
|
95
|
+
history_layout = QHBoxLayout()
|
|
96
|
+
history_label = QLabel("History:")
|
|
97
|
+
self.history_combo = QComboBox()
|
|
98
|
+
self.history_combo.setMinimumWidth(400)
|
|
99
|
+
self.update_history_combo()
|
|
100
|
+
self.history_combo.currentIndexChanged.connect(self.on_history_selected)
|
|
101
|
+
history_layout.addWidget(history_label)
|
|
102
|
+
history_layout.addWidget(self.history_combo)
|
|
103
|
+
top_layout.addLayout(history_layout)
|
|
104
|
+
|
|
105
|
+
# Raw mode checkbox
|
|
106
|
+
self.raw_mode_checkbox = QCheckBox("Raw Mode (Disable Escape Sequence Processing)")
|
|
107
|
+
self.raw_mode_checkbox.setChecked(True)
|
|
108
|
+
top_layout.addWidget(self.raw_mode_checkbox)
|
|
109
|
+
|
|
110
|
+
# Test string input
|
|
111
|
+
test_string_label = QLabel("Test String:")
|
|
112
|
+
top_layout.addWidget(test_string_label)
|
|
113
|
+
|
|
114
|
+
self.test_string_input = QTextEdit()
|
|
115
|
+
self.test_string_input.setMaximumHeight(100)
|
|
116
|
+
self.test_string_input.setPlaceholderText("Enter the string to test against the regular expression...")
|
|
117
|
+
top_layout.addWidget(self.test_string_input)
|
|
118
|
+
|
|
119
|
+
splitter.addWidget(top_group)
|
|
120
|
+
|
|
121
|
+
# Bottom group: Results and options
|
|
122
|
+
bottom_group = QGroupBox("Results & Options")
|
|
123
|
+
bottom_layout = QVBoxLayout(bottom_group)
|
|
124
|
+
|
|
125
|
+
# Options
|
|
126
|
+
options_layout = QHBoxLayout()
|
|
127
|
+
|
|
128
|
+
self.case_insensitive_checkbox = QCheckBox("Case Insensitive (re.IGNORECASE)")
|
|
129
|
+
self.multiline_checkbox = QCheckBox("Multiline (re.MULTILINE)")
|
|
130
|
+
self.dotall_checkbox = QCheckBox("Dotall (re.DOTALL)")
|
|
131
|
+
|
|
132
|
+
options_layout.addWidget(self.case_insensitive_checkbox)
|
|
133
|
+
options_layout.addWidget(self.multiline_checkbox)
|
|
134
|
+
options_layout.addWidget(self.dotall_checkbox)
|
|
135
|
+
bottom_layout.addLayout(options_layout)
|
|
136
|
+
|
|
137
|
+
# Results label with status indicator
|
|
138
|
+
self.results_label = QLabel("Validation Results: ")
|
|
139
|
+
self.results_label.setStyleSheet("font-size: 14px; font-weight: bold;")
|
|
140
|
+
bottom_layout.addWidget(self.results_label)
|
|
141
|
+
|
|
142
|
+
self.results_output = QTextEdit()
|
|
143
|
+
self.results_output.setReadOnly(True)
|
|
144
|
+
bottom_layout.addWidget(self.results_output)
|
|
145
|
+
|
|
146
|
+
splitter.addWidget(bottom_group)
|
|
147
|
+
|
|
148
|
+
# Set initial sizes for splitter
|
|
149
|
+
splitter.setSizes([200, 400])
|
|
150
|
+
|
|
151
|
+
# Connect text changes to auto-validate function
|
|
152
|
+
self.regex_input.textChanged.connect(self.on_text_changed)
|
|
153
|
+
self.test_string_input.textChanged.connect(self.on_text_changed)
|
|
154
|
+
|
|
155
|
+
def on_text_changed(self) -> None:
|
|
156
|
+
"""Handle text changes and auto-validate."""
|
|
157
|
+
self.validate_regex()
|
|
158
|
+
# Restart the timer to delay history update
|
|
159
|
+
self.history_timer.stop()
|
|
160
|
+
self.history_timer.start()
|
|
161
|
+
|
|
162
|
+
def load_history(self) -> list:
|
|
163
|
+
"""Load history from file."""
|
|
164
|
+
if HISTORY_FILE.exists():
|
|
165
|
+
try:
|
|
166
|
+
with open(HISTORY_FILE, encoding="utf-8") as f:
|
|
167
|
+
return json.load(f)
|
|
168
|
+
except Exception as e:
|
|
169
|
+
print(f"Failed to load history: {e}")
|
|
170
|
+
return []
|
|
171
|
+
|
|
172
|
+
def save_history(self) -> None:
|
|
173
|
+
"""Save history to file."""
|
|
174
|
+
try:
|
|
175
|
+
with open(HISTORY_FILE, "w", encoding="utf-8") as f:
|
|
176
|
+
json.dump(self.history, f, indent=2, ensure_ascii=False)
|
|
177
|
+
except Exception as e:
|
|
178
|
+
print(f"Failed to save history: {e}")
|
|
179
|
+
|
|
180
|
+
def update_history_combo(self) -> None:
|
|
181
|
+
"""Update the history combo box with current history."""
|
|
182
|
+
# Store current selection
|
|
183
|
+
current_index = self.history_combo.currentIndex()
|
|
184
|
+
self.history_combo.itemData(current_index) if current_index > 0 else None
|
|
185
|
+
|
|
186
|
+
# Block signals to prevent triggering selection changes
|
|
187
|
+
self.history_combo.blockSignals(True)
|
|
188
|
+
|
|
189
|
+
self.history_combo.clear()
|
|
190
|
+
self.history_combo.addItem("-- Select History --")
|
|
191
|
+
|
|
192
|
+
# Add history items with display format
|
|
193
|
+
for i, item in enumerate(self.history):
|
|
194
|
+
display_text = f"{i + 1}. {item['pattern'][:50]}{'...' if len(item['pattern']) > 50 else ''}"
|
|
195
|
+
self.history_combo.addItem(display_text, i)
|
|
196
|
+
|
|
197
|
+
# Restore selection to first item (placeholder) to avoid focus stealing
|
|
198
|
+
self.history_combo.setCurrentIndex(0)
|
|
199
|
+
|
|
200
|
+
# Unblock signals
|
|
201
|
+
self.history_combo.blockSignals(False)
|
|
202
|
+
|
|
203
|
+
def on_history_selected(self, index: int) -> None:
|
|
204
|
+
"""Handle history item selection."""
|
|
205
|
+
if index <= 0: # First item is placeholder
|
|
206
|
+
return
|
|
207
|
+
|
|
208
|
+
data_index = self.history_combo.itemData(index)
|
|
209
|
+
if data_index is not None and 0 <= data_index < len(self.history):
|
|
210
|
+
item = self.history[data_index]
|
|
211
|
+
|
|
212
|
+
# Block signals to prevent auto-validation during restoration
|
|
213
|
+
self.regex_input.blockSignals(True)
|
|
214
|
+
self.test_string_input.blockSignals(True)
|
|
215
|
+
|
|
216
|
+
# Restore values
|
|
217
|
+
self.regex_input.setText(item["pattern"])
|
|
218
|
+
self.test_string_input.setPlainText(item["test_string"])
|
|
219
|
+
self.raw_mode_checkbox.setChecked(item.get("raw_mode", True))
|
|
220
|
+
self.case_insensitive_checkbox.setChecked(item.get("case_insensitive", False))
|
|
221
|
+
self.multiline_checkbox.setChecked(item.get("multiline", False))
|
|
222
|
+
self.dotall_checkbox.setChecked(item.get("dotall", False))
|
|
223
|
+
|
|
224
|
+
# Unblock signals and validate
|
|
225
|
+
self.regex_input.blockSignals(False)
|
|
226
|
+
self.test_string_input.blockSignals(False)
|
|
227
|
+
self.validate_regex()
|
|
228
|
+
|
|
229
|
+
def add_to_history(self) -> None:
|
|
230
|
+
"""Add current settings to history if they are different."""
|
|
231
|
+
current_pattern = self.regex_input.text()
|
|
232
|
+
current_test_string = self.test_string_input.toPlainText()
|
|
233
|
+
|
|
234
|
+
if not current_pattern:
|
|
235
|
+
return
|
|
236
|
+
|
|
237
|
+
# Create current item
|
|
238
|
+
current_item = {
|
|
239
|
+
"pattern": current_pattern,
|
|
240
|
+
"test_string": current_test_string,
|
|
241
|
+
"raw_mode": self.raw_mode_checkbox.isChecked(),
|
|
242
|
+
"case_insensitive": self.case_insensitive_checkbox.isChecked(),
|
|
243
|
+
"multiline": self.multiline_checkbox.isChecked(),
|
|
244
|
+
"dotall": self.dotall_checkbox.isChecked(),
|
|
245
|
+
"timestamp": str(datetime.now()) if "datetime" in globals() else None,
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
# Check if this item already exists in history
|
|
249
|
+
for item in self.history:
|
|
250
|
+
if (
|
|
251
|
+
item["pattern"] == current_pattern
|
|
252
|
+
and item["test_string"] == current_test_string
|
|
253
|
+
and item.get("raw_mode", True) == current_item["raw_mode"]
|
|
254
|
+
):
|
|
255
|
+
# Item already exists, move it to front
|
|
256
|
+
self.history.remove(item)
|
|
257
|
+
self.history.insert(0, current_item)
|
|
258
|
+
self.save_history()
|
|
259
|
+
return
|
|
260
|
+
|
|
261
|
+
# Add new item to front
|
|
262
|
+
self.history.insert(0, current_item)
|
|
263
|
+
|
|
264
|
+
# Limit history size
|
|
265
|
+
if len(self.history) > MAX_HISTORY_ITEMS:
|
|
266
|
+
self.history = self.history[:MAX_HISTORY_ITEMS]
|
|
267
|
+
|
|
268
|
+
self.save_history()
|
|
269
|
+
self.update_history_combo()
|
|
270
|
+
|
|
271
|
+
def validate_regex(self) -> None:
|
|
272
|
+
"""Validate the regex against the test string."""
|
|
273
|
+
regex_pattern = self.regex_input.text()
|
|
274
|
+
test_string = self.test_string_input.toPlainText()
|
|
275
|
+
|
|
276
|
+
if not regex_pattern:
|
|
277
|
+
self.results_output.setText("Error: Regular expression is empty.")
|
|
278
|
+
self.results_output.setStyleSheet("background-color: #ffcccc;")
|
|
279
|
+
self.results_label.setText("Validation Results: ✗")
|
|
280
|
+
self.results_label.setStyleSheet("font-size: 14px; font-weight: bold; color: red;")
|
|
281
|
+
return
|
|
282
|
+
|
|
283
|
+
if not test_string:
|
|
284
|
+
self.results_output.setText("Warning: Test string is empty, but regex is being tested anyway.")
|
|
285
|
+
self.results_output.setStyleSheet("background-color: #ffffcc;")
|
|
286
|
+
self.results_label.setText("Validation Results: ")
|
|
287
|
+
self.results_label.setStyleSheet("font-size: 14px; font-weight: bold; color: orange;")
|
|
288
|
+
|
|
289
|
+
# Build flags based on checkboxes
|
|
290
|
+
flags = 0
|
|
291
|
+
if self.case_insensitive_checkbox.isChecked():
|
|
292
|
+
flags |= re.IGNORECASE
|
|
293
|
+
if self.multiline_checkbox.isChecked():
|
|
294
|
+
flags |= re.MULTILINE
|
|
295
|
+
if self.dotall_checkbox.isChecked():
|
|
296
|
+
flags |= re.DOTALL
|
|
297
|
+
|
|
298
|
+
try:
|
|
299
|
+
# Handle raw mode
|
|
300
|
+
if self.raw_mode_checkbox.isChecked():
|
|
301
|
+
# In raw mode, treat the regex as-is without processing escape sequences
|
|
302
|
+
compiled_regex = re.compile(regex_pattern, flags)
|
|
303
|
+
else:
|
|
304
|
+
# In non-raw mode, process escape sequences in the pattern
|
|
305
|
+
compiled_regex = re.compile(regex_pattern, flags)
|
|
306
|
+
|
|
307
|
+
# Perform various regex operations
|
|
308
|
+
match_result = compiled_regex.search(test_string)
|
|
309
|
+
findall_result = compiled_regex.findall(test_string)
|
|
310
|
+
finditer_result = list(compiled_regex.finditer(test_string))
|
|
311
|
+
fullmatch_result = compiled_regex.fullmatch(test_string) if test_string else None
|
|
312
|
+
|
|
313
|
+
# Prepare results
|
|
314
|
+
results = []
|
|
315
|
+
results.append("=" * 50)
|
|
316
|
+
results.append("REGEX VALIDATION RESULTS")
|
|
317
|
+
results.append("=" * 50)
|
|
318
|
+
results.append(f"Pattern: {regex_pattern}")
|
|
319
|
+
results.append(f"Test String: {test_string!r}")
|
|
320
|
+
results.append(f"Raw Mode: {'Enabled' if self.raw_mode_checkbox.isChecked() else 'Disabled'}")
|
|
321
|
+
results.append(f"Flags: {flags}")
|
|
322
|
+
results.append("-" * 50)
|
|
323
|
+
|
|
324
|
+
# Match result
|
|
325
|
+
if match_result:
|
|
326
|
+
results.append("MATCH FOUND:")
|
|
327
|
+
results.append(f" Match: {match_result.group()!r}")
|
|
328
|
+
results.append(f" Span: {match_result.span()}")
|
|
329
|
+
results.append(f" Start: {match_result.start()}")
|
|
330
|
+
results.append(f" End: {match_result.end()}")
|
|
331
|
+
|
|
332
|
+
# Show groups if any
|
|
333
|
+
if match_result.groups():
|
|
334
|
+
results.append(f" Groups: {match_result.groups()}")
|
|
335
|
+
|
|
336
|
+
if match_result.groupdict():
|
|
337
|
+
results.append(f" Named Groups: {match_result.groupdict()}")
|
|
338
|
+
else:
|
|
339
|
+
results.append("NO MATCH FOUND")
|
|
340
|
+
|
|
341
|
+
# Full match result
|
|
342
|
+
results.append("\nFULL MATCH:")
|
|
343
|
+
if fullmatch_result:
|
|
344
|
+
results.append(f" Full Match: {fullmatch_result.group()!r}")
|
|
345
|
+
results.append(f" Full Match Groups: {fullmatch_result.groups()}")
|
|
346
|
+
else:
|
|
347
|
+
results.append(" No full match")
|
|
348
|
+
|
|
349
|
+
# Findall result
|
|
350
|
+
results.append(f"\nFINDALL RESULT ({len(findall_result)} items):")
|
|
351
|
+
if findall_result:
|
|
352
|
+
for i, item in enumerate(findall_result):
|
|
353
|
+
results.append(f" [{i}]: {item!r}")
|
|
354
|
+
else:
|
|
355
|
+
results.append(" No matches found")
|
|
356
|
+
|
|
357
|
+
# Finditer result
|
|
358
|
+
results.append(f"\nFINDITER RESULT ({len(finditer_result)} matches):")
|
|
359
|
+
if finditer_result:
|
|
360
|
+
for i, match in enumerate(finditer_result):
|
|
361
|
+
results.append(f" Match {i + 1}: {match.group()!r} at {match.span()}")
|
|
362
|
+
if match.groups():
|
|
363
|
+
results.append(f" Groups: {match.groups()}")
|
|
364
|
+
else:
|
|
365
|
+
results.append(" No matches found")
|
|
366
|
+
|
|
367
|
+
# Check for special regex features
|
|
368
|
+
results.append("\nREGEX ANALYSIS:")
|
|
369
|
+
if "(" in regex_pattern and ")" in regex_pattern:
|
|
370
|
+
results.append(" Contains capturing groups")
|
|
371
|
+
if "(?:" in regex_pattern:
|
|
372
|
+
results.append(" Contains non-capturing groups")
|
|
373
|
+
if "(?P<" in regex_pattern:
|
|
374
|
+
results.append(" Contains named groups")
|
|
375
|
+
if "?" in regex_pattern:
|
|
376
|
+
results.append(" Contains quantifier modifiers")
|
|
377
|
+
if "\\" in regex_pattern:
|
|
378
|
+
results.append(" Contains escape sequences")
|
|
379
|
+
|
|
380
|
+
self.results_output.setText("\n".join(results))
|
|
381
|
+
|
|
382
|
+
# Set background color based on match result
|
|
383
|
+
if match_result:
|
|
384
|
+
self.results_output.setStyleSheet("background-color: #ccffcc;")
|
|
385
|
+
self.results_label.setText("Validation Results: ✓")
|
|
386
|
+
self.results_label.setStyleSheet("font-size: 14px; font-weight: bold; color: green;")
|
|
387
|
+
else:
|
|
388
|
+
self.results_output.setStyleSheet("background-color: #ffcccc;")
|
|
389
|
+
self.results_label.setText("Validation Results: ✗")
|
|
390
|
+
self.results_label.setStyleSheet("font-size: 14px; font-weight: bold; color: red;")
|
|
391
|
+
|
|
392
|
+
except re.error as e:
|
|
393
|
+
error_msg = f"Regex Error: {e!s}"
|
|
394
|
+
self.results_output.setText(error_msg)
|
|
395
|
+
self.results_output.setStyleSheet("background-color: #ffcccc;")
|
|
396
|
+
self.results_label.setText("Validation Results: ✗")
|
|
397
|
+
self.results_label.setStyleSheet("font-size: 14px; font-weight: bold; color: red;")
|
|
398
|
+
except Exception as e:
|
|
399
|
+
error_msg = f"Unexpected Error: {e!s}"
|
|
400
|
+
self.results_output.setText(error_msg)
|
|
401
|
+
self.results_output.setStyleSheet("background-color: #ffcccc;")
|
|
402
|
+
self.results_label.setText("Validation Results: ✗")
|
|
403
|
+
self.results_label.setStyleSheet("font-size: 14px; font-weight: bold; color: red;")
|
|
404
|
+
|
|
405
|
+
def show_help(self) -> None:
|
|
406
|
+
"""Show regex help dialog."""
|
|
407
|
+
dialog = RegexHelpDialog(self)
|
|
408
|
+
dialog.exec_()
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
class RegexHelpDialog(QDialog):
|
|
412
|
+
"""Dialog showing regex syntax help from HTML file."""
|
|
413
|
+
|
|
414
|
+
def __init__(self, parent: QWidget | None = None) -> None:
|
|
415
|
+
super().__init__(parent)
|
|
416
|
+
self.setWindowTitle("Regex Syntax Help")
|
|
417
|
+
self.setMinimumSize(700, 500)
|
|
418
|
+
self.resize(750, 600)
|
|
419
|
+
|
|
420
|
+
layout = QVBoxLayout(self)
|
|
421
|
+
|
|
422
|
+
# Load HTML content from file
|
|
423
|
+
help_html_path = Path(__file__).parent / "regex_help.html"
|
|
424
|
+
|
|
425
|
+
if help_html_path.exists():
|
|
426
|
+
with open(help_html_path, encoding="utf-8") as f:
|
|
427
|
+
html_content = f.read()
|
|
428
|
+
else:
|
|
429
|
+
html_content = """
|
|
430
|
+
<html><body>
|
|
431
|
+
<h2>Help File Not Found</h2>
|
|
432
|
+
<p>Cannot find help file: <code>regex_help.html</code></p>
|
|
433
|
+
<p>Please ensure the file is located in the same directory as <code>regexvalidate.py</code>.</p>
|
|
434
|
+
</body></html>
|
|
435
|
+
"""
|
|
436
|
+
|
|
437
|
+
# Create text browser to display HTML
|
|
438
|
+
text_browser = QTextBrowser()
|
|
439
|
+
text_browser.setHtml(html_content)
|
|
440
|
+
text_browser.setOpenExternalLinks(False) # Prevent opening external links
|
|
441
|
+
|
|
442
|
+
layout.addWidget(text_browser)
|
|
443
|
+
|
|
444
|
+
# Close button
|
|
445
|
+
close_button = QPushButton("Close")
|
|
446
|
+
close_button.setMaximumWidth(100)
|
|
447
|
+
close_button.clicked.connect(self.accept)
|
|
448
|
+
button_layout = QHBoxLayout()
|
|
449
|
+
button_layout.addStretch()
|
|
450
|
+
button_layout.addWidget(close_button)
|
|
451
|
+
layout.addLayout(button_layout)
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
def main() -> None:
|
|
455
|
+
app = QApplication(sys.argv)
|
|
456
|
+
|
|
457
|
+
# Set application font
|
|
458
|
+
font = QFont("Arial", 9)
|
|
459
|
+
app.setFont(font)
|
|
460
|
+
|
|
461
|
+
window = RegexValidatorGUI()
|
|
462
|
+
window.show()
|
|
463
|
+
|
|
464
|
+
sys.exit(app.exec_())
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
if __name__ == "__main__":
|
|
468
|
+
main()
|
sfi/taskkill/taskkill.py
CHANGED
pysfi-0.1.10.dist-info/RECORD
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
sfi/__init__.py,sha256=8bMY8NhWD1vYgwgWs9iUPIBAypGLtUPLEYaDIUaFXN4,75
|
|
2
|
-
sfi/cli.py,sha256=bUUTOg18sJQbSKSfsVANhlMgSj9yzO2txIzFAd9B2Ok,296
|
|
3
|
-
sfi/alarmclock/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
sfi/alarmclock/alarmclock.py,sha256=65G8OyTGpe4oQ2SFerQG1N9PVJ4KxO7WzgsTxpGm4O0,12509
|
|
5
|
-
sfi/bumpversion/__init__.py,sha256=K9BMEwc9KPoYJnm_FPKjKRrRrq9lNbSqGe96zOOuG6Q,86
|
|
6
|
-
sfi/bumpversion/bumpversion.py,sha256=HOyHLaE0sZajrlcVZ8hsim8mPjz77qwQVSo6aIzjMXE,20735
|
|
7
|
-
sfi/docscan/__init__.py,sha256=PZio8kjN0cGQ0CF-YjS3NK7MHTL7yPA5YsnAYtCt1Z8,121
|
|
8
|
-
sfi/docscan/docscan.py,sha256=rk8mjEI2SKNIliV-Yb41pfUmYBQ1tUhk5LHUNEjkszI,41890
|
|
9
|
-
sfi/docscan/docscan_gui.py,sha256=2WzvxMf-rsAJnEYXTCfRhTvojZFNp46LKt_Xke67D_s,50657
|
|
10
|
-
sfi/docscan/lang/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
sfi/docscan/lang/eng.py,sha256=_43KW9WfX64dS3Rjg4fbtvavP9MBWhNEKeIt1HKYktU,8377
|
|
12
|
-
sfi/docscan/lang/zhcn.py,sha256=n4QGTv5SwgBqICNZHiTF1kmaDcQA6wG7gvRc0OWIfe4,8715
|
|
13
|
-
sfi/embedinstall/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
sfi/embedinstall/embedinstall.py,sha256=Go0nmi22KVYpZPuW_-ORoVE5oHgQNbMw7Fbn0AZ9D8s,17507
|
|
15
|
-
sfi/filedate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
-
sfi/filedate/filedate.py,sha256=DpVp26lumE_Lz_4TgqUEX8IxtK3Y6yHSEFV8qJyegyk,3645
|
|
17
|
-
sfi/makepython/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
-
sfi/makepython/makepython.py,sha256=nKuklEW3yIm0VIol0Ly9Cm9RCyqdY9Fs-i5obvbO0kI,11423
|
|
19
|
-
sfi/pdfsplit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
sfi/pdfsplit/pdfsplit.py,sha256=1fntwckU8yy4-_A4h5eOrODs6-Cl_wMzaIvHGmMzCco,6177
|
|
21
|
-
sfi/projectparse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
-
sfi/projectparse/projectparse.py,sha256=Ojg-z4lZEtjEBpJYWyznTgL307N45AxlQKnRkEH0P70,5525
|
|
23
|
-
sfi/pylibpack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
-
sfi/pylibpack/pylibpack.py,sha256=BDcgtGZ1S0u9a0rrHZ-ZJCvmNs8D0YxM2b5aONxPkXc,31398
|
|
25
|
-
sfi/pyloadergen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
-
sfi/pyloadergen/pyloadergen.py,sha256=-8-uLFQOie1wgUhV18CFcfRF2uNkxm8AZuJQHYGTzng,51386
|
|
27
|
-
sfi/pypack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
-
sfi/pypack/pypack.py,sha256=up1Z6thEPuvo-naNnDGSA3S7YZGYAruxyN3Z2agkr8Q,31137
|
|
29
|
-
sfi/pysourcepack/pysourcepack.py,sha256=VwrKqYeHm2YU6J-Fdhze1mDTVDM4Or7DsJQ4vWL23tw,11725
|
|
30
|
-
sfi/taskkill/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
-
sfi/taskkill/taskkill.py,sha256=6Aw4afmgfLZcQnvgG_38A1VrwazDrnNdOmY1l4kr0lc,7758
|
|
32
|
-
sfi/which/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
|
-
sfi/which/which.py,sha256=zVIAwZA-pGGngxkkwZ6IxDX3ozVHg7cLSYwYO9FjaIc,2439
|
|
34
|
-
sfi/workflowengine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
-
sfi/workflowengine/workflowengine.py,sha256=ck5PjyyjtWtbjN4ePEKsTWV6QR-BUlrfwrY6jih52jQ,17055
|
|
36
|
-
pysfi-0.1.10.dist-info/METADATA,sha256=bhtOFk62jPKXMqrVA3icmNKpI7U2hJjPkxLwBB4glQc,4031
|
|
37
|
-
pysfi-0.1.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
38
|
-
pysfi-0.1.10.dist-info/entry_points.txt,sha256=_QEugTtofmViUWxD_LtMc6gzX8VfOaLmd2Vco0LZam0,678
|
|
39
|
-
pysfi-0.1.10.dist-info/RECORD,,
|