pygeodesy 24.3.24__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- PyGeodesy-24.3.24.dist-info/METADATA +272 -0
- PyGeodesy-24.3.24.dist-info/RECORD +115 -0
- PyGeodesy-24.3.24.dist-info/WHEEL +6 -0
- PyGeodesy-24.3.24.dist-info/top_level.txt +1 -0
- pygeodesy/LICENSE +21 -0
- pygeodesy/__init__.py +615 -0
- pygeodesy/__main__.py +103 -0
- pygeodesy/albers.py +867 -0
- pygeodesy/auxilats/_CX_4.py +218 -0
- pygeodesy/auxilats/_CX_6.py +314 -0
- pygeodesy/auxilats/_CX_8.py +475 -0
- pygeodesy/auxilats/__init__.py +54 -0
- pygeodesy/auxilats/__main__.py +86 -0
- pygeodesy/auxilats/auxAngle.py +548 -0
- pygeodesy/auxilats/auxDLat.py +302 -0
- pygeodesy/auxilats/auxDST.py +296 -0
- pygeodesy/auxilats/auxLat.py +848 -0
- pygeodesy/auxilats/auxily.py +272 -0
- pygeodesy/azimuthal.py +1150 -0
- pygeodesy/basics.py +892 -0
- pygeodesy/booleans.py +2031 -0
- pygeodesy/cartesianBase.py +1062 -0
- pygeodesy/clipy.py +704 -0
- pygeodesy/constants.py +516 -0
- pygeodesy/css.py +660 -0
- pygeodesy/datums.py +752 -0
- pygeodesy/deprecated/__init__.py +61 -0
- pygeodesy/deprecated/bases.py +40 -0
- pygeodesy/deprecated/classes.py +262 -0
- pygeodesy/deprecated/consterns.py +54 -0
- pygeodesy/deprecated/datum.py +40 -0
- pygeodesy/deprecated/functions.py +375 -0
- pygeodesy/deprecated/nvector.py +48 -0
- pygeodesy/deprecated/rhumbBase.py +32 -0
- pygeodesy/deprecated/rhumbaux.py +33 -0
- pygeodesy/deprecated/rhumbsolve.py +33 -0
- pygeodesy/deprecated/rhumbx.py +33 -0
- pygeodesy/dms.py +986 -0
- pygeodesy/ecef.py +1348 -0
- pygeodesy/elevations.py +279 -0
- pygeodesy/ellipsoidalBase.py +1224 -0
- pygeodesy/ellipsoidalBaseDI.py +913 -0
- pygeodesy/ellipsoidalExact.py +343 -0
- pygeodesy/ellipsoidalGeodSolve.py +343 -0
- pygeodesy/ellipsoidalKarney.py +403 -0
- pygeodesy/ellipsoidalNvector.py +685 -0
- pygeodesy/ellipsoidalVincenty.py +590 -0
- pygeodesy/ellipsoids.py +2476 -0
- pygeodesy/elliptic.py +1198 -0
- pygeodesy/epsg.py +243 -0
- pygeodesy/errors.py +804 -0
- pygeodesy/etm.py +1190 -0
- pygeodesy/fmath.py +1013 -0
- pygeodesy/formy.py +1818 -0
- pygeodesy/frechet.py +865 -0
- pygeodesy/fstats.py +760 -0
- pygeodesy/fsums.py +1898 -0
- pygeodesy/gars.py +358 -0
- pygeodesy/geodesicw.py +581 -0
- pygeodesy/geodesicx/_C4_24.py +1699 -0
- pygeodesy/geodesicx/_C4_27.py +2395 -0
- pygeodesy/geodesicx/_C4_30.py +3301 -0
- pygeodesy/geodesicx/__init__.py +48 -0
- pygeodesy/geodesicx/__main__.py +91 -0
- pygeodesy/geodesicx/gx.py +1382 -0
- pygeodesy/geodesicx/gxarea.py +535 -0
- pygeodesy/geodesicx/gxbases.py +154 -0
- pygeodesy/geodesicx/gxline.py +669 -0
- pygeodesy/geodsolve.py +426 -0
- pygeodesy/geohash.py +914 -0
- pygeodesy/geoids.py +1884 -0
- pygeodesy/hausdorff.py +892 -0
- pygeodesy/heights.py +1155 -0
- pygeodesy/interns.py +687 -0
- pygeodesy/iters.py +545 -0
- pygeodesy/karney.py +919 -0
- pygeodesy/ktm.py +633 -0
- pygeodesy/latlonBase.py +1766 -0
- pygeodesy/lazily.py +960 -0
- pygeodesy/lcc.py +684 -0
- pygeodesy/ltp.py +1107 -0
- pygeodesy/ltpTuples.py +1563 -0
- pygeodesy/mgrs.py +721 -0
- pygeodesy/named.py +1324 -0
- pygeodesy/namedTuples.py +683 -0
- pygeodesy/nvectorBase.py +695 -0
- pygeodesy/osgr.py +781 -0
- pygeodesy/points.py +1686 -0
- pygeodesy/props.py +628 -0
- pygeodesy/resections.py +1048 -0
- pygeodesy/rhumb/__init__.py +46 -0
- pygeodesy/rhumb/aux_.py +397 -0
- pygeodesy/rhumb/bases.py +1148 -0
- pygeodesy/rhumb/ekx.py +563 -0
- pygeodesy/rhumb/solve.py +572 -0
- pygeodesy/simplify.py +647 -0
- pygeodesy/solveBase.py +472 -0
- pygeodesy/sphericalBase.py +724 -0
- pygeodesy/sphericalNvector.py +1264 -0
- pygeodesy/sphericalTrigonometry.py +1447 -0
- pygeodesy/streprs.py +627 -0
- pygeodesy/trf.py +2079 -0
- pygeodesy/triaxials.py +1484 -0
- pygeodesy/units.py +969 -0
- pygeodesy/unitsBase.py +349 -0
- pygeodesy/ups.py +538 -0
- pygeodesy/utily.py +1231 -0
- pygeodesy/utm.py +762 -0
- pygeodesy/utmups.py +318 -0
- pygeodesy/utmupsBase.py +517 -0
- pygeodesy/vector2d.py +785 -0
- pygeodesy/vector3d.py +968 -0
- pygeodesy/vector3dBase.py +1049 -0
- pygeodesy/webmercator.py +383 -0
- pygeodesy/wgrs.py +439 -0
pygeodesy/errors.py
ADDED
|
@@ -0,0 +1,804 @@
|
|
|
1
|
+
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
u'''Errors, exceptions, exception formatting and exception chaining.
|
|
5
|
+
|
|
6
|
+
Error, exception classes and functions to format PyGeodesy errors, including
|
|
7
|
+
the setting of I{exception chaining} for Python 3.9+.
|
|
8
|
+
|
|
9
|
+
By default, I{exception chaining} is turned I{off}. To enable I{exception
|
|
10
|
+
chaining}, use command line option C{python -X dev} I{OR} set env variable
|
|
11
|
+
C{PYTHONDEVMODE=1} or to any non-empty string I{OR} set env variable
|
|
12
|
+
C{PYGEODESY_EXCEPTION_CHAINING=std} or to any non-empty string.
|
|
13
|
+
'''
|
|
14
|
+
# from pygeodesy.basics import isint, isodd, itemsorted, _xinstanceof, _zip # _MODS
|
|
15
|
+
# from pygeodesy.ellipsoidalBase import CartesianEllipsoidalBase, LatLonEllipsoidalBase # _MODS
|
|
16
|
+
# from pygeodesy import errors # _MODS.getattr
|
|
17
|
+
from pygeodesy.interns import MISSING, NN, _a_, _an_, _and_, _clip_, _COLON_, \
|
|
18
|
+
_COLONSPACE_, _COMMASPACE_, _datum_, _ellipsoidal_, \
|
|
19
|
+
_incompatible_, _invalid_, _len_, _not_, _or_, _SPACE_, \
|
|
20
|
+
_specified_, _UNDER_, _vs_, _with_, _tailof
|
|
21
|
+
from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _getenv, _PYTHON_X_DEV
|
|
22
|
+
# from pygeodesy.streprs import Fmt, unstr # _MODS
|
|
23
|
+
# from pygeodesy.vector3dBase import Vector3dBase # _MODS
|
|
24
|
+
|
|
25
|
+
from copy import copy as _copy
|
|
26
|
+
|
|
27
|
+
__all__ = _ALL_LAZY.errors # _ALL_DOCS('_InvalidError', '_IsnotError') _under
|
|
28
|
+
__version__ = '24.03.24'
|
|
29
|
+
|
|
30
|
+
_box_ = 'box'
|
|
31
|
+
_limiterrors = True # in .formy
|
|
32
|
+
_name_value_ = repr('name=value')
|
|
33
|
+
_rangerrors = True # in .dms
|
|
34
|
+
_region_ = 'region'
|
|
35
|
+
_vs__ = _SPACE_(NN, _vs_, NN)
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
_exception_chaining = None # not available
|
|
39
|
+
_ = Exception().__cause__ # Python 3.9+ exception chaining
|
|
40
|
+
|
|
41
|
+
if _PYTHON_X_DEV or _getenv('PYGEODESY_EXCEPTION_CHAINING', NN): # == _std_
|
|
42
|
+
_exception_chaining = True # turned on, std
|
|
43
|
+
raise AttributeError # allow exception chaining
|
|
44
|
+
|
|
45
|
+
_exception_chaining = False # turned off
|
|
46
|
+
|
|
47
|
+
def _error_cause(inst, cause=None):
|
|
48
|
+
'''(INTERNAL) Set or avoid Python 3+ exception chaining.
|
|
49
|
+
|
|
50
|
+
Setting C{inst.__cause__ = None} is equivalent to syntax
|
|
51
|
+
C{raise Error(...) from None} to avoid exception chaining.
|
|
52
|
+
|
|
53
|
+
@arg inst: An error instance (I{caught} C{Exception}).
|
|
54
|
+
@kwarg cause: A previous error instance (I{caught} C{Exception})
|
|
55
|
+
or C{None} to avoid exception chaining.
|
|
56
|
+
|
|
57
|
+
@see: Alex Martelli, et.al., "Python in a Nutshell", 3rd Ed., page 163,
|
|
58
|
+
O'Reilly, 2017, U{PEP-3134<https://www.Python.org/dev/peps/pep-3134>},
|
|
59
|
+
U{here<https://StackOverflow.com/questions/17091520/how-can-i-more-
|
|
60
|
+
easily-suppress-previous-exceptions-when-i-raise-my-own-exception>}
|
|
61
|
+
and U{here<https://StackOverflow.com/questions/1350671/
|
|
62
|
+
inner-exception-with-traceback-in-python>}.
|
|
63
|
+
'''
|
|
64
|
+
inst.__cause__ = cause # None, no exception chaining
|
|
65
|
+
return inst
|
|
66
|
+
|
|
67
|
+
except AttributeError: # Python 2+
|
|
68
|
+
|
|
69
|
+
def _error_cause(inst, **unused): # PYCHOK expected
|
|
70
|
+
return inst # no-op
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class _AssertionError(AssertionError):
|
|
74
|
+
'''(INTERNAL) Format an C{AssertionError} with/-out exception chaining.
|
|
75
|
+
'''
|
|
76
|
+
def __init__(self, *args, **kwds):
|
|
77
|
+
_error_init(AssertionError, self, args, **kwds)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class _AttributeError(AttributeError):
|
|
81
|
+
'''(INTERNAL) Format an C{AttributeError} with/-out exception chaining.
|
|
82
|
+
'''
|
|
83
|
+
def __init__(self, *args, **kwds):
|
|
84
|
+
_error_init(AttributeError, self, args, **kwds)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class _ImportError(ImportError):
|
|
88
|
+
'''(INTERNAL) Format an C{ImportError} with/-out exception chaining.
|
|
89
|
+
'''
|
|
90
|
+
def __init__(self, *args, **kwds):
|
|
91
|
+
_error_init(ImportError, self, args, **kwds)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class _IndexError(IndexError):
|
|
95
|
+
'''(INTERNAL) Format an C{IndexError} with/-out exception chaining.
|
|
96
|
+
'''
|
|
97
|
+
def __init__(self, *args, **kwds):
|
|
98
|
+
_error_init(IndexError, self, args, **kwds)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class _KeyError(KeyError):
|
|
102
|
+
'''(INTERNAL) Format a C{KeyError} with/-out exception chaining.
|
|
103
|
+
'''
|
|
104
|
+
def __init__(self, *args, **kwds): # txt=_invalid_
|
|
105
|
+
_error_init(KeyError, self, args, **kwds)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class _NameError(NameError):
|
|
109
|
+
'''(INTERNAL) Format a C{NameError} with/-out exception chaining.
|
|
110
|
+
'''
|
|
111
|
+
def __init__(self, *args, **kwds):
|
|
112
|
+
_error_init(NameError, self, args, **kwds)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class _NotImplementedError(NotImplementedError):
|
|
116
|
+
'''(INTERNAL) Format a C{NotImplementedError} with/-out exception chaining.
|
|
117
|
+
'''
|
|
118
|
+
def __init__(self, *args, **kwds):
|
|
119
|
+
_error_init(NotImplementedError, self, args, **kwds)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class _OverflowError(OverflowError):
|
|
123
|
+
'''(INTERNAL) Format an C{OverflowError} with/-out exception chaining.
|
|
124
|
+
'''
|
|
125
|
+
def __init__(self, *args, **kwds): # txt=_invalid_
|
|
126
|
+
_error_init(OverflowError, self, args, **kwds)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class _TypeError(TypeError):
|
|
130
|
+
'''(INTERNAL) Format a C{TypeError} with/-out exception chaining.
|
|
131
|
+
'''
|
|
132
|
+
def __init__(self, *args, **kwds):
|
|
133
|
+
_error_init(TypeError, self, args, fmt_name_value='type(%s) (%r)', **kwds)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _TypesError(name, value, *Types, **kwds):
|
|
137
|
+
'''(INTERNAL) Format a C{TypeError} with/-out exception chaining.
|
|
138
|
+
'''
|
|
139
|
+
# no longer C{class _TypesError} to avoid missing value
|
|
140
|
+
# argument errors in _XError line ...E = Error(str(e))
|
|
141
|
+
t = _not_(_an(_or(*(t.__name__ for t in Types))))
|
|
142
|
+
return _TypeError(name, value, txt=t, **kwds)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class _ValueError(ValueError):
|
|
146
|
+
'''(INTERNAL) Format a C{ValueError} with/-out exception chaining.
|
|
147
|
+
'''
|
|
148
|
+
def __init__(self, *args, **kwds): # ..., cause=None, txt=_invalid_, ...
|
|
149
|
+
_error_init(ValueError, self, args, **kwds)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class _ZeroDivisionError(ZeroDivisionError):
|
|
153
|
+
'''(INTERNAL) Format a C{ZeroDivisionError} with/-out exception chaining.
|
|
154
|
+
'''
|
|
155
|
+
def __init__(self, *args, **kwds):
|
|
156
|
+
_error_init(ZeroDivisionError, self, args, **kwds)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class AuxError(_ValueError):
|
|
160
|
+
'''Error raised for a L{rhumb.aux_}, C{Aux}, C{AuxDLat} or C{AuxLat} issue.
|
|
161
|
+
'''
|
|
162
|
+
pass
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class ClipError(_ValueError):
|
|
166
|
+
'''Clip box or clip region issue.
|
|
167
|
+
'''
|
|
168
|
+
def __init__(self, *name_n_corners, **txt_cause):
|
|
169
|
+
'''New L{ClipError}.
|
|
170
|
+
|
|
171
|
+
@arg name_n_corners: Either just a name (C{str}) or
|
|
172
|
+
name, number, corners (C{str},
|
|
173
|
+
C{int}, C{tuple}).
|
|
174
|
+
@kwarg txt_cause: Optional C{B{txt}=str} explanation
|
|
175
|
+
of the error and C{B{cause}=None}
|
|
176
|
+
for exception chaining.
|
|
177
|
+
'''
|
|
178
|
+
if len(name_n_corners) == 3:
|
|
179
|
+
t, n, v = name_n_corners
|
|
180
|
+
n = _SPACE_(t, _clip_, (_box_ if n == 2 else _region_))
|
|
181
|
+
name_n_corners = n, v
|
|
182
|
+
_ValueError.__init__(self, *name_n_corners, **txt_cause)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class CrossError(_ValueError):
|
|
186
|
+
'''Error raised for zero or near-zero vectorial cross products,
|
|
187
|
+
occurring for coincident or colinear points, lines or bearings.
|
|
188
|
+
'''
|
|
189
|
+
pass
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class GeodesicError(_ValueError):
|
|
193
|
+
'''Error raised for lack of convergence or other issues in L{pygeodesy.geodesicx},
|
|
194
|
+
L{pygeodesy.geodesicw} or L{pygeodesy.karney}.
|
|
195
|
+
'''
|
|
196
|
+
pass
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class IntersectionError(_ValueError): # in .ellipsoidalBaseDI, .formy, ...
|
|
200
|
+
'''Error raised for line or circle intersection issues.
|
|
201
|
+
'''
|
|
202
|
+
def __init__(self, *args, **kwds):
|
|
203
|
+
'''New L{IntersectionError}.
|
|
204
|
+
'''
|
|
205
|
+
if args:
|
|
206
|
+
_ValueError.__init__(self, _SPACE_(*args), **kwds)
|
|
207
|
+
else:
|
|
208
|
+
_ValueError.__init__(self, **kwds)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class LenError(_ValueError): # in .ecef, .fmath, .heights, .iters, .named
|
|
212
|
+
'''Error raised for mis-matching C{len} values.
|
|
213
|
+
'''
|
|
214
|
+
def __init__(self, where, **lens_txt): # txt=None
|
|
215
|
+
'''New L{LenError}.
|
|
216
|
+
|
|
217
|
+
@arg where: Object with C{.__name__} attribute
|
|
218
|
+
(C{class}, C{method}, or C{function}).
|
|
219
|
+
@kwarg lens_txt: Two or more C{name=len(name)} pairs
|
|
220
|
+
(C{keyword arguments}).
|
|
221
|
+
'''
|
|
222
|
+
def _ns_vs_txt_x(cause=None, txt=_invalid_, **kwds):
|
|
223
|
+
ns, vs = zip(*_MODS.basics.itemsorted(kwds)) # unzip
|
|
224
|
+
return ns, vs, txt, cause
|
|
225
|
+
|
|
226
|
+
ns, vs, txt, x = _ns_vs_txt_x(**lens_txt)
|
|
227
|
+
ns = _COMMASPACE_.join(ns)
|
|
228
|
+
t = _MODS.streprs.Fmt.PAREN(where.__name__, ns)
|
|
229
|
+
vs = _vs__.join(map(str, vs))
|
|
230
|
+
t = _SPACE_(t, _len_, vs)
|
|
231
|
+
_ValueError.__init__(self, t, txt=txt, cause=x)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class LimitError(_ValueError):
|
|
235
|
+
'''Error raised for lat- or longitudinal values or deltas exceeding
|
|
236
|
+
the given B{C{limit}} in functions L{pygeodesy.equirectangular},
|
|
237
|
+
L{pygeodesy.equirectangular_}, C{nearestOn*} and C{simplify*}
|
|
238
|
+
or methods with C{limit} or C{options} keyword arguments.
|
|
239
|
+
|
|
240
|
+
@see: Subclass L{UnitError}.
|
|
241
|
+
'''
|
|
242
|
+
pass
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class MGRSError(_ValueError):
|
|
246
|
+
'''Military Grid Reference System (MGRS) parse or other L{Mgrs} issue.
|
|
247
|
+
'''
|
|
248
|
+
pass
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class NumPyError(_ValueError):
|
|
252
|
+
'''Error raised for C{NumPy} issues.
|
|
253
|
+
'''
|
|
254
|
+
pass
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class ParseError(_ValueError): # in .dms, .elevations, .utmupsBase
|
|
258
|
+
'''Error parsing degrees, radians or several other formats.
|
|
259
|
+
'''
|
|
260
|
+
pass
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
class PointsError(_ValueError): # in .clipy, .frechet, ...
|
|
264
|
+
'''Error for an insufficient number of points.
|
|
265
|
+
'''
|
|
266
|
+
pass
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class RangeError(_ValueError):
|
|
270
|
+
'''Error raised for lat- or longitude values outside the B{C{clip}},
|
|
271
|
+
B{C{clipLat}}, B{C{clipLon}} in functions L{pygeodesy.parse3llh},
|
|
272
|
+
L{pygeodesy.parseDMS}, L{pygeodesy.parseDMS2} and L{pygeodesy.parseRad}
|
|
273
|
+
or the given B{C{limit}} in functions L{pygeodesy.clipDegrees} and
|
|
274
|
+
L{pygeodesy.clipRadians}.
|
|
275
|
+
|
|
276
|
+
@see: Function L{pygeodesy.rangerrors}.
|
|
277
|
+
'''
|
|
278
|
+
pass
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class RhumbError(_ValueError):
|
|
282
|
+
'''Error raised for a L{pygeodesy.rhumb.aux_}, L{pygeodesy.rhumb.ekx}
|
|
283
|
+
or L{pygeodesy.rhumb.solve} issue.
|
|
284
|
+
'''
|
|
285
|
+
pass
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class TriangleError(_ValueError): # in .resections, .vector2d
|
|
289
|
+
'''Error raised for triangle, inter- or resection issues.
|
|
290
|
+
'''
|
|
291
|
+
pass
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class SciPyError(PointsError):
|
|
295
|
+
'''Error raised for C{SciPy} issues.
|
|
296
|
+
'''
|
|
297
|
+
pass
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class SciPyWarning(PointsError):
|
|
301
|
+
'''Error thrown for C{SciPy} warnings.
|
|
302
|
+
|
|
303
|
+
To raise C{SciPy} warnings as L{SciPyWarning} exceptions, Python
|
|
304
|
+
C{warnings} must be filtered as U{warnings.filterwarnings('error')
|
|
305
|
+
<https://docs.Python.org/3/library/warnings.html#the-warnings-filter>}
|
|
306
|
+
I{prior to} C{import scipy} OR by setting env var U{PYTHONWARNINGS
|
|
307
|
+
<https://docs.Python.org/3/using/cmdline.html#envvar-PYTHONWARNINGS>}
|
|
308
|
+
OR by invoking C{python} with command line option U{-W<https://docs.
|
|
309
|
+
Python.org/3/using/cmdline.html#cmdoption-w>} set to C{-W error}.
|
|
310
|
+
'''
|
|
311
|
+
pass
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
class TRFError(_ValueError): # in .ellipsoidalBase, .trf, .units
|
|
315
|
+
'''Terrestrial Reference Frame (TRF), L{Epoch}, L{RefFrame}
|
|
316
|
+
or L{RefFrame} conversion issue.
|
|
317
|
+
'''
|
|
318
|
+
pass
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
class UnitError(LimitError): # in .named, .units
|
|
322
|
+
'''Default exception for L{units} issues for a value exceeding the
|
|
323
|
+
C{low} or C{high} limit.
|
|
324
|
+
'''
|
|
325
|
+
pass
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
class VectorError(_ValueError): # in .nvectorBase, .vector3d, .vector3dBase
|
|
329
|
+
'''L{Vector3d}, C{Cartesian*} or C{*Nvector} issues.
|
|
330
|
+
'''
|
|
331
|
+
pass
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def _an(noun):
|
|
335
|
+
'''(INTERNAL) Prepend an article to a noun based
|
|
336
|
+
on the pronounciation of the first letter.
|
|
337
|
+
'''
|
|
338
|
+
a = _an_ if noun[:1].lower() in 'aeinoux' else _a_
|
|
339
|
+
return _SPACE_(a, noun)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def _and(*words):
|
|
343
|
+
'''(INTERNAL) Join C{words} with C{", "} and C{" and "}.
|
|
344
|
+
'''
|
|
345
|
+
return _and_or(_and_, *words)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def _and_or(last, *words):
|
|
349
|
+
'''(INTERNAL) Join C{words} with C{", "} and C{B{last}}.
|
|
350
|
+
'''
|
|
351
|
+
t, w = NN, list(words)
|
|
352
|
+
if w:
|
|
353
|
+
t = w.pop()
|
|
354
|
+
if w:
|
|
355
|
+
w = _COMMASPACE_.join(w)
|
|
356
|
+
t = _SPACE_(w, last, t)
|
|
357
|
+
return t
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def crosserrors(raiser=None):
|
|
361
|
+
'''Report or ignore vectorial cross product errors.
|
|
362
|
+
|
|
363
|
+
@kwarg raiser: Use C{True} to throw or C{False} to ignore
|
|
364
|
+
L{CrossError} exceptions. Use C{None} to
|
|
365
|
+
leave the setting unchanged.
|
|
366
|
+
|
|
367
|
+
@return: Previous setting (C{bool}).
|
|
368
|
+
|
|
369
|
+
@see: Property C{Vector3d[Base].crosserrors}.
|
|
370
|
+
'''
|
|
371
|
+
V = _MODS.vector3dBase.Vector3dBase
|
|
372
|
+
t = V._crosserrors # XXX class attr!
|
|
373
|
+
if raiser in (True, False):
|
|
374
|
+
V._crosserrors = raiser
|
|
375
|
+
return t
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def _error_init(Error, inst, args, fmt_name_value='%s (%r)', txt=NN,
|
|
379
|
+
cause=None, **kwds): # by .lazily
|
|
380
|
+
'''(INTERNAL) Format an error text and initialize an C{Error} instance.
|
|
381
|
+
|
|
382
|
+
@arg Error: The error super-class (C{Exception}).
|
|
383
|
+
@arg inst: Sub-class instance to be __init__-ed (C{_Exception}).
|
|
384
|
+
@arg args: Either just a value or several name, value, ...
|
|
385
|
+
positional arguments (C{str}, any C{type}), in
|
|
386
|
+
particular for name conflicts with keyword
|
|
387
|
+
arguments of C{error_init} or which can't be
|
|
388
|
+
given as C{name=value} keyword arguments.
|
|
389
|
+
@kwarg fmt_name_value: Format for (name, value) (C{str}).
|
|
390
|
+
@kwarg txt: Optional explanation of the error (C{str}).
|
|
391
|
+
@kwarg cause: Optional, caught error (L{Exception}), for
|
|
392
|
+
exception chaining (supported in Python 3+).
|
|
393
|
+
@kwarg kwds: Additional C{B{name}=value} pairs, if any.
|
|
394
|
+
'''
|
|
395
|
+
def _fmtuple(pairs):
|
|
396
|
+
return tuple(fmt_name_value % t for t in pairs)
|
|
397
|
+
|
|
398
|
+
t, n = (), len(args)
|
|
399
|
+
if n > 2:
|
|
400
|
+
s = _MODS.basics.isodd(n)
|
|
401
|
+
t = _fmtuple(zip(args[0::2], args[1::2]))
|
|
402
|
+
if s: # XXX _xzip(..., strict=s)
|
|
403
|
+
t += args[-1:]
|
|
404
|
+
elif n == 2:
|
|
405
|
+
t = (fmt_name_value % args),
|
|
406
|
+
elif n: # == 1
|
|
407
|
+
t = str(args[0]),
|
|
408
|
+
|
|
409
|
+
if kwds:
|
|
410
|
+
t += _fmtuple(_MODS.basics.itemsorted(kwds))
|
|
411
|
+
t = _or(*t) if t else _SPACE_(_name_value_, MISSING)
|
|
412
|
+
|
|
413
|
+
if txt is not None:
|
|
414
|
+
x = str(txt) or (str(cause) if cause else _invalid_)
|
|
415
|
+
C = _COMMASPACE_ if _COLON_ in t else _COLONSPACE_
|
|
416
|
+
t = C(t, x)
|
|
417
|
+
# else: # LenError, _xzip, .dms, .heights, .vector2d
|
|
418
|
+
# x = NN # XXX or t?
|
|
419
|
+
Error.__init__(inst, t)
|
|
420
|
+
# inst.__x_txt__ = x # hold explanation
|
|
421
|
+
_error_cause(inst, cause=cause if _exception_chaining else None)
|
|
422
|
+
_error_under(inst)
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def _error_under(inst):
|
|
426
|
+
'''(INTERNAL) Remove leading underscore from instance' class name.
|
|
427
|
+
'''
|
|
428
|
+
n = inst.__class__.__name__
|
|
429
|
+
if n.startswith(_UNDER_):
|
|
430
|
+
inst.__class__.__name__ = n.lstrip(_UNDER_)
|
|
431
|
+
return inst
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def exception_chaining(exc=None):
|
|
435
|
+
'''Get an error's I{cause} or the exception chaining setting.
|
|
436
|
+
|
|
437
|
+
@kwarg exc: An error instance (C{Exception}) or C{None}.
|
|
438
|
+
|
|
439
|
+
@return: If C{B{exc} is None}, return C{True} if exception
|
|
440
|
+
chaining is enabled for PyGeodesy errors, C{False}
|
|
441
|
+
if turned off and C{None} if not available. If
|
|
442
|
+
B{C{exc}} is not C{None}, return it's error I{cause}
|
|
443
|
+
or C{None}.
|
|
444
|
+
|
|
445
|
+
@note: To enable exception chaining for C{pygeodesy} errors,
|
|
446
|
+
set env var C{PYGEODESY_EXCEPTION_CHAINING} to any
|
|
447
|
+
non-empty value prior to C{import pygeodesy}.
|
|
448
|
+
'''
|
|
449
|
+
return _exception_chaining if exc is None else \
|
|
450
|
+
getattr(exc, '__cause__', None)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def _incompatible(this):
|
|
454
|
+
'''(INTERNAL) Format an C{"incompatible with ..."} text.
|
|
455
|
+
'''
|
|
456
|
+
return _SPACE_(_incompatible_, _with_, this)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def _InvalidError(Error=_ValueError, **txt_name_values_cause): # txt=_invalid_, name=value [, ...]
|
|
460
|
+
'''(INTERNAL) Create an C{Error} instance.
|
|
461
|
+
|
|
462
|
+
@kwarg Error: The error class or sub-class (C{Exception}).
|
|
463
|
+
@kwarg txt_name_values: One or more C{B{name}=value} pairs
|
|
464
|
+
and optionally, keyword argument C{B{txt}=str}
|
|
465
|
+
to override the default C{B{txt}='invalid'} and
|
|
466
|
+
C{B{cause}=None} for exception chaining.
|
|
467
|
+
|
|
468
|
+
@return: An B{C{Error}} instance.
|
|
469
|
+
'''
|
|
470
|
+
return _XError(Error, **txt_name_values_cause)
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def isError(exc):
|
|
474
|
+
'''Check a (caught) exception.
|
|
475
|
+
|
|
476
|
+
@arg exc: The exception C({Exception}).
|
|
477
|
+
|
|
478
|
+
@return: C{True} if B{C{exc}} is a C{pygeodesy} error,
|
|
479
|
+
C{False} if B{C{exc}} is a standard Python error
|
|
480
|
+
of C{None} if neither.
|
|
481
|
+
'''
|
|
482
|
+
return True if isinstance(exc, _XErrors) else (
|
|
483
|
+
False if isinstance(exc, Exception) else None)
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
def _IsnotError(*nouns, **name_value_Error_cause): # name=value [, Error=TypeError, cause=None]
|
|
487
|
+
'''Create a C{TypeError} for an invalid C{name=value} type.
|
|
488
|
+
|
|
489
|
+
@arg nouns: One or more expected class or type names, usually nouns (C{str}).
|
|
490
|
+
@kwarg name_value_Error_cause: One C{B{name}=value} pair and optionally,
|
|
491
|
+
keyword argument C{B{Error}=TypeError} to override the default
|
|
492
|
+
and C{B{cause}=None} for exception chaining.
|
|
493
|
+
|
|
494
|
+
@return: A C{TypeError} or an B{C{Error}} instance.
|
|
495
|
+
'''
|
|
496
|
+
def _n_v_E_x(cause=None, Error=TypeError, **name_value):
|
|
497
|
+
return _xkwds_item2(name_value) + (Error, cause)
|
|
498
|
+
|
|
499
|
+
n, v, E, x = _n_v_E_x(**name_value_Error_cause)
|
|
500
|
+
|
|
501
|
+
n = _MODS.streprs.Fmt.PARENSPACED(n, repr(v))
|
|
502
|
+
t = _not_(_an(_or(*nouns)) if nouns else _specified_)
|
|
503
|
+
return _XError(E, n, txt=t, cause=x)
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def limiterrors(raiser=None):
|
|
507
|
+
'''Get/set the throwing of L{LimitError}s.
|
|
508
|
+
|
|
509
|
+
@kwarg raiser: Choose C{True} to raise or C{False} to
|
|
510
|
+
ignore L{LimitError} exceptions. Use
|
|
511
|
+
C{None} to leave the setting unchanged.
|
|
512
|
+
|
|
513
|
+
@return: Previous setting (C{bool}).
|
|
514
|
+
'''
|
|
515
|
+
global _limiterrors
|
|
516
|
+
t = _limiterrors
|
|
517
|
+
if raiser in (True, False):
|
|
518
|
+
_limiterrors = raiser
|
|
519
|
+
return t
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def _or(*words):
|
|
523
|
+
'''(INTERNAL) Join C{words} with C{", "} and C{" or "}.
|
|
524
|
+
'''
|
|
525
|
+
return _and_or(_or_, *words)
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
def _parseX(parser, *args, **name_values_Error): # name=value[, ..., Error=ParseError]
|
|
529
|
+
'''(INTERNAL) Invoke a parser and handle exceptions.
|
|
530
|
+
|
|
531
|
+
@arg parser: The parser (C{callable}).
|
|
532
|
+
@arg args: Any B{C{parser}} arguments (any C{type}s).
|
|
533
|
+
@kwarg name_values_Error: Any C{B{name}=value} pairs and
|
|
534
|
+
optionally, C{B{Error}=ParseError} keyword
|
|
535
|
+
argument to override the default.
|
|
536
|
+
|
|
537
|
+
@return: Parser result.
|
|
538
|
+
|
|
539
|
+
@raise ParseError: Or the specified C{B{Error}}.
|
|
540
|
+
'''
|
|
541
|
+
try:
|
|
542
|
+
return parser(*args)
|
|
543
|
+
except Exception as x:
|
|
544
|
+
E = type(x) if isError(x) else ParseError
|
|
545
|
+
E, kwds = _xkwds_pop2(name_values_Error, Error=E)
|
|
546
|
+
raise _XError(E, **_xkwds(kwds, cause=x))
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
def rangerrors(raiser=None):
|
|
550
|
+
'''Get/set the throwing of L{RangeError}s.
|
|
551
|
+
|
|
552
|
+
@kwarg raiser: Choose C{True} to raise or C{False} to ignore
|
|
553
|
+
L{RangeError} exceptions. Use C{None} to leave
|
|
554
|
+
the setting unchanged.
|
|
555
|
+
|
|
556
|
+
@return: Previous setting (C{bool}).
|
|
557
|
+
'''
|
|
558
|
+
global _rangerrors
|
|
559
|
+
t = _rangerrors
|
|
560
|
+
if raiser in (True, False):
|
|
561
|
+
_rangerrors = raiser
|
|
562
|
+
return t
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
def _SciPyIssue(exc, *extras): # PYCHOK no cover
|
|
566
|
+
if isinstance(exc, (RuntimeWarning, UserWarning)):
|
|
567
|
+
E = SciPyWarning
|
|
568
|
+
else:
|
|
569
|
+
E = SciPyError # PYCHOK not really
|
|
570
|
+
t = _SPACE_(str(exc).strip(), *extras)
|
|
571
|
+
return E(t, txt=None, cause=exc)
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def _xAssertionError(where, *args, **kwds):
|
|
575
|
+
'''(INTERNAL) Embellish an C{AssertionError} with/-out exception chaining.
|
|
576
|
+
'''
|
|
577
|
+
x, kwds = _xkwds_pop2(kwds, cause=None)
|
|
578
|
+
w = _MODS.streprs.unstr(where, *args, **kwds)
|
|
579
|
+
return _AssertionError(w, txt=None, cause=x)
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
def _xattr(obj, **name_default): # see .strerprs._xattrs
|
|
583
|
+
'''(INTERNAL) Get an C{obj}'s attribute by C{name}.
|
|
584
|
+
'''
|
|
585
|
+
if len(name_default) == 1:
|
|
586
|
+
for n, d in name_default.items():
|
|
587
|
+
return getattr(obj, n, d)
|
|
588
|
+
raise _xAssertionError(_xattr, obj, **name_default)
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def _xcallable(**names_callables):
|
|
592
|
+
'''(INTERNAL) Check one or more C{callable}s.
|
|
593
|
+
'''
|
|
594
|
+
for n, c in names_callables.items():
|
|
595
|
+
if not callable(c):
|
|
596
|
+
raise _TypeError(n, c, txt=_not_(callable.__name__))
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
def _xdatum(datum1, datum2, Error=None):
|
|
600
|
+
'''(INTERNAL) Check for datum, ellipsoid or rhumb mis-match.
|
|
601
|
+
'''
|
|
602
|
+
if Error:
|
|
603
|
+
e1, e2 = datum1.ellipsoid, datum2.ellipsoid
|
|
604
|
+
if e1 != e2:
|
|
605
|
+
raise Error(e2.named2, txt=_incompatible(e1.named2))
|
|
606
|
+
elif datum1 != datum2:
|
|
607
|
+
t = _SPACE_(_datum_, repr(datum1.name),
|
|
608
|
+
_not_, repr(datum2.name))
|
|
609
|
+
raise _AssertionError(t)
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
def _xellipsoidal(**name_value): # see _xellipsoidall elel
|
|
613
|
+
'''(INTERNAL) Check an I{ellipsoidal} item and return its value.
|
|
614
|
+
'''
|
|
615
|
+
if len(name_value) == 1:
|
|
616
|
+
for n, v in name_value.items():
|
|
617
|
+
try:
|
|
618
|
+
if v.isEllipsoidal:
|
|
619
|
+
return v
|
|
620
|
+
except AttributeError:
|
|
621
|
+
pass
|
|
622
|
+
raise _TypeError(n, v, txt=_not_(_ellipsoidal_))
|
|
623
|
+
raise _xAssertionError(_xellipsoidal, name_value)
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
def _xellipsoidall(point): # see _xellipsoidal
|
|
627
|
+
'''(INTERNAL) Check an ellipsoidal C{point}, return C{True}
|
|
628
|
+
if geodetic latlon or C{False} if cartesian.
|
|
629
|
+
'''
|
|
630
|
+
m = _MODS.ellipsoidalBase
|
|
631
|
+
ll = isinstance(point, m.LatLonEllipsoidalBase)
|
|
632
|
+
if not ll:
|
|
633
|
+
b = _MODS.basics
|
|
634
|
+
b._xinstanceof(m.CartesianEllipsoidalBase,
|
|
635
|
+
m.LatLonEllipsoidalBase, point=point)
|
|
636
|
+
return ll
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
def _XError(Error, *args, **kwds):
|
|
640
|
+
'''(INTERNAL) Format an C{Error} or C{_Error}.
|
|
641
|
+
'''
|
|
642
|
+
try: # C{_Error} style
|
|
643
|
+
return Error(*args, **kwds)
|
|
644
|
+
except TypeError: # no keyword arguments
|
|
645
|
+
pass
|
|
646
|
+
e = _ValueError(*args, **kwds)
|
|
647
|
+
E = Error(str(e))
|
|
648
|
+
if _exception_chaining:
|
|
649
|
+
_error_cause(E, cause=e.__cause__) # PYCHOK OK
|
|
650
|
+
return E
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
def _xError(exc, *args, **kwds):
|
|
654
|
+
'''(INTERNAL) Embellish a (caught) exception.
|
|
655
|
+
|
|
656
|
+
@arg exc: The exception (usually, C{_Error}).
|
|
657
|
+
@arg args: Embelishments (C{any}).
|
|
658
|
+
@kwarg kwds: Embelishments (C{any}).
|
|
659
|
+
'''
|
|
660
|
+
return _XError(type(exc), *args, **_xkwds(kwds, cause=exc))
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
def _xError2(exc): # in .constants, .fsums, .lazily, .vector2d
|
|
664
|
+
'''(INTERNAL) Map an exception to 2-tuple (C{_Error} class, error C{txt}).
|
|
665
|
+
|
|
666
|
+
@arg exc: The exception instance (usually, C{Exception}).
|
|
667
|
+
'''
|
|
668
|
+
m = __name__ # 'pygeodesy.errors'
|
|
669
|
+
X = type(exc)
|
|
670
|
+
n = NN(_UNDER_, _tailof(X.__name__))
|
|
671
|
+
E = _MODS.getattr(m, n, X) # == _X2Error.get(X, X)
|
|
672
|
+
if E is X and not isError(exc):
|
|
673
|
+
E = _NotImplementedError
|
|
674
|
+
t = repr(exc)
|
|
675
|
+
else:
|
|
676
|
+
t = str(exc)
|
|
677
|
+
return E, t
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
_XErrors = _TypeError, _ValueError
|
|
681
|
+
# map certain C{Exception} classes to the C{_Error}
|
|
682
|
+
# _X2Error = {AssertionError: _AssertionError,
|
|
683
|
+
# AttributeError: _AttributeError,
|
|
684
|
+
# ImportError: _ImportError,
|
|
685
|
+
# IndexError: _IndexError,
|
|
686
|
+
# KeyError: _KeyError,
|
|
687
|
+
# NameError: _NameError,
|
|
688
|
+
# NotImplementedError: _NotImplementedError,
|
|
689
|
+
# OverflowError: _OverflowError,
|
|
690
|
+
# TypeError: _TypeError,
|
|
691
|
+
# ValueError: _ValueError,
|
|
692
|
+
# ZeroDivisionError: _ZeroDivisionError}
|
|
693
|
+
|
|
694
|
+
try:
|
|
695
|
+
_ = {}.__or__ # {} | {} # Python 3.9+
|
|
696
|
+
|
|
697
|
+
def _xkwds(kwds, **dflts):
|
|
698
|
+
'''(INTERNAL) Update C{dflts} with specified C{kwds}.
|
|
699
|
+
'''
|
|
700
|
+
return (dflts | kwds) if kwds else dflts
|
|
701
|
+
|
|
702
|
+
except AttributeError:
|
|
703
|
+
|
|
704
|
+
def _xkwds(kwds, **dflts): # PYCHOK expected
|
|
705
|
+
'''(INTERNAL) Update C{dflts} with specified C{kwds}.
|
|
706
|
+
'''
|
|
707
|
+
d = dflts
|
|
708
|
+
if kwds:
|
|
709
|
+
d = _copy(d)
|
|
710
|
+
d.update(kwds)
|
|
711
|
+
return d
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
# def _xkwds_bool(inst, **kwds): # no longer in .frechet, .hausdorff, .heights
|
|
715
|
+
# '''(INTERNAL) Set applicable C{bool} properties/attributes.
|
|
716
|
+
# '''
|
|
717
|
+
# for n, v in kwds.items():
|
|
718
|
+
# b = getattr(inst, n, None)
|
|
719
|
+
# if b is None: # invalid bool attr
|
|
720
|
+
# t = _SPACE_(_EQUAL_(n, repr(v)), 'for', inst.__class__.__name__) # XXX .classname
|
|
721
|
+
# raise _AttributeError(t, txt=_not_('applicable'))
|
|
722
|
+
# if v in (False, True) and v != b:
|
|
723
|
+
# setattr(inst, NN(_UNDER_, n), v)
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
def _xkwds_get(kwds, **name_default):
|
|
727
|
+
'''(INTERNAL) Get a C{kwds} value by C{name} or the
|
|
728
|
+
C{default} if not present.
|
|
729
|
+
'''
|
|
730
|
+
if isinstance(kwds, dict) and len(name_default) == 1:
|
|
731
|
+
for n, d in name_default.items():
|
|
732
|
+
return kwds.get(n, d)
|
|
733
|
+
raise _xAssertionError(_xkwds_get, kwds, **name_default)
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
def _xkwds_get_(kwds, **names_defaults):
|
|
737
|
+
'''(INTERNAL) Yield each C{kwds} value or its C{default}
|
|
738
|
+
in I{case-insensitive, alphabetical} C{name} order.
|
|
739
|
+
'''
|
|
740
|
+
if not isinstance(kwds, dict):
|
|
741
|
+
raise _xAssertionError(_xkwds_get_, kwds)
|
|
742
|
+
for n, d in _MODS.basics.itemsorted(names_defaults):
|
|
743
|
+
yield kwds.get(n, d)
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
def _xkwds_item2(kwds):
|
|
747
|
+
'''(INTERNAL) Return the 2-tuple C{item}, keeping the
|
|
748
|
+
single-item C{kwds} I{unmodified}.
|
|
749
|
+
'''
|
|
750
|
+
if isinstance(kwds, dict) and len(kwds) == 1:
|
|
751
|
+
for item in kwds.items():
|
|
752
|
+
return item
|
|
753
|
+
raise _xAssertionError(_xkwds_item2, kwds)
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
def _xkwds_not(*args, **kwds):
|
|
757
|
+
'''(INTERNAL) Return C{kwds} with a value not in C{args}.
|
|
758
|
+
'''
|
|
759
|
+
return dict((n, v) for n, v in kwds.items() if v not in args)
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
def _xkwds_pop2(kwds, **name_default):
|
|
763
|
+
'''(INTERNAL) Pop a C{kwds} item by C{name} and return the value and
|
|
764
|
+
reduced C{kwds} copy, otherwise the C{default} and original C{kwds}.
|
|
765
|
+
'''
|
|
766
|
+
if isinstance(kwds, dict) and len(name_default) == 1:
|
|
767
|
+
for n, d in name_default.items():
|
|
768
|
+
if n in kwds:
|
|
769
|
+
kwds = _copy(kwds)
|
|
770
|
+
d = kwds.pop(n, d)
|
|
771
|
+
return d, kwds
|
|
772
|
+
raise _xAssertionError(_xkwds_pop2, kwds, **name_default)
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
def _Xorder(_Coeffs, Error, **Xorder): # in .auxLat, .ktm, .rhumb.bases, .rhumb.ekx
|
|
776
|
+
'''(INTERNAL) Validate C{RAorder} or C{TMorder}.
|
|
777
|
+
'''
|
|
778
|
+
X, m = _xkwds_item2(Xorder)
|
|
779
|
+
if m in _Coeffs and _MODS.basics.isint(m):
|
|
780
|
+
return m
|
|
781
|
+
t = sorted(map(str, _Coeffs.keys()))
|
|
782
|
+
raise Error(X, m, txt=_not_(_or(*t)))
|
|
783
|
+
|
|
784
|
+
# **) MIT License
|
|
785
|
+
#
|
|
786
|
+
# Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
|
|
787
|
+
#
|
|
788
|
+
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
789
|
+
# copy of this software and associated documentation files (the "Software"),
|
|
790
|
+
# to deal in the Software without restriction, including without limitation
|
|
791
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
792
|
+
# and/or sell copies of the Software, and to permit persons to whom the
|
|
793
|
+
# Software is furnished to do so, subject to the following conditions:
|
|
794
|
+
#
|
|
795
|
+
# The above copyright notice and this permission notice shall be included
|
|
796
|
+
# in all copies or substantial portions of the Software.
|
|
797
|
+
#
|
|
798
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
799
|
+
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
800
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
801
|
+
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
802
|
+
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
803
|
+
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
804
|
+
# OTHER DEALINGS IN THE SOFTWARE.
|