Coverage for src/types/paths.py: 100.00%

61 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-10-18 15:02 +0000

1#!/usr/bin/env python3 

2 

3# Standard libraries 

4from glob import glob 

5from os.path import expanduser 

6from pathlib import Path, PurePosixPath 

7from typing import List 

8 

9# Components 

10from ..system.platform import Platform 

11from .environment import Environment 

12 

13# Paths class 

14class Paths: 

15 

16 # Basename 

17 @staticmethod 

18 def basename(data: str) -> str: 

19 

20 # POSIX path 

21 path: PurePosixPath = PurePosixPath(data) 

22 

23 # Result 

24 return str(path.name) 

25 

26 # Expand 

27 @staticmethod 

28 def expand( 

29 path: str, 

30 env: bool = True, 

31 home: bool = True, 

32 ) -> str: 

33 

34 # Expand environment 

35 if env: 

36 path = Environment.expand(path) 

37 

38 # Expand home 

39 if home: 

40 path = expanduser(path) 

41 

42 # Result 

43 return path 

44 

45 # Get 

46 @staticmethod 

47 def get(data: Path | PurePosixPath | str) -> str: 

48 

49 # POSIX path 

50 path: PurePosixPath = PurePosixPath(data) 

51 

52 # Result 

53 return str(path) 

54 

55 # Home 

56 @staticmethod 

57 def home(user: str) -> str: 

58 

59 # Expand home 

60 path: str = expanduser(f'~{user}') 

61 if path[0:1] != '~': 

62 return path 

63 

64 # Default root 

65 if user == 'root': # pragma: no cover 

66 return '/root' 

67 

68 # Default user 

69 return f'/home/{user}' 

70 

71 # Resolve 

72 @staticmethod 

73 def resolve(data: Path | str) -> str: 

74 

75 # Resolve path 

76 path: str = str(Path(data).resolve()) 

77 

78 # Result 

79 return path 

80 

81 # Translate 

82 @staticmethod 

83 def translate(data: str) -> str: 

84 

85 # Double backslash translation 

86 if data[0:1] == '\\': # pragma: no cover 

87 data = f'/{data[1:]}' 

88 

89 # Double slash translation 

90 if data[0:2] == '//': # pragma: no cover 

91 data = data[1:] 

92 

93 # Result 

94 return data 

95 

96 # Wildcard 

97 @staticmethod 

98 def wildcard( 

99 path: str, 

100 strict: bool = False, 

101 ) -> List[Path]: 

102 

103 # Variables 

104 paths: List[Path] = [] 

105 variants: List[str] = [] 

106 

107 # Apply strict wildcards 

108 if strict: 

109 path = path.replace('**', '*/**') 

110 

111 # Generate wildcard variants 

112 def wildcard_variants(path: str) -> List[str]: 

113 variants: List[str] = [path] 

114 if path.startswith('*'): # pragma: no cover 

115 variants += ['.' + path] 

116 index = path.find(Platform.PATH_SEPARATOR + '*') 

117 while index != -1: 

118 variants_new = [] 

119 for variant in variants: 

120 new_variant = variant[:index + 1] + '.' + variant[index + 1:] 

121 variants_new.append(new_variant) 

122 for variant_new in variants_new: 

123 if variant_new not in variants: 

124 variants += [variant_new] 

125 index = variants[0].find(Platform.PATH_SEPARATOR + '*', index + 1) 

126 return variants 

127 

128 # Evaluate wildcard variants 

129 variants = wildcard_variants(path) 

130 

131 # Evaluate wildcards 

132 for variant in variants: 

133 for item in [Path(item) for item in glob( 

134 variant, 

135 recursive=True, 

136 )]: 

137 paths += [Path(item)] 

138 

139 # Fallback to input 

140 if not paths: 

141 paths += [Path(path)] 

142 

143 # Result 

144 return paths