Coverage for /home/runner/work/viur-core/viur-core/viur/src/viur/core/utils/__init__.py: 15%

97 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-02-07 19:28 +0000

1import logging 

2import typing as t 

3import warnings 

4import datetime 

5from collections.abc import Iterable 

6from . import string, parse, json # noqa: used by external imports 

7from viur.core import current, db 

8from viur.core.config import conf 

9 

10 

11def utcNow() -> datetime.datetime: 

12 """ 

13 Returns an actual timestamp with UTC timezone setting. 

14 """ 

15 return datetime.datetime.now(datetime.timezone.utc) 

16 

17 

18def seoUrlToEntry(module: str, 

19 entry: t.Optional["SkeletonInstance"] = None, 

20 skelType: t.Optional[str] = None, 

21 language: t.Optional[str] = None) -> str: 

22 """ 

23 Return the seo-url to a skeleton instance or the module. 

24 

25 :param module: The module name. 

26 :param entry: A skeleton instance or None, to get the path to the module. 

27 :param skelType: # FIXME: Not used 

28 :param language: For which language. 

29 If None, the language of the current request is used. 

30 :return: The path (with a leading /). 

31 """ 

32 from viur.core import conf 

33 pathComponents = [""] 

34 if language is None: 

35 language = current.language.get() 

36 if conf.i18n.language_method == "url": 

37 pathComponents.append(language) 

38 if module in conf.i18n.language_module_map and language in conf.i18n.language_module_map[module]: 

39 module = conf.i18n.language_module_map[module][language] 

40 pathComponents.append(module) 

41 if not entry: 

42 return "/".join(pathComponents) 

43 else: 

44 try: 

45 currentSeoKeys = entry["viurCurrentSeoKeys"] 

46 except: 

47 return "/".join(pathComponents) 

48 if language in (currentSeoKeys or {}): 

49 pathComponents.append(str(currentSeoKeys[language])) 

50 elif "key" in entry: 

51 key = entry["key"] 

52 if isinstance(key, str): 

53 try: 

54 key = db.Key.from_legacy_urlsafe(key) 

55 except: 

56 pass 

57 pathComponents.append(str(key.id_or_name) if isinstance(key, db.Key) else str(key)) 

58 elif "name" in dir(entry): 

59 pathComponents.append(str(entry.name)) 

60 return "/".join(pathComponents) 

61 

62 

63def seoUrlToFunction(module: str, function: str, render: t.Optional[str] = None) -> str: 

64 from viur.core import conf 

65 lang = current.language.get() 

66 if module in conf.i18n.language_module_map and lang in conf.i18n.language_module_map[module]: 

67 module = conf.i18n.language_module_map[module][lang] 

68 if conf.i18n.language_method == "url": 

69 pathComponents = ["", lang] 

70 else: 

71 pathComponents = [""] 

72 targetObject = conf.main_resolver 

73 if module in targetObject: 

74 pathComponents.append(module) 

75 targetObject = targetObject[module] 

76 if render and render in targetObject: 

77 pathComponents.append(render) 

78 targetObject = targetObject[render] 

79 if function in targetObject: 

80 func = targetObject[function] 

81 if func.seo_language_map and lang in func.seo_language_map: 

82 pathComponents.append(func.seo_language_map[lang]) 

83 else: 

84 pathComponents.append(function) 

85 return "/".join(pathComponents) 

86 

87 

88def normalizeKey(key: t.Union[None, 'db.KeyClass']) -> t.Union[None, 'db.KeyClass']: 

89 """ 

90 Normalizes a datastore key (replacing _application with the current one) 

91 

92 :param key: Key to be normalized. 

93 

94 :return: Normalized key in string representation. 

95 """ 

96 if key is None: 

97 return None 

98 if key.parent: 

99 parent = normalizeKey(key.parent) 

100 else: 

101 parent = None 

102 return db.Key(key.kind, key.id_or_name, parent=parent) 

103 

104 

105def ensure_iterable( 

106 obj: t.Any, 

107 *, 

108 test: t.Optional[t.Callable[[t.Any], bool]] = None, 

109 allow_callable: bool = True, 

110) -> t.Iterable[t.Any]: 

111 """ 

112 Ensures an object to be iterable. 

113 

114 An additional test can be provided to check additionally. 

115 

116 If the object is not considered to be iterable, a tuple with the object is returned. 

117 """ 

118 if allow_callable and callable(obj): 

119 obj = obj() 

120 

121 if isinstance(obj, Iterable): # uses collections.abc.Iterable 

122 if test is None or test(obj): 

123 return obj # return the obj, which is an iterable 

124 

125 return () # empty tuple 

126 

127 elif obj is None: 

128 return () # empty tuple 

129 

130 return obj, # return a tuple with the obj 

131 

132 

133# DEPRECATED ATTRIBUTES HANDLING 

134__UTILS_CONF_REPLACEMENT = { 

135 "projectID": "viur.instance.project_id", 

136 "isLocalDevelopmentServer": "viur.instance.is_dev_server", 

137 "projectBasePath": "viur.instance.project_base_path", 

138 "coreBasePath": "viur.instance.core_base_path" 

139} 

140 

141__UTILS_NAME_REPLACEMENT = { 

142 "currentLanguage": ("current.language", current.language), 

143 "currentRequest": ("current.request", current.request), 

144 "currentRequestData": ("current.request_data", current.request_data), 

145 "currentSession": ("current.session", current.session), 

146 "downloadUrlFor": ("modules.file.File.create_download_url", "viur.core.modules.file.File.create_download_url"), 

147 "escapeString": ("utils.string.escape", string.escape), 

148 "generateRandomString": ("utils.string.random", string.random), 

149 "getCurrentUser": ("current.user.get", current.user.get), 

150 "is_prefix": ("utils.string.is_prefix", string.is_prefix), 

151 "parse_bool": ("utils.parse.bool", parse.bool), 

152 "srcSetFor": ("modules.file.File.create_src_set", "viur.core.modules.file.File.create_src_set"), 

153} 

154 

155 

156def __getattr__(attr): 

157 if replace := __UTILS_CONF_REPLACEMENT.get(attr): 157 ↛ 158line 157 didn't jump to line 158 because the condition on line 157 was never true

158 msg = f"Use of `utils.{attr}` is deprecated; Use `conf.{replace}` instead!" 

159 warnings.warn(msg, DeprecationWarning, stacklevel=3) 

160 logging.warning(msg, stacklevel=3) 

161 return conf[replace] 

162 

163 if replace := __UTILS_NAME_REPLACEMENT.get(attr): 163 ↛ 164line 163 didn't jump to line 164 because the condition on line 163 was never true

164 msg = f"Use of `utils.{attr}` is deprecated; Use `{replace[0]}` instead!" 

165 warnings.warn(msg, DeprecationWarning, stacklevel=3) 

166 logging.warning(msg, stacklevel=3) 

167 

168 ret = replace[1] 

169 

170 # When this is a string, try to resolve by dynamic import 

171 if isinstance(ret, str): 

172 mod, item, attr = ret.rsplit(".", 2) 

173 mod = __import__(mod, fromlist=(item,)) 

174 item = getattr(mod, item) 

175 ret = getattr(item, attr) 

176 

177 return ret 

178 

179 return super(__import__(__name__).__class__).__getattribute__(attr)