Coverage for pyrdnap / v_grids.py: 99%

71 statements  

« prev     ^ index     » next       coverage.py v7.14.0, created at 2026-05-27 11:33 -0400

1 

2# -*- coding: utf-8 -*- 

3 

4u'''(INTERNAL) C{RD NAP 2018} v#grid utilities. 

5''' 

6from pyrdnap import pyrdnap_abspath # pyrdnap 1st 

7from pyrdnap.__pygeodesy import _0_0s, import_module, _ValueError 

8from pygeodesy import print_ 

9 

10from array import array 

11import os.path as os_path 

12import sys 

13from zipfile import ZipFile 

14 

15__all__ = () 

16__version__ = '26.05.13' 

17 

18_R_C = 481, 301 # shape: rows, cols 

19_RxC = 144781 # total 

20 

21 

22class RDNAPError(_ValueError): # exported by rdnap2018 

23 '''Error raised for C{RD}, C{NAP} and unzip issues. 

24 ''' 

25 pass 

26 

27 

28class _V_grid(tuple): 

29 '''(INTERNAL) V_grid, an R-tuple of C-arrays of C{floats}. 

30 ''' 

31 

32 def __call__(self, i, j): 

33 # R, C = _R_C 

34 # assert isinstance(i, int) and 0 <= i < R 

35 # assert isinstance(j, int) and 0 <= j < C 

36 return self[i][j] 

37 

38 def _assert(self, _0s=0): 

39 z, Z = self._assert2(*_R_C) 

40 _v_assert(z, _0s) 

41 _v_assert(Z, 197 if _0s else 0) 

42 _v_assert(sum(map(len, self)), _RxC) 

43 return self 

44 

45 def _assert2(self, R, C): 

46 _v_assert(len(self), R) 

47 _v_assert(len(_ZEROW), C) 

48 z = Z = 0 # count zeros and _ZEROSWs 

49 try: 

50 for i, r in enumerate(self): 

51 _v_assert(type(r), array) 

52 _v_assert(len(r), C) 

53 if r is _ZEROW: 

54 Z += 1 

55 z += C 

56 else: 

57 z += sum((0 if f else 1) for f in r) 

58 except AssertionError as x: 

59 raise AssertionError('row %s: %s' % (i, x)) 

60 return z, Z 

61 

62 def _round(self, _op, ndigits): 

63 # round(_op(f for a in self 

64 # for f in a), ndigits) 

65 return round(_op(map(_op, self)), ndigits) 

66 

67 

68def _d_array(floats): # lat_/lon_corr_ 

69 return array('d', floats) 

70 

71 

72def _f_array(floats): # _NAP_h, _ZEROW 

73 return array('f', floats) 

74 

75_ZEROW = _f_array(_0_0s(301)) # PYCHOK singleton 

76 

77 

78def _v_grid(v): 

79 return 'v%sgrid' % (v,) 

80 

81 

82def _v_assert(value, valid=_R_C): # in .rd0 

83 if value != valid: 

84 raise AssertionError('%r not %r' % (value, valid)) 

85 return True 

86 

87 

88def _v_grid_txt(v, name, col2or3, _array, **_0s): 

89 '''(INTERNAL) Return a C{_V_grid} for column C{col2or3} of 

90 compressed, variant C{v} grid file C{<name>2018.txt.zip}. 

91 ''' 

92 v = _V_grid(_v_txt_unzip(v, name, col2or3, _array)) 

93 return v._assert(**_0s) 

94 

95 

96def _v_gridz3(v): # PHYCOK no cover 

97 '''(INTERNAL) Return the fully-qualified path, directory and module. 

98 ''' 

99 m = _v_grid(v) 

100 d = pyrdnap_abspath 

101 p = os_path.join(d, m + 'z.zip') 

102 return p, d, m 

103 

104 

105def _v_gridz_import(v): # PHYCOK no cover 

106 '''(INTERNAL) Try "from v#gridz.zip import v#grid" 

107 ''' 

108 v_grid = None 

109 p, _, m = _v_gridz3(v) 

110 try: # Py 3.4+ 

111 # <https://RealPython.com/python-zip-import/ 

112 # #explore-pythons-zipimport-the-tool-behind-zip-imports> 

113 from zipimport import zipimporter as Z # ZipImportError 

114 # get an importer for zip file p and load module m 

115 v_grid = Z(p).load_module(m) # Py3.14- 

116 # XXX should use .exec_module but that fails and/or 

117 # XXX needs .create_module, .find_spec, etc??? 

118 except (AttributeError, ImportError): 

119 try: # trusted old-fashion way 

120 sys.path.insert(0, p) 

121 v_grid = import_module(m) 

122# except ImportError: 

123# v_grid = None 

124 finally: 

125 try: 

126 sys.path.remove(p) 

127 except ValueError: 

128 pass # AssertionError 

129# if v_grid: 

130# sys.modules[m] = v_grid 

131 return v_grid 

132 

133 

134def _v_gridz_unzip(v, force=False, verbose=False): # PHYCOK no cover 

135 '''(INTERNAL) Unzip a C{v#gridz.zip} file into the "pyrdnap" directory 

136 ''' 

137 p, d, m = _v_gridz3(v) 

138 t = os_path.join(d, m) 

139 if (not force) and os_path.exists(t): 

140 t = '%r exists: %r' % (m, t) 

141 raise RDNAPError(t) 

142 try: 

143 with ZipFile(p) as z: 

144 z.extractall(d) 

145 except Exception as x: 

146 raise RDNAPError(m, cause=x) 

147 if verbose: 

148 print_('unzipped', repr(p)) 

149 print_(' into', repr(t)) 

150 

151 

152def _v_txt_unzip(v, name, col2or3, _array): 

153 '''(INTERNAL) Open grid file C{<name>2018.txt} or unzip 

154 C{<name>2018.txt.zip} of variant C{v}, extract column 

155 C{col2or3} and yield 481 rows, each a 301-C{_array} 

156 of floats or _ZEROW if all zeros. 

157 ''' 

158 r = [] 

159 try: 

160 n = name + '2018.txt' 

161 p = pyrdnap_abspath 

162 p = os_path.join(p, _v_grid(v), n) 

163 with (open(p, 'rb') if os_path.exists(p) else 

164 ZipFile(p + '.zip').open(n)) as f: 

165 _, C = _R_C 

166 _r = r.append 

167 t = f.readline() # ignore 1st line 

168 while t: 

169 for _ in range(C * 2): 

170 t = f.readline() 

171 if t: 

172 _r(t.strip().split()[col2or3]) 

173 else: 

174 break 

175 while len(r) >= C: 

176 y = _array(map(float, r[:C])) 

177 yield y if any(y) else _ZEROW 

178 r[:] = r[C:] 

179 except Exception as x: 

180 raise RDNAPError(n, cause=x) 

181 _v_assert(len(r), 0) 

182 

183 

184# __all__ += _ALL_OTHER(RDNAPError) # in .rdnap2018 

185 

186# **) MIT License 

187# 

188# Copyright (C) 2026-2026 -- mrJean1 at Gmail -- All Rights Reserved. 

189# 

190# Permission is hereby granted, free of charge, to any person obtaining a 

191# copy of this software and associated documentation files (the "Software"), 

192# to deal in the Software without restriction, including without limitation 

193# the rights to use, copy, modify, merge, publish, distribute, sublicense, 

194# and/or sell copies of the Software, and to permit persons to whom the 

195# Software is furnished to do so, subject to the following conditions: 

196# 

197# The above copyright notice and this permission notice shall be included 

198# in all copies or substantial portions of the Software. 

199# 

200# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 

201# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 

202# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 

203# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 

204# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 

205# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 

206# OTHER DEALINGS IN THE SOFTWARE.