Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/phonenumbers/util.py: 38%

95 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1"""Python 2.x/3.x compatibility utilities. 

2 

3This module defines a collection of functions that allow the same Python 

4source code to be used in both Python 2.x and Python 3.x. 

5 

6 - prnt() prints its arguments to a file, with given separator and ending. 

7 - to_long() creates a (long) integer object from its input parameter. 

8 - u() allows string literals involving non-ASCII characters to be 

9 used in both Python 2.x / 3.x, e.g. u("\u0101 is a-with-macron") 

10 - unicod() forces its argument to a Unicode string. 

11 - rpr() generates a representation of a string that can be parsed in either 

12 Python 2.x or 3.x, assuming use of the u() function above. 

13 

14>>> from .util import prnt, u, rpr 

15>>> prnt("hello") 

16hello 

17>>> prnt("hello", "world") 

18hello world 

19>>> prnt("hello", "world", sep=":") 

20hello:world 

21>>> prnt("hello", "world", sep=":", end='!\\n') 

22hello:world! 

23>>> u('\u0101') == u('\U00000101') 

24True 

25>>> u('\u0101') == u('\N{LATIN SMALL LETTER A WITH MACRON}') 

26True 

27>>> a_macron = u('\u0101') 

28>>> rpr(a_macron) 

29"u('\\\\u0101')" 

30>>> rpr(u('abc')) == "'abc'" # In Python 2, LHS is Unicode but RHS is string 

31True 

32>>> rpr("'") 

33"'\\\\''" 

34""" 

35import sys 

36 

37 

38if sys.version_info >= (3, 0): # pragma no cover 38 ↛ 58line 38 didn't jump to line 58, because the condition on line 38 was never false

39 import builtins 

40 print3 = builtins.__dict__['print'] 

41 

42 unicod = str 

43 u = str 

44 to_long = int 

45 

46 def prnt(*args, **kwargs): 

47 sep = kwargs.get('sep', ' ') 

48 end = kwargs.get('end', '\n') 

49 file = kwargs.get('file', None) 

50 print3(*args, **{'sep': sep, 'end': end, 'file': file}) 

51 

52 class UnicodeMixin(object): 

53 """Mixin class to define a __str__ method in terms of __unicode__ method""" 

54 def __str__(self): 

55 return self.__unicode__() 

56 

57else: # pragma no cover 

58 unicod = unicode 

59 

60 import unicodedata 

61 import re 

62 # \N{name} = character named name in the Unicode database 

63 _UNAME_RE = re.compile(r'\\N\{(?P<name>[^}]+)\}') 

64 # \uxxxx = character with 16-bit hex value xxxx 

65 _U16_RE = re.compile(r'\\u(?P<hexval>[0-9a-fA-F]{4})') 

66 # \Uxxxxxxxx = character with 32-bit hex value xxxxxxxx 

67 _U32_RE = re.compile(r'\\U(?P<hexval>[0-9a-fA-F]{8})') 

68 

69 def u(s): 

70 """Generate Unicode string from a string input, encoding Unicode characters. 

71 

72 This is expected to work in the same way as u'<string>' would work in Python 

73 2.x (although it is not completely robust as it is based on a simple set of 

74 regexps). 

75 """ 

76 us = re.sub(_U16_RE, lambda m: unichr(int(m.group('hexval'), 16)), unicode(s)) 

77 us = re.sub(_U32_RE, lambda m: unichr(int(m.group('hexval'), 16)), us) 

78 us = re.sub(_UNAME_RE, lambda m: unicodedata.lookup(m.group('name')), us) 

79 return us 

80 

81 to_long = long 

82 

83 def prnt(*args, **kwargs): 

84 sep = kwargs.get('sep', ' ') 

85 end = kwargs.get('end', '\n') 

86 file = kwargs.get('file', None) 

87 if file is None: 

88 file = sys.stdout 

89 print >> file, sep.join([str(arg) for arg in args]) + end, 

90 

91 class UnicodeMixin(object): # pragma no cover 

92 """Mixin class to define a __str__ method in terms of __unicode__ method""" 

93 def __str__(self): 

94 return unicode(self).encode('utf-8') 

95 

96# Constants for Unicode strings 

97U_EMPTY_STRING = unicod("") 

98U_SPACE = unicod(" ") 

99U_DASH = unicod("-") 

100U_TILDE = unicod("~") 

101U_PLUS = unicod("+") 

102U_STAR = unicod("*") 

103U_ZERO = unicod("0") 

104U_SLASH = unicod("/") 

105U_SEMICOLON = unicod(";") 

106U_X_LOWER = unicod("x") 

107U_X_UPPER = unicod("X") 

108U_PERCENT = unicod("%") 

109 

110 

111def rpr(s): 

112 """Create a representation of a Unicode string that can be used in both 

113 Python 2 and Python 3k, allowing for use of the u() function""" 

114 if s is None: 

115 return 'None' 

116 seen_unicode = False 

117 results = [] 

118 for cc in s: 

119 ccn = ord(cc) 

120 if ccn >= 32 and ccn < 127: 

121 if cc == "'": # escape single quote 

122 results.append('\\') 

123 results.append(cc) 

124 elif cc == "\\": # escape backslash 

125 results.append('\\') 

126 results.append(cc) 

127 else: 

128 results.append(cc) 

129 else: 

130 seen_unicode = True 

131 if ccn <= 0xFFFF: 

132 results.append('\\u') 

133 results.append("%04x" % ccn) 

134 else: # pragma no cover 

135 results.append('\\U') 

136 results.append("%08x" % ccn) 

137 result = "'" + "".join(results) + "'" 

138 if seen_unicode: 

139 return "u(" + result + ")" 

140 else: 

141 return result 

142 

143 

144def force_unicode(s): 

145 """Force the argument to be a Unicode string, preserving None""" 

146 if s is None: 

147 return None 

148 else: 

149 return unicod(s) 

150 

151 

152class ImmutableMixin(object): 

153 """Mixin class to make objects of subclasses immutable""" 

154 _mutable = False 

155 

156 def __setattr__(self, name, value): 

157 if self._mutable or name == "_mutable": 157 ↛ 160line 157 didn't jump to line 160, because the condition on line 157 was never false

158 object.__setattr__(self, name, value) 

159 else: 

160 raise TypeError("Can't modify immutable instance") 

161 

162 def __delattr__(self, name): 

163 if self._mutable: 

164 object.__delattr__(self, name) 

165 else: 

166 raise TypeError("Can't modify immutable instance") 

167 

168 

169def mutating_method(func): 

170 """Decorator for methods that are allowed to modify immutable objects""" 

171 def wrapper(self, *__args, **__kwargs): 

172 old_mutable = self._mutable 

173 self._mutable = True 

174 try: 

175 # Call the wrapped function 

176 return func(self, *__args, **__kwargs) 

177 finally: 

178 self._mutable = old_mutable 

179 return wrapper 

180 

181 

182if __name__ == '__main__': # pragma no cover 182 ↛ 183line 182 didn't jump to line 183, because the condition on line 182 was never true

183 import doctest 

184 doctest.testmod()