Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/google/cloud/bigquery/_versions_helpers.py: 56%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

95 statements  

1# Copyright 2023 Google LLC 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14 

15"""Shared helper functions for verifying versions of installed modules.""" 

16 

17import sys 

18from typing import Any 

19 

20import packaging.version 

21 

22from google.cloud.bigquery import exceptions 

23 

24 

25_MIN_PYARROW_VERSION = packaging.version.Version("3.0.0") 

26_MIN_BQ_STORAGE_VERSION = packaging.version.Version("2.0.0") 

27_BQ_STORAGE_OPTIONAL_READ_SESSION_VERSION = packaging.version.Version("2.6.0") 

28_MIN_PANDAS_VERSION = packaging.version.Version("1.1.0") 

29 

30_MIN_PANDAS_VERSION_RANGE = packaging.version.Version("1.5.0") 

31_MIN_PYARROW_VERSION_RANGE = packaging.version.Version("10.0.1") 

32 

33 

34class PyarrowVersions: 

35 """Version comparisons for pyarrow package.""" 

36 

37 def __init__(self): 

38 self._installed_version = None 

39 

40 @property 

41 def installed_version(self) -> packaging.version.Version: 

42 """Return the parsed version of pyarrow.""" 

43 if self._installed_version is None: 

44 import pyarrow # type: ignore 

45 

46 self._installed_version = packaging.version.parse( 

47 # Use 0.0.0, since it is earlier than any released version. 

48 # Legacy versions also have the same property, but 

49 # creating a LegacyVersion has been deprecated. 

50 # https://github.com/pypa/packaging/issues/321 

51 getattr(pyarrow, "__version__", "0.0.0") 

52 ) 

53 

54 return self._installed_version 

55 

56 @property 

57 def use_compliant_nested_type(self) -> bool: 

58 return self.installed_version.major >= 4 

59 

60 def try_import(self, raise_if_error: bool = False) -> Any: 

61 """Verifies that a recent enough version of pyarrow extra is installed. 

62 

63 The function assumes that pyarrow extra is installed, and should thus 

64 be used in places where this assumption holds. 

65 

66 Because `pip` can install an outdated version of this extra despite 

67 the constraints in `setup.py`, the calling code can use this helper 

68 to verify the version compatibility at runtime. 

69 

70 Returns: 

71 The ``pyarrow`` module or ``None``. 

72 

73 Raises: 

74 exceptions.LegacyPyarrowError: 

75 If the pyarrow package is outdated and ``raise_if_error`` is 

76 ``True``. 

77 """ 

78 try: 

79 import pyarrow 

80 except ImportError as exc: 

81 if raise_if_error: 

82 raise exceptions.LegacyPyarrowError( 

83 "pyarrow package not found. Install pyarrow version >=" 

84 f" {_MIN_PYARROW_VERSION}." 

85 ) from exc 

86 return None 

87 

88 if self.installed_version < _MIN_PYARROW_VERSION: 

89 if raise_if_error: 

90 msg = ( 

91 "Dependency pyarrow is outdated, please upgrade" 

92 f" it to version >= {_MIN_PYARROW_VERSION}" 

93 f" (version found: {self.installed_version})." 

94 ) 

95 raise exceptions.LegacyPyarrowError(msg) 

96 return None 

97 

98 return pyarrow 

99 

100 

101PYARROW_VERSIONS = PyarrowVersions() 

102 

103 

104class BQStorageVersions: 

105 """Version comparisons for google-cloud-bigqueyr-storage package.""" 

106 

107 def __init__(self): 

108 self._installed_version = None 

109 

110 @property 

111 def installed_version(self) -> packaging.version.Version: 

112 """Return the parsed version of google-cloud-bigquery-storage.""" 

113 if self._installed_version is None: 

114 from google.cloud import bigquery_storage 

115 

116 self._installed_version = packaging.version.parse( 

117 # Use 0.0.0, since it is earlier than any released version. 

118 # Legacy versions also have the same property, but 

119 # creating a LegacyVersion has been deprecated. 

120 # https://github.com/pypa/packaging/issues/321 

121 getattr(bigquery_storage, "__version__", "0.0.0") 

122 ) 

123 

124 return self._installed_version # type: ignore 

125 

126 @property 

127 def is_read_session_optional(self) -> bool: 

128 """True if read_session is optional to rows(). 

129 

130 See: https://github.com/googleapis/python-bigquery-storage/pull/228 

131 """ 

132 return self.installed_version >= _BQ_STORAGE_OPTIONAL_READ_SESSION_VERSION 

133 

134 def try_import(self, raise_if_error: bool = False) -> Any: 

135 """Tries to import the bigquery_storage module, and returns results 

136 accordingly. It also verifies the module version is recent enough. 

137 

138 If the import succeeds, returns the ``bigquery_storage`` module. 

139 

140 If the import fails, 

141 returns ``None`` when ``raise_if_error == False``, 

142 raises Error when ``raise_if_error == True``. 

143 

144 Returns: 

145 The ``bigquery_storage`` module or ``None``. 

146 

147 Raises: 

148 exceptions.BigQueryStorageNotFoundError: 

149 If google-cloud-bigquery-storage is not installed 

150 exceptions.LegacyBigQueryStorageError: 

151 If google-cloud-bigquery-storage package is outdated 

152 """ 

153 try: 

154 from google.cloud import bigquery_storage # type: ignore 

155 except ImportError: 

156 if raise_if_error: 

157 msg = ( 

158 "Package google-cloud-bigquery-storage not found. " 

159 "Install google-cloud-bigquery-storage version >= " 

160 f"{_MIN_BQ_STORAGE_VERSION}." 

161 ) 

162 raise exceptions.BigQueryStorageNotFoundError(msg) 

163 return None 

164 

165 if self.installed_version < _MIN_BQ_STORAGE_VERSION: 

166 if raise_if_error: 

167 msg = ( 

168 "Dependency google-cloud-bigquery-storage is outdated, " 

169 f"please upgrade it to version >= {_MIN_BQ_STORAGE_VERSION} " 

170 f"(version found: {self.installed_version})." 

171 ) 

172 raise exceptions.LegacyBigQueryStorageError(msg) 

173 return None 

174 

175 return bigquery_storage 

176 

177 

178BQ_STORAGE_VERSIONS = BQStorageVersions() 

179 

180 

181class PandasVersions: 

182 """Version comparisons for pandas package.""" 

183 

184 def __init__(self): 

185 self._installed_version = None 

186 

187 @property 

188 def installed_version(self) -> packaging.version.Version: 

189 """Return the parsed version of pandas""" 

190 if self._installed_version is None: 

191 import pandas # type: ignore 

192 

193 self._installed_version = packaging.version.parse( 

194 # Use 0.0.0, since it is earlier than any released version. 

195 # Legacy versions also have the same property, but 

196 # creating a LegacyVersion has been deprecated. 

197 # https://github.com/pypa/packaging/issues/321 

198 getattr(pandas, "__version__", "0.0.0") 

199 ) 

200 

201 return self._installed_version 

202 

203 def try_import(self, raise_if_error: bool = False) -> Any: 

204 """Verify that a recent enough version of pandas extra is installed. 

205 The function assumes that pandas extra is installed, and should thus 

206 be used in places where this assumption holds. 

207 Because `pip` can install an outdated version of this extra despite 

208 the constraints in `setup.py`, the calling code can use this helper 

209 to verify the version compatibility at runtime. 

210 Returns: 

211 The ``pandas`` module or ``None``. 

212 Raises: 

213 exceptions.LegacyPandasError: 

214 If the pandas package is outdated and ``raise_if_error`` is 

215 ``True``. 

216 """ 

217 try: 

218 import pandas 

219 except ImportError as exc: 

220 if raise_if_error: 

221 raise exceptions.LegacyPandasError( 

222 "pandas package not found. Install pandas version >=" 

223 f" {_MIN_PANDAS_VERSION}" 

224 ) from exc 

225 return None 

226 

227 if self.installed_version < _MIN_PANDAS_VERSION: 

228 if raise_if_error: 

229 msg = ( 

230 "Dependency pandas is outdated, please upgrade" 

231 f" it to version >= {_MIN_PANDAS_VERSION}" 

232 f" (version found: {self.installed_version})." 

233 ) 

234 raise exceptions.LegacyPandasError(msg) 

235 return None 

236 

237 return pandas 

238 

239 

240PANDAS_VERSIONS = PandasVersions() 

241 

242# Since RANGE support in pandas requires specific versions 

243# of both pyarrow and pandas, we make this a separate 

244# constant instead of as a property of PANDAS_VERSIONS 

245# or PYARROW_VERSIONS. 

246SUPPORTS_RANGE_PYARROW = ( 

247 PANDAS_VERSIONS.try_import() is not None 

248 and PANDAS_VERSIONS.installed_version >= _MIN_PANDAS_VERSION_RANGE 

249 and PYARROW_VERSIONS.try_import() is not None 

250 and PYARROW_VERSIONS.installed_version >= _MIN_PYARROW_VERSION_RANGE 

251) 

252 

253 

254def extract_runtime_version(): 

255 # Retrieve the version information 

256 version_info = sys.version_info 

257 

258 # Extract the major, minor, and micro components 

259 major = version_info.major 

260 minor = version_info.minor 

261 micro = version_info.micro 

262 

263 # Display the version number in a clear format 

264 return major, minor, micro