Coverage for src/sparkle/CLI/help/nicknames.py: 87%

45 statements  

« prev     ^ index     » next       coverage.py v7.16.0, created at 2026-09-08 12:00 +0000

1"""Helper functions for CLI nicknames.""" 

2 

3from __future__ import annotations 

4from pathlib import Path 

5from typing import Callable 

6 

7from sparkle.instance import Instance_Set, InstanceSet, MultiFileInstanceSet 

8 

9 

10def resolve_object_name( 

11 name: str | Path, 

12 nickname_dict: dict = {}, 

13 target_dir: Path = Path(), 

14 class_name: Callable = None, 

15) -> Path | any: 

16 """Attempts to resolve a (nick) name. 

17 

18 Args: 

19 name: The (nick)name to resolve 

20 target_dir: The location where the file object should exist 

21 nickname_dict: Nicknames 

22 class_name: If passed, will attempt to return an object 

23 that is constructed from this Path. 

24 

25 Returns: 

26 Path to the object, None if unresolvable. 

27 """ 

28 path = None 

29 # We cannot handle None as a name 

30 if name is None: 

31 return None 

32 # First check if the name already is a path 

33 if isinstance(name, (str, Path)) and Path(name).exists(): 

34 path = Path(name) 

35 # Second check if its a nickname registered in Sparkle 

36 elif str(name) in nickname_dict: 

37 path = Path(nickname_dict[str(name)]) 

38 # Third check if we can create a valid path with the name 

39 elif isinstance(name, (str, Path)) and (target_dir / name).exists(): 

40 path = target_dir / name 

41 # Finally, attempt to construct the object from the Path 

42 try: 

43 if class_name is not None: 

44 if path is not None: 

45 return class_name(path) 

46 if name is not None: 

47 return class_name(name) 

48 except Exception: 

49 return None 

50 return path 

51 

52 

53def resolve_instance_name( 

54 instance_set: str, 

55 instance_name: str, 

56 search_location: str | Path | list[InstanceSet], 

57) -> str | Path | list[Path] | None: 

58 """Attempts to resolve an instance to its file path(s). 

59 

60 The inverse of resolve_instance_pair, which maps a path back to its (set, instance). 

61 

62 Args: 

63 instance_set: The name of the set the instance belongs to. Used to look in the 

64 correct set, so instances sharing a name across different sets are not 

65 confused with one another. 

66 instance_name: The name of the instance to resolve. 

67 search_location: Where to look for the instance. Either a str/Path to a 

68 directory containing instance sets, or the instance sets themselves as 

69 a list. 

70 

71 Returns: 

72 The Path of the instance, or None if it cannot be resolved. Multi-file instances 

73 are returned as a space-joined string of their paths, as they are passed on to 

74 a command line as a single argument. 

75 """ 

76 # Check if the name is already an instance file path 

77 name_path = Path(instance_name) 

78 if name_path.exists() and name_path.is_file(): 

79 return name_path 

80 # Attempt to find files 

81 matches = [path for path in name_path.parent.glob(name_path.name + ".*")] 

82 if matches: 

83 return " ".join(str(path) for path in matches) # Concat for multi file instance 

84 # Normalise search_location into a list of InstanceSet objects. A str/Path points to 

85 # a directory that contains instance set directories. 

86 if isinstance(search_location, (str, Path)): 

87 instance_sets = [ 

88 Instance_Set(instance_dir) 

89 for instance_dir in Path(search_location).iterdir() 

90 if instance_dir.is_dir() 

91 ] 

92 else: 

93 instance_sets = search_location 

94 # We know which set the instance belongs to so restrict the search to that set so a 

95 # shared instance name in another set cannot shadow it. Fall back to all sets if the 

96 # named set is not among those given. 

97 matching_sets = [ 

98 inst_set for inst_set in instance_sets if inst_set.name == instance_set 

99 ] 

100 search_sets = matching_sets if matching_sets else instance_sets 

101 

102 instance_path = None 

103 for current_set in search_sets: 

104 instance_path = current_set.get_path_by_name(instance_name) 

105 if instance_path is None: 

106 continue 

107 # Handle multi file instance 

108 if isinstance(current_set, MultiFileInstanceSet): 

109 instance_path = ( 

110 [instance_path] if not isinstance(instance_path, list) else instance_path 

111 ) 

112 instance_path = " ".join(str(path) for path in instance_path) 

113 break 

114 return instance_path