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

68 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

1from __future__ import annotations 

2 

3import inspect 

4import re 

5import types 

6from typing import Any 

7 

8 

9def describe( 

10 article: str | None, 

11 value: Any, 

12 name: str | None = None, 

13 verbose: bool = False, 

14 capital: bool = False, 

15) -> str: 

16 """Return string that describes a value 

17 

18 Parameters 

19 ---------- 

20 article : str or None 

21 A definite or indefinite article. If the article is 

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

23 will be inferred. Thus, the arguments of ``describe`` 

24 can themselves represent what the resulting string 

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

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

27 description, values that are instances are treated 

28 definitely, while classes are handled indefinitely. 

29 value : any 

30 The value which will be named. 

31 name : str or None (default: None) 

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

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

34 By default one will be inferred from the value's 

35 type and repr methods. 

36 verbose : bool (default: False) 

37 Whether the name should be concise or verbose. When 

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

39 class name where an object was defined. 

40 capital : bool (default: False) 

41 Whether the first letter of the article should 

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

43 

44 Examples 

45 -------- 

46 Indefinite description: 

47 

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

49 'an object' 

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

51 'an object' 

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

53 'a type' 

54 

55 Definite description: 

56 

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

58 "the object at '...'" 

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

60 'the object object' 

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

62 'the type type' 

63 

64 Definitely named description: 

65 

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

67 'the object I made' 

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

69 'the object I will use' 

70 """ 

71 if isinstance(article, str): 

72 article = article.lower() 

73 

74 if not inspect.isclass(value): 

75 typename = type(value).__name__ 

76 else: 

77 typename = value.__name__ 

78 if verbose: 

79 typename = _prefix(value) + typename 

80 

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

82 if name is not None: 

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

84 if article is not None: 

85 return add_article(result, True, capital) 

86 else: 

87 return result 

88 else: 

89 tick_wrap = False 

90 if inspect.isclass(value): 

91 name = value.__name__ 

92 elif isinstance(value, types.FunctionType): 

93 name = value.__name__ 

94 tick_wrap = True 

95 elif isinstance(value, types.MethodType): 

96 name = value.__func__.__name__ 

97 tick_wrap = True 

98 elif type(value).__repr__ in ( 

99 object.__repr__, 

100 type.__repr__, 

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

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

103 verbose = False 

104 else: 

105 name = repr(value) 

106 verbose = False 

107 if verbose: 

108 name = _prefix(value) + name 

109 if tick_wrap: 

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

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

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

113 if article is None: 

114 return typename 

115 return add_article(typename, False, capital) 

116 else: 

117 raise ValueError( 

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

119 ) 

120 

121 

122def _prefix(value: Any) -> str: 

123 if isinstance(value, types.MethodType): 

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

125 else: 

126 module = inspect.getmodule(value) 

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

128 name = module.__name__ + "." 

129 else: 

130 name = "" 

131 return name 

132 

133 

134def class_of(value: Any) -> Any: 

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

136 

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

138 """ 

139 if inspect.isclass(value): 

140 return add_article(value.__name__) 

141 else: 

142 return class_of(type(value)) 

143 

144 

145def add_article(name: str, definite: bool = False, capital: bool = False) -> str: 

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

147 

148 The input does not need to begin with a character. 

149 

150 Parameters 

151 ---------- 

152 name : str 

153 Name to which to prepend an article 

154 definite : bool (default: False) 

155 Whether the article is definite or not. 

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

157 while 'the' is definite. 

158 capital : bool (default: False) 

159 Whether the added article should have 

160 its first letter capitalized or not. 

161 """ 

162 if definite: 

163 result = "the " + name 

164 else: 

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

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

167 result = "an " + name 

168 else: 

169 result = "a " + name 

170 if capital: 

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

172 else: 

173 return result 

174 

175 

176def repr_type(obj: Any) -> str: 

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

178 

179 error messages. 

180 """ 

181 the_type = type(obj) 

182 return f"{obj!r} {the_type!r}"