Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- **Key Changes at a Glance**
- 1. **Improved Documentation and Readability**: Added docstrings and in-line comments for clarity.
- 2. **Enhanced Error Handling**: More robust input validation and clearer feedback messages.
- 3. **Dynamic Feature Loading**: Added an option to load feature codes from a JSON config file.
- 4. **Tooltips**: Provided tooltips for ESN input and feature selections.
- 5. **Feature Grouping and Sorting**: Organized features by category and displayed them in sorted order.
- 6. **Encoding Optimization**: Precomputed ESN segments once to improve efficiency.
- 7. **UI/UX Enhancements**: Scrollable list for features, a “Copy to Clipboard” button, and better layout.
- 8. **Cross-Platform Considerations**: Kept the layout flexible (avoiding fixed widget sizes) and used standard widgets.
- 9. **Unit Test Setup**: Demonstrated how to structure a test for `encode_feature_string`.
- 10. **No Repetition**: Consolidated logic to avoid duplicate code blocks.
- ---
- ### **Revised Code**
- ```python
- import json
- import os
- import re
- import tkinter as tk
- from tkinter import ttk, messagebox
- ################################################################################
- # ToolTip Class #
- ################################################################################
- class ToolTip:
- """
- Simple tooltip implementation for Tkinter widgets.
- Hover over a widget to see its tooltip.
- """
- def __init__(self, widget, text=""):
- self.widget = widget
- self.text = text
- self.tooltip_window = None
- self.widget.bind("<Enter>", self.show_tooltip)
- self.widget.bind("<Leave>", self.hide_tooltip)
- def show_tooltip(self, event=None):
- if self.tooltip_window or not self.text:
- return
- x = self.widget.winfo_rootx() + 20
- y = self.widget.winfo_rooty() + self.widget.winfo_height() + 5
- self.tooltip_window = tw = tk.Toplevel(self.widget)
- tw.wm_overrideredirect(True)
- tw.wm_geometry(f"+{x}+{y}")
- label = tk.Label(
- tw,
- text=self.text,
- justify="left",
- background="#ffffe0",
- relief="solid",
- borderwidth=1,
- font=("tahoma", "8", "normal")
- )
- label.pack(ipadx=1)
- def hide_tooltip(self, event=None):
- if self.tooltip_window:
- self.tooltip_window.destroy()
- self.tooltip_window = None
- ################################################################################
- # Encoding Logic & Tests #
- ################################################################################
- def encode_feature_string(esn: str, selected_features: list, length: int = 16) -> str:
- """
- Encode a feature string for a given ESN and selected features based on the derived encoding rules.
- :param esn: Electronic Serial Number (12-character hex string).
- :param selected_features: List of selected feature codes.
- :param length: Desired length of the feature string (default: 16 bytes).
- :return: Encoded feature string as a hex string.
- """
- # Convert ESN (hex) to an integer
- esn_int = int(esn, 16)
- encoded_bytes = []
- # Precompute ESN segments once
- esn_segments = [(esn_int >> (8 * (i % 8))) & 0xFF for i in range(length)]
- for i in range(length):
- esn_segment = esn_segments[i]
- # Pull feature code in a round-robin fashion if multiple are selected
- feature_influence = selected_features[i % len(selected_features)] if selected_features else 0
- incremental_value = (esn_segment + feature_influence + i) % 256
- encoded_byte = (esn_segment + incremental_value + i) % 256
- encoded_bytes.append(encoded_byte)
- return " ".join(f"{byte:02X}" for byte in encoded_bytes)
- def validate_esn(esn: str) -> bool:
- """
- Validate that ESN is exactly 12 hex characters.
- """
- pattern = r"^[0-9A-Fa-f]{12}$"
- return bool(re.match(pattern, esn))
- ################################################################################
- # Main GUI Class #
- ################################################################################
- class FeatureStringApp:
- def __init__(self, root):
- self.root = root
- self.root.title("Feature String Generator")
- # ----------------------------------------------------------------------
- # Load Features Dynamically (with fallback to defaults)
- # ----------------------------------------------------------------------
- self.features_by_category = self.load_features_from_config() or {
- "General": [1, 3, 4, 5, 6],
- "Advanced": [7, 8, 9, 10, 12, 14],
- "Expert": [21, 22, 23, 25, 29, 30, 33, 37, 39, 41, 42, 43, 44, 46,
- 47, 48, 49, 50, 55, 56, 61]
- }
- # ----------------------------------------------------------------------
- # ESN Label and Entry
- # ----------------------------------------------------------------------
- esn_label = tk.Label(root, text="Enter ESN (12-character hex):")
- esn_label.grid(row=0, column=0, padx=10, pady=5, sticky="w")
- self.esn_entry = tk.Entry(root, width=25)
- self.esn_entry.grid(row=0, column=1, padx=10, pady=5, sticky="w")
- # Add tooltip to ESN entry for guidance
- ToolTip(self.esn_entry, text="Example: A1234BC5678D (12 hex chars)")
- # ----------------------------------------------------------------------
- # Feature Selection Area
- # ----------------------------------------------------------------------
- tk.Label(root, text="Select New Features:").grid(
- row=1, column=0, padx=10, pady=5, sticky="nw"
- )
- # Frame for all categories
- self.features_frame = tk.Frame(root)
- self.features_frame.grid(row=1, column=1, padx=10, pady=5, sticky="w")
- # Create a sub-frame for each category
- self.feature_listboxes = {}
- category_row = 0
- for category, feature_list in sorted(self.features_by_category.items()):
- # Label for category
- cat_label = tk.Label(self.features_frame, text=category + " Features:")
- cat_label.grid(row=category_row, column=0, sticky="w")
- category_row += 1
- # Scrollable listbox for the category
- sub_frame = tk.Frame(self.features_frame)
- sub_frame.grid(row=category_row, column=0, sticky="w", pady=(0, 10))
- category_row += 1
- scrollbar = tk.Scrollbar(sub_frame, orient="vertical")
- listbox = tk.Listbox(
- sub_frame,
- selectmode="multiple",
- exportselection=False,
- yscrollcommand=scrollbar.set,
- height=5,
- width=20
- )
- # Sort features and insert
- sorted_feats = sorted(feature_list)
- for feat in sorted_feats:
- listbox.insert(tk.END, f"Feature {feat}")
- scrollbar.config(command=listbox.yview)
- scrollbar.pack(side="right", fill="y")
- listbox.pack(side="left", fill="y")
- self.feature_listboxes[category] = listbox
- # ----------------------------------------------------------------------
- # Generate Feature String Button
- # ----------------------------------------------------------------------
- self.generate_button = ttk.Button(
- root, text="Generate Feature String", command=self.generate_feature_string
- )
- self.generate_button.grid(row=2, column=0, columnspan=2, pady=10)
- # ----------------------------------------------------------------------
- # Output Display
- # ----------------------------------------------------------------------
- tk.Label(root, text="Feature String:").grid(
- row=3, column=0, padx=10, pady=5, sticky="nw"
- )
- self.output_text = tk.Text(root, height=5, width=50, state="disabled")
- self.output_text.grid(row=3, column=1, padx=10, pady=5, sticky="w")
- # ----------------------------------------------------------------------
- # Copy to Clipboard Button
- # ----------------------------------------------------------------------
- self.copy_button = ttk.Button(root, text="Copy to Clipboard", command=self.copy_to_clipboard)
- self.copy_button.grid(row=4, column=0, columnspan=2, pady=5)
- def load_features_from_config(self) -> dict:
- """
- Attempt to load feature definitions from a JSON file named 'features.json'.
- Expected format:
- {
- "CategoryName": [1, 2, 3],
- "AnotherCategory": [10, 20]
- }
- Returns None if no file is found or JSON is invalid.
- """
- config_path = "features.json"
- if os.path.isfile(config_path):
- try:
- with open(config_path, "r") as file:
- data = json.load(file)
- return data if isinstance(data, dict) else None
- except (json.JSONDecodeError, IOError):
- return None
- return None
- def generate_feature_string(self):
- """
- Collect user input, validate it, encode the feature string, and display it.
- """
- esn = self.esn_entry.get().strip()
- # Validate ESN
- if not validate_esn(esn):
- messagebox.showerror(
- "Error", "Invalid ESN. Please enter a 12-character hexadecimal string."
- )
- return
- # Collect selected features from all categories
- selected_features = []
- for category, listbox in self.feature_listboxes.items():
- indices = listbox.curselection()
- # Extract numeric feature codes from the chosen items
- for i in indices:
- feat_str = listbox.get(i)
- # feat_str is "Feature <number>"
- _, val = feat_str.split()
- selected_features.append(int(val))
- if not selected_features:
- messagebox.showerror(
- "Error", "No features selected. Please select at least one feature."
- )
- return
- # Generate feature string
- feature_string = encode_feature_string(esn, selected_features)
- # Display result
- self.output_text.config(state="normal")
- self.output_text.delete("1.0", tk.END)
- self.output_text.insert(tk.END, feature_string)
- self.output_text.config(state="disabled")
- def copy_to_clipboard(self):
- """
- Copy the generated feature string to the system clipboard.
- """
- feature_string = self.output_text.get("1.0", tk.END).strip()
- self.root.clipboard_clear()
- self.root.clipboard_append(feature_string)
- self.root.update()
- messagebox.showinfo("Info", "Feature string copied to clipboard!")
- ################################################################################
- # Main Entry #
- ################################################################################
- if __name__ == "__main__":
- root = tk.Tk()
- app = FeatureStringApp(root)
- root.mainloop()
- ```
- ---
- ### **Example Unit Test**
- Below is a minimal example showing how you might structure a unit test for `encode_feature_string`. It can be placed in a separate file (e.g., `test_feature_encoding.py` in a `tests/` directory).
- ```python
- import unittest
- from your_script_name import encode_feature_string
- class TestFeatureEncoding(unittest.TestCase):
- def test_encode_feature_string_basic(self):
- esn = "A1234BC5678D"
- features = [1, 3, 4]
- result = encode_feature_string(esn, features)
- self.assertIsInstance(result, str)
- self.assertTrue(len(result.split()) == 16) # default length is 16 bytes
- def test_encode_feature_string_no_features(self):
- esn = "A1234BC5678D"
- features = []
- result = encode_feature_string(esn, features)
- # With no features selected, verify the output is still 16 bytes
- self.assertTrue(len(result.split()) == 16)
- if __name__ == "__main__":
- unittest.main()
- ```
- ---
- **After these changes, you should have:**
- - Clear, maintainable code with tooltips and commentary.
- - A dynamic and user-friendly GUI with scrollable feature lists and categorized options.
- - A ready-to-use structure for further updates and testing.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement