Coverage for /var/devmt/py/utils4_1.8.0/utils4/validation.py: 100%

41 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2025-08-26 21:39 +0100

1# -*- coding: utf-8 -*- 

2r""" 

3:Purpose: This module serves as a general validation processor. 

4 

5 .. note:: 

6 This is currently **very basic** module, and only contains 

7 validation rules which are commonly used by S3DEV projects. 

8 More functionality will be added as needed. 

9 

10:Developer: J Berendt 

11:Email: support@s3dev.uk 

12 

13:Comments: n/a 

14 

15:Example: 

16 

17 Test if an IP address is valid:: 

18 

19 >>> from utils4 import validation 

20 

21 >>> validation.rules.is_ip(value='128.31.0.62') 

22 True 

23 

24 

25 Test if a set of geo coordinates is valid:: 

26 

27 >>> from utils4 import validation 

28 

29 >>> validation.rules.is_coordinates(value=['4.6097100', '-74.0817500']) 

30 True 

31 

32 

33 Return the regex pattern for latitude:: 

34 

35 >>> from utils4 import validation 

36 

37 >>> validation.regex.latitude 

38 re.compile(r'^(-)?(([0-9]|[1-8][0-9])(\.[0-9]{1,})?|90)$', re.UNICODE) 

39 

40""" 

41 

42import re 

43import ipaddress 

44from typing import List 

45 

46 

47class RegEx: 

48 """This class holds a variety of validation regex strings. 

49 

50 Each property in this class returns a *compiled* regex pattern, of the 

51 type ``re.Pattern``. 

52 

53 """ 

54 

55 @property 

56 def latitude(self): 

57 """Regex string for latitude. 

58 

59 Returns: 

60 re.Pattern: A compiled regex pattern for latitude. 

61 

62 """ 

63 return re.compile(r'^(-)?(([0-9]|[1-8][0-9])(\.[0-9]{1,})?|90)$') 

64 

65 @property 

66 def longitude(self): 

67 """Regex string for longitude. 

68 

69 Returns: 

70 re.Pattern: A compiled regex pattern for longitude. 

71 

72 """ 

73 return r'^(-)?(([0-9]|[1-9][0-9]|1[0-7][0-9])(\.[0-9]{1,})?|180)$' 

74 

75 

76class Rules: 

77 """A collection of validation rules.""" 

78 

79 def __init__(self): 

80 """Class initialiser.""" 

81 self._re = RegEx() 

82 

83 def is_coordinates(self, value: List[str]) -> bool: 

84 """Test ``value`` is a valid set of geo coordinates. 

85 

86 Args: 

87 value (List[str]): A list containing latitude and longitude as 

88 strings. 

89 

90 :Rules: 

91 

92 - ``value`` is a ``list`` 

93 - The index 0 is a valid latitude coordinate (-90, 90) 

94 - The index 1 is a valid longitude coordinate (-180, 180) 

95 - For example:: 

96 

97 ['4.6097100', '-74.0817500'] 

98 

99 Returns: 

100 bool: True if ``value`` is a *valid* set of coordinates, otherwise 

101 False. 

102 

103 """ 

104 is_lat = False 

105 is_lon = False 

106 is_list = self.is_list(value, indexes=2) 

107 if is_list: 

108 is_lat = self.is_latitude(value=value[0]) 

109 is_lon = self.is_longitude(value=value[1]) 

110 return all([is_list, is_lat, is_lon]) 

111 

112 @staticmethod 

113 def is_ip(value: str) -> bool: 

114 """Test if an IP address (IPv4 or IPv6) is valid. 

115 

116 This function wraps the built-in :func:`ipaddress.ip_address` function 

117 to test whether an IP address is valid, or not. 

118 

119 Args: 

120 value (str): The IP address to be tested. 

121 

122 Returns: 

123 bool: True if ``value`` is a valid IPv4 or IPv6 address, otherwise 

124 False. 

125 

126 """ 

127 try: 

128 ipaddress.ip_address(address=value) 

129 return True 

130 except ValueError: 

131 return False 

132 

133 def is_latitude(self, value: str) -> bool: 

134 """Test ``value`` is a latitude coordinate (-90, 90). 

135 

136 Args: 

137 value (str): The latitude coordinate to be tested. 

138 

139 Returns: 

140 bool: True if ``value`` is a valid latitude coordinate, otherwise 

141 False. 

142 

143 """ 

144 return bool(re.match(self._re.latitude, value)) 

145 

146 @staticmethod 

147 def is_list(value: object, indexes: int=None) -> bool: 

148 """Validate if ``value`` is a ``list`` with (n) number of indexes. 

149 

150 Args: 

151 value (list): The object to be tested. 

152 indexes (int, optional): Number of expected indexes in the list. 

153 Defaults to None. 

154 

155 Returns: 

156 bool: True if ``value`` is a ``list`` with (n) indexes, otherwise 

157 False. 

158 

159 """ 

160 _idx = True 

161 _list = isinstance(value, list) 

162 if _list and indexes: 

163 _idx = len(value) == indexes 

164 return all([_list, _idx]) 

165 

166 def is_longitude(self, value: str) -> bool: 

167 """Test ``value`` is a longitude coordinate (-180, 180). 

168 

169 Args: 

170 value (str): The longitude coordinate to be tested. 

171 

172 Returns: 

173 bool: True if ``value`` is a valid longitude coordinate, otherwise 

174 False. 

175 

176 """ 

177 return bool(re.match(self._re.longitude, value)) 

178 

179 

180regex = RegEx() 

181rules = Rules()