From e10c3700fe249fcbc3ca19483043a7b060b1006a Mon Sep 17 00:00:00 2001 From: s-weibe Date: Thu, 23 Oct 2025 10:57:01 -0700 Subject: [PATCH] Enhance Interactives class for CLI and file search Refactor Interactives class to improve CLI interaction and file searching. --- tests/sherlock_interactives.py | 96 +++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 26 deletions(-) diff --git a/tests/sherlock_interactives.py b/tests/sherlock_interactives.py index c28b9dc06..d4ea65fee 100644 --- a/tests/sherlock_interactives.py +++ b/tests/sherlock_interactives.py @@ -1,38 +1,82 @@ -import os +import subprocess import platform import re -import subprocess +from pathlib import Path + class Interactives: - def run_cli(args:str = "") -> str: - """Pass arguments to Sherlock as a normal user on the command line""" - # Adapt for platform differences (Windows likes to be special) - if platform.system() == "Windows": - command:str = f"py -m sherlock_project {args}" - else: - command:str = f"sherlock {args}" - - proc_out:str = "" + """ + A helper class to interact with the Sherlock CLI and perform + file pattern searches within the sherlock_project directory. + """ + + @staticmethod + def run_cli(args: str = "") -> str: + """ + Run the Sherlock CLI with given arguments. + + Args: + args (str): Command-line arguments for Sherlock. + + Returns: + str: Output from the Sherlock command. + + Raises: + InteractivesSubprocessError: If the subprocess returns a non-zero exit code. + """ + command = "py -m sherlock_project" if platform.system() == "Windows" else "sherlock" + full_command = f"{command} {args}".strip() + try: - proc_out = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT) - return proc_out.decode() + result = subprocess.check_output(full_command, shell=True, stderr=subprocess.STDOUT) + return result.decode() except subprocess.CalledProcessError as e: - raise InteractivesSubprocessError(e.output.decode()) - + raise InteractivesSubprocessError( + f"Command failed:\n{full_command}\n\nError Output:\n{e.output.decode()}" + ) + @staticmethod def walk_sherlock_for_files_with(pattern: str) -> list[str]: - """Check all files within the Sherlock package for matching patterns""" - pattern:re.Pattern = re.compile(pattern) - matching_files:list[str] = [] - for root, dirs, files in os.walk("sherlock_project"): - for file in files: - file_path = os.path.join(root,file) - if "__pycache__" in file_path: - continue - with open(file_path, 'r', errors='ignore') as f: - if pattern.search(f.read()): - matching_files.append(file_path) + """ + Recursively search for files containing a regex pattern in the sherlock_project directory. + + Args: + pattern (str): Regular expression pattern to search for. + + Returns: + list[str]: List of file paths containing the pattern. + """ + compiled_pattern = re.compile(pattern) + base_path = Path("sherlock_project") + matching_files = [] + + for file_path in base_path.rglob("*"): + if file_path.is_file() and "__pycache__" not in str(file_path): + try: + text = file_path.read_text(encoding="utf-8", errors="ignore") + if compiled_pattern.search(text): + matching_files.append(str(file_path)) + except Exception as e: + print(f"Skipping file {file_path}: {e}") + return matching_files + class InteractivesSubprocessError(Exception): + """Custom exception for subprocess errors.""" pass + + +if __name__ == "__main__": + # Example usage for testing before making a pull request + print("Running example CLI command...") + try: + print(Interactives.run_cli("--help")) + except InteractivesSubprocessError as e: + print(e) + + print("\nSearching for pattern 'def ' in project files...") + matches = Interactives.walk_sherlock_for_files_with(r"def ") + print(f"Found {len(matches)} files containing 'def':") + for match in matches: + print(f" - {match}")