Coverage for src/sparkle/CLI/_cli_.py: 84%

55 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-10-15 14:11 +0000

1#!/usr/bin/env python3 

2"""Sparkle CLI entry point.""" 

3 

4import sys 

5import os 

6from pathlib import Path 

7 

8module_path = Path(__file__).parent.resolve() 

9 

10package_cli_entry_points = [ 

11 module_path.parent / "solver" / "solver_cli.py", 

12 module_path.parent / "selector" / "selector_cli.py", 

13 module_path.parent / "selector" / "extractor_cli.py", 

14 module_path.parent / "configurator" / "configurator_cli.py", 

15] 

16 

17 

18def commands() -> list[str]: 

19 """Get list of available commands.""" 

20 module_path = Path(__file__).parent.resolve() 

21 self_name = Path(__file__).name 

22 return [ 

23 path.stem 

24 for path in module_path.iterdir() 

25 if path.is_file() 

26 and path.suffix == ".py" 

27 and path.name != self_name 

28 and path.name != "__init__.py" 

29 ] 

30 

31 

32def main() -> None: 

33 """Pass through command to launch CLI commands.""" 

34 max_space = max( 

35 [path.name.count("_") for path in module_path.iterdir() if path.is_file()] 

36 ) 

37 if len(sys.argv) < 2: 

38 print("Usage: sparkle <command>") 

39 sys.exit(1) 

40 if " ".join(sys.argv[1:]) == "install autocomplete": 

41 import urllib.request 

42 

43 print(sys.prefix) 

44 if sys.prefix == sys.base_prefix: 

45 print( 

46 "Sparkle is not installed in a virtual environment! " 

47 "Autocomplete must be installed manually, see the documentation." 

48 ) 

49 sys.exit(-1) 

50 # TODO: Update this URL to link to the file on main 

51 code_inject = ( 

52 urllib.request.urlopen( 

53 "https://raw.githubusercontent.com/ADA-research/Sparkle/refs/heads/development/Resources/Other/venv_autocomplete.sh" 

54 ) 

55 .read() 

56 .decode() 

57 ) 

58 venv_profile_path = Path(sys.prefix) / "bin" / "activate" 

59 if venv_profile_path.is_file(): 

60 if code_inject in venv_profile_path.read_text(): 

61 print( 

62 f"[{Path(sys.prefix).name}] Sparkle autocomplete is already installed in the virtual environment! Exit." 

63 ) 

64 sys.exit(-1) 

65 with venv_profile_path.open("a") as f: 

66 f.write(code_inject) 

67 print( 

68 f"[{Path(sys.prefix).name}] Sparkle autocomplete has been installed in the virtual environment!" 

69 ) 

70 sys.exit(0) 

71 print( 

72 "Virtual environment not found! Manual installation in activation script required, see the documentation." 

73 ) 

74 sys.exit(-1) 

75 # Support spaces instead of _ 

76 possible_commands = commands() 

77 command, command_file = "", Path() 

78 for i in range(1, min(max_space, len(sys.argv))): 

79 if "--" in sys.argv[i]: # Parameter is never part of the command 

80 break 

81 command = "_".join(sys.argv[1 : i + 1]) 

82 args = sys.argv[i + 1 :] 

83 command_file = module_path / f"{command}.py" 

84 if command in possible_commands: 

85 break 

86 

87 if command_file.is_file(): 

88 os.system(f"python3 {command_file} {' '.join(args)}") 

89 sys.exit(0) 

90 else: 

91 print(f"Sparkle does not understand command <{command}>", end="") 

92 from difflib import SequenceMatcher 

93 

94 similarities = [ 

95 SequenceMatcher(None, command, alt).ratio() for alt in possible_commands 

96 ] 

97 

98 if max(similarities) > 0.6: 

99 alternative = possible_commands[similarities.index(max(similarities))] 

100 print(f". Did you mean <{alternative}>?") 

101 sys.exit(-2) 

102 

103 sys.exit(-1) 

104 

105 

106if __name__ == "__main__": 

107 main()