Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/traitlets/utils/descriptions.py: 22%

67 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-01 06:54 +0000

1import inspect 

2import re 

3import types 

4 

5 

6def describe(article, value, name=None, verbose=False, capital=False): 

7 """Return string that describes a value 

8 

9 Parameters 

10 ---------- 

11 article : str or None 

12 A definite or indefinite article. If the article is 

13 indefinite (i.e. "a" or "an") the appropriate one 

14 will be infered. Thus, the arguments of ``describe`` 

15 can themselves represent what the resulting string 

16 will actually look like. If None, then no article 

17 will be prepended to the result. For non-articled 

18 description, values that are instances are treated 

19 definitely, while classes are handled indefinitely. 

20 value : any 

21 The value which will be named. 

22 name : str or None (default: None) 

23 Only applies when ``article`` is "the" - this 

24 ``name`` is a definite reference to the value. 

25 By default one will be infered from the value's 

26 type and repr methods. 

27 verbose : bool (default: False) 

28 Whether the name should be concise or verbose. When 

29 possible, verbose names include the module, and/or 

30 class name where an object was defined. 

31 capital : bool (default: False) 

32 Whether the first letter of the article should 

33 be capitalized or not. By default it is not. 

34 

35 Examples 

36 -------- 

37 Indefinite description: 

38 

39 >>> describe("a", object()) 

40 'an object' 

41 >>> describe("a", object) 

42 'an object' 

43 >>> describe("a", type(object)) 

44 'a type' 

45 

46 Definite description: 

47 

48 >>> describe("the", object()) 

49 "the object at '...'" 

50 >>> describe("the", object) 

51 'the object object' 

52 >>> describe("the", type(object)) 

53 'the type type' 

54 

55 Definitely named description: 

56 

57 >>> describe("the", object(), "I made") 

58 'the object I made' 

59 >>> describe("the", object, "I will use") 

60 'the object I will use' 

61 """ 

62 if isinstance(article, str): 

63 article = article.lower() 

64 

65 if not inspect.isclass(value): 

66 typename = type(value).__name__ 

67 else: 

68 typename = value.__name__ 

69 if verbose: 

70 typename = _prefix(value) + typename 

71 

72 if article == "the" or (article is None and not inspect.isclass(value)): 

73 if name is not None: 

74 result = f"{typename} {name}" 

75 if article is not None: 

76 return add_article(result, True, capital) 

77 else: 

78 return result 

79 else: 

80 tick_wrap = False 

81 if inspect.isclass(value): 

82 name = value.__name__ 

83 elif isinstance(value, types.FunctionType): 

84 name = value.__name__ 

85 tick_wrap = True 

86 elif isinstance(value, types.MethodType): 

87 name = value.__func__.__name__ 

88 tick_wrap = True 

89 elif type(value).__repr__ in ( 

90 object.__repr__, 

91 type.__repr__, 

92 ): # type:ignore[comparison-overlap] 

93 name = "at '%s'" % hex(id(value)) 

94 verbose = False 

95 else: 

96 name = repr(value) 

97 verbose = False 

98 if verbose: 

99 name = _prefix(value) + name 

100 if tick_wrap: 

101 name = name.join("''") 

102 return describe(article, value, name=name, verbose=verbose, capital=capital) 

103 elif article in ("a", "an") or article is None: 

104 if article is None: 

105 return typename 

106 return add_article(typename, False, capital) 

107 else: 

108 raise ValueError( 

109 "The 'article' argument should be 'the', 'a', 'an', or None not %r" % article 

110 ) 

111 

112 

113def _prefix(value): 

114 if isinstance(value, types.MethodType): 

115 name = describe(None, value.__self__, verbose=True) + "." 

116 else: 

117 module = inspect.getmodule(value) 

118 if module is not None and module.__name__ != "builtins": 

119 name = module.__name__ + "." 

120 else: 

121 name = "" 

122 return name 

123 

124 

125def class_of(value): 

126 """Returns a string of the value's type with an indefinite article. 

127 

128 For example 'an Image' or 'a PlotValue'. 

129 """ 

130 if inspect.isclass(value): 

131 return add_article(value.__name__) 

132 else: 

133 return class_of(type(value)) 

134 

135 

136def add_article(name, definite=False, capital=False): 

137 """Returns the string with a prepended article. 

138 

139 The input does not need to begin with a charater. 

140 

141 Parameters 

142 ---------- 

143 name : str 

144 Name to which to prepend an article 

145 definite : bool (default: False) 

146 Whether the article is definite or not. 

147 Indefinite articles being 'a' and 'an', 

148 while 'the' is definite. 

149 capital : bool (default: False) 

150 Whether the added article should have 

151 its first letter capitalized or not. 

152 """ 

153 if definite: 

154 result = "the " + name 

155 else: 

156 first_letters = re.compile(r"[\W_]+").sub("", name) 

157 if first_letters[:1].lower() in "aeiou": 

158 result = "an " + name 

159 else: 

160 result = "a " + name 

161 if capital: 

162 return result[0].upper() + result[1:] 

163 else: 

164 return result 

165 

166 

167def repr_type(obj): 

168 """Return a string representation of a value and its type for readable 

169 

170 error messages. 

171 """ 

172 the_type = type(obj) 

173 msg = f"{obj!r} {the_type!r}" 

174 return msg