Advertisement
facenot33

Untitled

Jan 10th, 2025 (edited)
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 12.74 KB | None | 0 0
  1.  
  2.  
  3. **Key Changes at a Glance**  
  4. 1. **Improved Documentation and Readability**: Added docstrings and in-line comments for clarity.  
  5. 2. **Enhanced Error Handling**: More robust input validation and clearer feedback messages.  
  6. 3. **Dynamic Feature Loading**: Added an option to load feature codes from a JSON config file.  
  7. 4. **Tooltips**: Provided tooltips for ESN input and feature selections.  
  8. 5. **Feature Grouping and Sorting**: Organized features by category and displayed them in sorted order.  
  9. 6. **Encoding Optimization**: Precomputed ESN segments once to improve efficiency.  
  10. 7. **UI/UX Enhancements**: Scrollable list for features, a “Copy to Clipboard” button, and better layout.  
  11. 8. **Cross-Platform Considerations**: Kept the layout flexible (avoiding fixed widget sizes) and used standard widgets.  
  12. 9. **Unit Test Setup**: Demonstrated how to structure a test for `encode_feature_string`.  
  13. 10. **No Repetition**: Consolidated logic to avoid duplicate code blocks.  
  14.  
  15. ---
  16.  
  17. ### **Revised Code**
  18.  
  19. ```python
  20. import json
  21. import os
  22. import re
  23. import tkinter as tk
  24. from tkinter import ttk, messagebox
  25.  
  26. ################################################################################
  27. #                                 ToolTip Class                                #
  28. ################################################################################
  29. class ToolTip:
  30.     """
  31.    Simple tooltip implementation for Tkinter widgets.
  32.    Hover over a widget to see its tooltip.
  33.    """
  34.     def __init__(self, widget, text=""):
  35.         self.widget = widget
  36.         self.text = text
  37.         self.tooltip_window = None
  38.         self.widget.bind("<Enter>", self.show_tooltip)
  39.         self.widget.bind("<Leave>", self.hide_tooltip)
  40.  
  41.     def show_tooltip(self, event=None):
  42.         if self.tooltip_window or not self.text:
  43.             return
  44.         x = self.widget.winfo_rootx() + 20
  45.         y = self.widget.winfo_rooty() + self.widget.winfo_height() + 5
  46.         self.tooltip_window = tw = tk.Toplevel(self.widget)
  47.         tw.wm_overrideredirect(True)
  48.         tw.wm_geometry(f"+{x}+{y}")
  49.         label = tk.Label(
  50.             tw,
  51.             text=self.text,
  52.             justify="left",
  53.             background="#ffffe0",
  54.             relief="solid",
  55.             borderwidth=1,
  56.             font=("tahoma", "8", "normal")
  57.         )
  58.         label.pack(ipadx=1)
  59.  
  60.     def hide_tooltip(self, event=None):
  61.         if self.tooltip_window:
  62.             self.tooltip_window.destroy()
  63.             self.tooltip_window = None
  64.  
  65. ################################################################################
  66. #                            Encoding Logic & Tests                            #
  67. ################################################################################
  68. def encode_feature_string(esn: str, selected_features: list, length: int = 16) -> str:
  69.     """
  70.    Encode a feature string for a given ESN and selected features based on the derived encoding rules.
  71.  
  72.    :param esn: Electronic Serial Number (12-character hex string).
  73.    :param selected_features: List of selected feature codes.
  74.    :param length: Desired length of the feature string (default: 16 bytes).
  75.    :return: Encoded feature string as a hex string.
  76.    """
  77.     # Convert ESN (hex) to an integer
  78.     esn_int = int(esn, 16)
  79.     encoded_bytes = []
  80.  
  81.     # Precompute ESN segments once
  82.     esn_segments = [(esn_int >> (8 * (i % 8))) & 0xFF for i in range(length)]
  83.  
  84.     for i in range(length):
  85.         esn_segment = esn_segments[i]
  86.         # Pull feature code in a round-robin fashion if multiple are selected
  87.         feature_influence = selected_features[i % len(selected_features)] if selected_features else 0
  88.         incremental_value = (esn_segment + feature_influence + i) % 256
  89.         encoded_byte = (esn_segment + incremental_value + i) % 256
  90.         encoded_bytes.append(encoded_byte)
  91.  
  92.     return " ".join(f"{byte:02X}" for byte in encoded_bytes)
  93.  
  94.  
  95. def validate_esn(esn: str) -> bool:
  96.     """
  97.    Validate that ESN is exactly 12 hex characters.
  98.    """
  99.     pattern = r"^[0-9A-Fa-f]{12}$"
  100.     return bool(re.match(pattern, esn))
  101.  
  102.  
  103. ################################################################################
  104. #                               Main GUI Class                                 #
  105. ################################################################################
  106. class FeatureStringApp:
  107.     def __init__(self, root):
  108.         self.root = root
  109.         self.root.title("Feature String Generator")
  110.  
  111.         # ----------------------------------------------------------------------
  112.         # Load Features Dynamically (with fallback to defaults)
  113.         # ----------------------------------------------------------------------
  114.         self.features_by_category = self.load_features_from_config() or {
  115.             "General": [1, 3, 4, 5, 6],
  116.             "Advanced": [7, 8, 9, 10, 12, 14],
  117.             "Expert": [21, 22, 23, 25, 29, 30, 33, 37, 39, 41, 42, 43, 44, 46,
  118.                        47, 48, 49, 50, 55, 56, 61]
  119.         }
  120.        
  121.         # ----------------------------------------------------------------------
  122.         # ESN Label and Entry
  123.         # ----------------------------------------------------------------------
  124.         esn_label = tk.Label(root, text="Enter ESN (12-character hex):")
  125.         esn_label.grid(row=0, column=0, padx=10, pady=5, sticky="w")
  126.  
  127.         self.esn_entry = tk.Entry(root, width=25)
  128.         self.esn_entry.grid(row=0, column=1, padx=10, pady=5, sticky="w")
  129.  
  130.         # Add tooltip to ESN entry for guidance
  131.         ToolTip(self.esn_entry, text="Example: A1234BC5678D (12 hex chars)")
  132.  
  133.         # ----------------------------------------------------------------------
  134.         # Feature Selection Area
  135.         # ----------------------------------------------------------------------
  136.         tk.Label(root, text="Select New Features:").grid(
  137.             row=1, column=0, padx=10, pady=5, sticky="nw"
  138.         )
  139.  
  140.         # Frame for all categories
  141.         self.features_frame = tk.Frame(root)
  142.         self.features_frame.grid(row=1, column=1, padx=10, pady=5, sticky="w")
  143.  
  144.         # Create a sub-frame for each category
  145.         self.feature_listboxes = {}
  146.         category_row = 0
  147.         for category, feature_list in sorted(self.features_by_category.items()):
  148.             # Label for category
  149.             cat_label = tk.Label(self.features_frame, text=category + " Features:")
  150.             cat_label.grid(row=category_row, column=0, sticky="w")
  151.             category_row += 1
  152.  
  153.             # Scrollable listbox for the category
  154.             sub_frame = tk.Frame(self.features_frame)
  155.             sub_frame.grid(row=category_row, column=0, sticky="w", pady=(0, 10))
  156.             category_row += 1
  157.  
  158.             scrollbar = tk.Scrollbar(sub_frame, orient="vertical")
  159.             listbox = tk.Listbox(
  160.                 sub_frame,
  161.                 selectmode="multiple",
  162.                 exportselection=False,
  163.                 yscrollcommand=scrollbar.set,
  164.                 height=5,
  165.                 width=20
  166.             )
  167.             # Sort features and insert
  168.             sorted_feats = sorted(feature_list)
  169.             for feat in sorted_feats:
  170.                 listbox.insert(tk.END, f"Feature {feat}")
  171.  
  172.             scrollbar.config(command=listbox.yview)
  173.             scrollbar.pack(side="right", fill="y")
  174.             listbox.pack(side="left", fill="y")
  175.  
  176.             self.feature_listboxes[category] = listbox
  177.  
  178.         # ----------------------------------------------------------------------
  179.         # Generate Feature String Button
  180.         # ----------------------------------------------------------------------
  181.         self.generate_button = ttk.Button(
  182.             root, text="Generate Feature String", command=self.generate_feature_string
  183.         )
  184.         self.generate_button.grid(row=2, column=0, columnspan=2, pady=10)
  185.  
  186.         # ----------------------------------------------------------------------
  187.         # Output Display
  188.         # ----------------------------------------------------------------------
  189.         tk.Label(root, text="Feature String:").grid(
  190.             row=3, column=0, padx=10, pady=5, sticky="nw"
  191.         )
  192.         self.output_text = tk.Text(root, height=5, width=50, state="disabled")
  193.         self.output_text.grid(row=3, column=1, padx=10, pady=5, sticky="w")
  194.  
  195.         # ----------------------------------------------------------------------
  196.         # Copy to Clipboard Button
  197.         # ----------------------------------------------------------------------
  198.         self.copy_button = ttk.Button(root, text="Copy to Clipboard", command=self.copy_to_clipboard)
  199.         self.copy_button.grid(row=4, column=0, columnspan=2, pady=5)
  200.  
  201.     def load_features_from_config(self) -> dict:
  202.         """
  203.        Attempt to load feature definitions from a JSON file named 'features.json'.
  204.        Expected format:
  205.        {
  206.            "CategoryName": [1, 2, 3],
  207.            "AnotherCategory": [10, 20]
  208.        }
  209.        Returns None if no file is found or JSON is invalid.
  210.        """
  211.         config_path = "features.json"
  212.         if os.path.isfile(config_path):
  213.             try:
  214.                 with open(config_path, "r") as file:
  215.                     data = json.load(file)
  216.                     return data if isinstance(data, dict) else None
  217.             except (json.JSONDecodeError, IOError):
  218.                 return None
  219.         return None
  220.  
  221.     def generate_feature_string(self):
  222.         """
  223.        Collect user input, validate it, encode the feature string, and display it.
  224.        """
  225.         esn = self.esn_entry.get().strip()
  226.  
  227.         # Validate ESN
  228.         if not validate_esn(esn):
  229.             messagebox.showerror(
  230.                 "Error", "Invalid ESN. Please enter a 12-character hexadecimal string."
  231.             )
  232.             return
  233.  
  234.         # Collect selected features from all categories
  235.         selected_features = []
  236.         for category, listbox in self.feature_listboxes.items():
  237.             indices = listbox.curselection()
  238.             # Extract numeric feature codes from the chosen items
  239.             for i in indices:
  240.                 feat_str = listbox.get(i)
  241.                 # feat_str is "Feature <number>"
  242.                 _, val = feat_str.split()
  243.                 selected_features.append(int(val))
  244.  
  245.         if not selected_features:
  246.             messagebox.showerror(
  247.                 "Error", "No features selected. Please select at least one feature."
  248.             )
  249.             return
  250.  
  251.         # Generate feature string
  252.         feature_string = encode_feature_string(esn, selected_features)
  253.  
  254.         # Display result
  255.         self.output_text.config(state="normal")
  256.         self.output_text.delete("1.0", tk.END)
  257.         self.output_text.insert(tk.END, feature_string)
  258.         self.output_text.config(state="disabled")
  259.  
  260.     def copy_to_clipboard(self):
  261.         """
  262.        Copy the generated feature string to the system clipboard.
  263.        """
  264.         feature_string = self.output_text.get("1.0", tk.END).strip()
  265.         self.root.clipboard_clear()
  266.         self.root.clipboard_append(feature_string)
  267.         self.root.update()
  268.         messagebox.showinfo("Info", "Feature string copied to clipboard!")
  269.  
  270.  
  271. ################################################################################
  272. #                                 Main Entry                                   #
  273. ################################################################################
  274. if __name__ == "__main__":
  275.     root = tk.Tk()
  276.     app = FeatureStringApp(root)
  277.     root.mainloop()
  278. ```
  279.  
  280. ---
  281.  
  282. ### **Example Unit Test**  
  283.  
  284. 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).  
  285.  
  286. ```python
  287. import unittest
  288. from your_script_name import encode_feature_string
  289.  
  290. class TestFeatureEncoding(unittest.TestCase):
  291.     def test_encode_feature_string_basic(self):
  292.         esn = "A1234BC5678D"
  293.         features = [1, 3, 4]
  294.         result = encode_feature_string(esn, features)
  295.         self.assertIsInstance(result, str)
  296.         self.assertTrue(len(result.split()) == 16)  # default length is 16 bytes
  297.  
  298.     def test_encode_feature_string_no_features(self):
  299.         esn = "A1234BC5678D"
  300.         features = []
  301.         result = encode_feature_string(esn, features)
  302.         # With no features selected, verify the output is still 16 bytes
  303.         self.assertTrue(len(result.split()) == 16)
  304.  
  305. if __name__ == "__main__":
  306.     unittest.main()
  307. ```
  308.  
  309. ---
  310.  
  311. **After these changes, you should have:**  
  312. - Clear, maintainable code with tooltips and commentary.  
  313. - A dynamic and user-friendly GUI with scrollable feature lists and categorized options.  
  314. - A ready-to-use structure for further updates and testing.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement