pygeodesy 25.1.5__py2.py3-none-any.whl → 25.4.8__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/__init__.py CHANGED
@@ -7,7 +7,7 @@ methods for geodetic (lat-/longitude), geocentric (U{ECEF<https://WikiPedia.org/
7
7
  cartesian) and certain U{triaxial ellipsoidal<https://GeographicLib.SourceForge.io/1.44/triaxial.html>}
8
8
  coordinates.
9
9
 
10
- Transcoded partially from U{JavaScript originals<https://GitHub.com/ChrisVeness/geodesy>} by I{Chris Veness (C)
10
+ Transcoded in part from U{JavaScript originals<https://GitHub.com/ChrisVeness/geodesy>} by I{Chris Veness (C)
11
11
  2005-2024} and from several U{C++ classes<https://GeographicLib.SourceForge.io/C++/doc/annotated.html>} by I{Charles
12
12
  F. F. Karney (C) 2008-2024} and published under the same U{MIT License<https://OpenSource.org/licenses/MIT>}**.
13
13
 
@@ -64,19 +64,19 @@ wiki/Hausdorff_distance>} distances.
64
64
  Installation
65
65
  ============
66
66
 
67
- To install PyGeodesy, type C{python[3] -m pip install PyGeodesy} or C{python[3] -m easy_install
68
- PyGeodesy} in a terminal or command window.
67
+ To install C{pygeodesy}, type C{python[3] -m pip install pygeodesy} or C{python[3] -m easy_install
68
+ pygeodesy} in a terminal or command window.
69
69
 
70
- If the wheel C{PyGeodesy-yy.m.d-py2.py3-none-any.whl} is missing in U{PyPI Download files<https://
71
- PyPI.org/project/PyGeodesy/#files>}, download the file from U{GitHub/dist<https://GitHub.com/mrJean1/
70
+ If the wheel C{pygeodesy-yy.m.d-py2.py3-none-any.whl} is missing in U{PyPI Download files<https://
71
+ PyPI.org/project/pygeodesy/#files>}, download the file from U{GitHub/dist<https://GitHub.com/mrJean1/
72
72
  PyGeodesy/tree/master/dist>}. Install that with C{python[3] -m pip install <path-to-downloaded-wheel>}
73
73
  and verify with C{python[3] -m pygeodesy}.
74
74
 
75
- Alternatively, download C{PyGeodesy-yy.m.d.tar.gz} from U{PyPI<https://PyPI.org/project/PyGeodesy>}
75
+ Alternatively, download C{pygeodesy-yy.m.d.tar.gz} from U{PyPI<https://PyPI.org/project/pygeodesy>}
76
76
  or U{GitHub<https://GitHub.com/mrJean1/PyGeodesy>}, C{unzip} the downloaded file, C{cd} to
77
- directory C{Pygeodesy-yy.m.d} and type C{python[3] setup.py install}.
77
+ directory C{pygeodesy-yy.m.d} and type C{python[3] setup.py install}.
78
78
 
79
- To run all PyGeodesy tests, type C{python[3] test/run.py} or type C{python[3] test/unitTestSuite.py}
79
+ To run all C{pygeodesy} tests, type C{python[3] test/run.py} or type C{python[3] test/unitTestSuite.py}
80
80
  before or after installation.
81
81
 
82
82
  Dependencies
@@ -113,16 +113,16 @@ env variable C{PYGEODESY_RHUMBSOLVE} or with property L{Ellipsoid.rhumbsolve}.
113
113
  Documentation
114
114
  =============
115
115
 
116
- In addition to the C{pygeodesy} package, the U{PyGeodesy<https://PyPI.org/project/PyGeodesy>}
116
+ In addition to the C{pygeodesy} package, the U{pygeodesy<https://PyPI.org/project/pygeodesy>}
117
117
  U{distribution files<https://GitHub.com/mrJean1/PyGeodesy/tree/master/dist>} contain the tests,
118
118
  the test results (on macOS only) and the complete U{documentation<https://mrJean1.GitHub.io/PyGeodesy>}
119
119
  (generated by U{Epydoc<https://PyPI.org/project/epydoc>} using command line:
120
- C{epydoc --html --no-private --no-source --name=PyGeodesy --url=... -v pygeodesy}).
120
+ C{epydoc --html --no-private --no-source --name=pygeodesy --url=... -v pygeodesy}).
121
121
 
122
122
  Tests
123
123
  =====
124
124
 
125
- The tests ran with Python 3.13.1 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0),
125
+ The tests ran with Python 3.13.2 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0),
126
126
  Python 3.12.7 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0,
127
127
  U{numpy<https://PyPI.org/project/numpy>} 2.1.0, U{scipy<https://PyPI.org/project/scipy>} 1.14.1,
128
128
  U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.3,
@@ -139,20 +139,21 @@ U{numpy<https://PyPI.org/project/numpy>} 1.16.6, U{scipy<https://PyPI.org/projec
139
139
  U{GeoConvert<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.3,
140
140
  U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.3,
141
141
  U{IntersectTool<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.3 and
142
- U{RhumbSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.3), all in 64-bit on macOS 14.6.1 Sonoma.
142
+ U{RhumbSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.3), all in 64-bit on
143
+ macOS 15.4 Sequoia.
143
144
 
144
145
  All tests ran with and without C{lazy import} for Python 3 and with command line option C{-W default} and
145
146
  env variable C{PYGEODESY_WARNINGS=on} for all Python versions. The results of those tests are included in
146
147
  the distribution files.
147
148
 
148
149
  Test coverage has been measured with U{coverage<https://PyPI.org/project/coverage>} 7.6.1 using Python
149
- 3.13.1, 3.12.7, 3.11.5 and 3.10.8. The complete coverage report in HTML and a PDF summary are included in
150
+ 3.13.2, 3.12.7, 3.11.5 and 3.10.8. The complete coverage report in HTML and a PDF summary are included in
150
151
  the distribution files.
151
152
 
152
- Python 3.13.1, 3.12.7, 3.11.5 and 3.10.8 run on Apple M1 Silicon (C{arm64}), I{natively}. Python 2.7.18 runs
153
+ Python 3.13.2, 3.12.7, 3.11.5 and 3.10.8 run on Apple M1 Silicon (C{arm64}), I{natively}. Python 2.7.18 runs
153
154
  on Intel (C{x86_64}) or Intel I{emulation} ("C{arm64_x86_64}", see function L{machine<pygeodesy.machine>}).
154
155
 
155
- The tests also ran with Python 3.13.1 (and U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0) on
156
+ The tests also ran with Python 3.13.2 (and U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0) on
156
157
  U{Debian 12<https://Cirrus-CI.com/github/mrJean1/PyGeodesy/master>} in 64-bit only, with Python 3.12.5 (and
157
158
  U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0) on U{Windows 2019Server
158
159
  <https://CI.AppVeyor.com/project/mrJean1/pygeodesy>} in 64-bit only and with Python 2.7.18 (and U{geographiclib
@@ -162,7 +163,7 @@ in 64- and 32-bit.
162
163
  A single-File and single-Directory application with C{pygeodesy} has been bundled using U{PyInstaller
163
164
  <https://PyPI.org/project/pyinstaller>} 3.4 and 64-bit Python 3.7.3 on macOS 10.13.6 High Sierra.
164
165
 
165
- Previously, the tests were run with Python 3.13.0, 3.12.0-6, 3.11.2-4, 3.10.1-7, 3.9.6, 3.9.1, 3.8.7, 3.7.1, 2.7.15,
166
+ Previously, the tests were run with Python 3.13.0-1, 3.12.0-6, 3.11.2-4, 3.10.1-7, 3.9.6, 3.9.1, 3.8.7, 3.7.1, 2.7.15,
166
167
  U{PyPy<https://PyPy.org>} 7.3.12 (Python 3.10.12), 7.3.1 (Python 3.6.9) and U{PyPy<https://PyPy.org>} 7.1.1 (Python
167
168
  2.7.13) (and U{geographiclib <https://PyPI.org/project/geographiclib>} 1.52, U{numpy<https://PyPI.org/project/numpy>}
168
169
  1.16.3, 1.16.4, 1.16.6, 1.19.0, 1.19.4, 1.19.5 or 1.22.4 and U{scipy<https://PyPI.org/project/scipy>} 1.2.1, 1.4.1,
@@ -171,7 +172,7 @@ U{PyPy<https://PyPy.org>} 7.3.12 (Python 3.10.12), 7.3.1 (Python 3.6.9) and U{Py
171
172
  1.16.5, 1.16.2, 1.15.2, 1.14.0, 1.13.1, 1.8.0rc1 or 1.6.2 and U{scipy<https://PyPI.org/project/scipy>} 1.5.0), U{PyPy
172
173
  <https://PyPy.org>} 7.3.0 (Python 2.7.13 and 3.6.9), U{PyPy<https://PyPy.org>} 6.0.0 (Python 2.7.13 and 3.5.3)
173
174
  and U{Intel-Python<https://software.Intel.com/en-us/distribution-for-python>} 3.5.3 (and U{numpy
174
- <https://PyPI.org/project/numpy>} 1.11.3) on macOS 14.0-5 Sonoma, 13.0-5.2 Ventura, 12.1-6 Monterey, 11.0-5.2-6.1
175
+ <https://PyPI.org/project/numpy>} 1.11.3) on macOS 14.0-6.1 Sonoma, 13.0-5.2 Ventura, 12.1-6 Monterey, 11.0-5.2-6.1
175
176
  Big Sur (aka 10.16), 10.15.3, 10.15.5-7 Catalina, 10.14 Mojave, 10.13.6 High Sierra and 10.12 Sierra, MacOS X
176
177
  10.11 El Capitan and/or MacOS X 10.10 Yosemite, with U{Pythonista<https://OMZ-Software.com/pythonista>}3.2 (with
177
178
  geographiclib 1.50 or 1.49 and numpy 1.8.0) on iOS 14.4.2, 11.4.1, 12.0-3 on iPad4, iPhone6, iPhone10 and/or
@@ -186,7 +187,7 @@ All Python source code has been statically U{checked<https://GitHub.com/ActiveSt
186
187
  Python/546532_PyChecker_postprocessor>} with U{PyChecker<https://PyPI.org/project/pychecker>}, U{PyFlakes
187
188
  <https://PyPI.org/project/pyflakes>}, U{PyCodeStyle<https://PyPI.org/project/pycodestyle>} (formerly Pep8) and
188
189
  U{McCabe<https://PyPI.org/project/mccabe>} using Python 2.7.18 and with U{Flake8<https://PyPI.org/project/flake8>}
189
- using Python 3.11.5, both in 64-bit on macOS 14.6.1 Sonoma.
190
+ using Python 3.11.5, both in 64-bit on macOS 15.4 Sequoia.
190
191
 
191
192
  For a summary of all I{Karney}-based functionality in C{pygeodesy}, see module U{karney
192
193
  <https://mrJean1.GitHub.io/PyGeodesy/docs/pygeodesy.karney-module.html>}.
@@ -197,7 +198,7 @@ characters and if so, I{not} C{unicode}.
197
198
  Env variables
198
199
  =============
199
200
 
200
- The following environment variables are observed by C{PyGeodesy}:
201
+ The following environment variables are observed by C{pygeodesy}:
201
202
 
202
203
  - C{PYGEODESY_EXCEPTION_CHAINING} - see module L{errors<pygeodesy.errors>}.
203
204
  - C{PYGEODESY_FMT_FORM} - see module L{dms<pygeodesy.dms>}.
@@ -355,7 +356,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.}
355
356
 
356
357
  @var pygeodesy_abspath: Fully qualified C{pygeodesy} directory name (C{str}).
357
358
 
358
- @var version: Normalized C{PyGeodesy} version (C{str}).
359
+ @var version: Normalized C{pygeodesy} version (C{str}).
359
360
  '''
360
361
 
361
362
  import os.path as _os_path
@@ -598,7 +599,7 @@ else:
598
599
 
599
600
  from pygeodesy.internals import _version2, _DOT_ # PYCHOK import
600
601
  # from pygeodesy.interns import _DOT_ # from .internals
601
- __version__ = '25.01.05'
602
+ __version__ = '25.04.08'
602
603
  # see setup.py for similar logic
603
604
  version = _DOT_(*_version2(__version__, n=3))
604
605
 
@@ -11,8 +11,10 @@ MIT/X11 License. For more information, see <https:#GeographicLib.SourceForge.io
11
11
  # make sure int/int division yields float quotient, see .basics
12
12
  from __future__ import division as _; del _ # PYCHOK semicolon
13
13
 
14
- from pygeodesy.constants import _floats
14
+ # from pygeodesy.basics import _splituple # _MODS
15
+ from pygeodesy.constants import _floats as _Cs
15
16
  from pygeodesy.errors import _AssertionError, _MODS
17
+ # from pygeodesy.internals import _sizeof # _MODS
16
18
  from pygeodesy.interns import NN, MISSING, _COMMA_, _duplicate_, _NL_, \
17
19
  _QUOTE3_, _SLASH_, _ELLIPSIS4_ # PYCHOK used!
18
20
  # from pygeodesy.lazily import _ALL_MODS as _MODS # from .errors
@@ -20,7 +22,7 @@ from pygeodesy.named import ADict, Property_RO
20
22
  # from pygeodesy.props import Property_RO # from .named
21
23
 
22
24
  __all__ = ()
23
- __version__ = '24.09.04'
25
+ __version__ = '25.04.08'
24
26
 
25
27
 
26
28
  class _Rcoeffs(ADict):
@@ -31,17 +33,19 @@ class _Rcoeffs(ADict):
31
33
  '''
32
34
  try:
33
35
  if not isinstance(coeffs, dict):
34
- raise _RdictError(coeffs=type(coeffs))
36
+ raise _RsError(coeffs=type(coeffs))
35
37
  n = 0
36
38
  for k, d in coeffs.items():
39
+ if not isinstance(k, _Rkey):
40
+ raise _RsError(k=type(k))
37
41
  if not isinstance(d, _Rdict):
38
- raise _RdictError(k=k, d=type(d))
42
+ raise _RsError(k=k, d=type(d))
39
43
  n += d.n
40
44
 
41
45
  ADict.__init__(self, coeffs)
42
46
  self.set_(ALorder=ALorder, n=n) # in .validate
43
47
  except Exception as x:
44
- raise _RdictError(ALorder=ALorder, cause=x)
48
+ raise _RsError(ALorder=ALorder, cause=x)
45
49
 
46
50
  def bnuz4(self): # in .auxilats.__main__ # PYCHOK no cover
47
51
  # get C{(strB, number, unique, floatB)} rationals
@@ -53,8 +57,8 @@ class _Rcoeffs(ADict):
53
57
  t = R._tuple
54
58
  z += _zB(t) # Float
55
59
  # assert R.Rdict is None
56
- n += len(t)
57
- u += sum(1 for f in t if f in _floats)
60
+ n += len(t)
61
+ u += sum(1 for f in t if f in _Cs)
58
62
  return b, n, (n - u), z
59
63
 
60
64
  def items(self): # string-ify keys # PYCHOK no cover
@@ -74,48 +78,48 @@ class _Rcoeffs(ADict):
74
78
  # for R in self._Rtuples():
75
79
  # assert isinstance(R, _Rtuple)
76
80
  if aL != a or lenAux != n:
77
- raise _RdictError(aL=aL, ALorder=a, lenAux=lenAux, n=n)
81
+ raise _RsError(aL=aL, ALorder=a, lenAux=lenAux, n=n)
78
82
  return self
79
83
 
80
84
 
81
85
  class _Rdict(dict): # in ._CX_#, .auxLat, .rhumb.aux_
82
86
  '''(INTERNAL) Dict of C{_Rtuple}s.
83
87
  '''
84
- n = 0 # sum(R.k_n_k[1] for r in Rtuples)
88
+ n = 0 # sum(R.k_n_k[1] for R in Rtuples)
85
89
 
86
90
  def __init__(self, nt, *Rtuples):
87
91
  '''New C{_Rdict}.
88
92
  '''
89
93
  if not Rtuples:
90
- raise _RdictError(Rtuples=MISSING)
94
+ raise _RsError(Rtuples=MISSING)
91
95
 
92
96
  for R in Rtuples:
93
97
  if not isinstance(R, _Rtuple):
94
- raise _RdictError(R, R=type(R))
98
+ raise _RsError(R, R=type(R))
95
99
  k, n, _ = R.k_n_rs
96
100
  if k in self:
97
- raise _RdictError(_duplicate_, k=k)
101
+ raise _RsError(_duplicate_, k=k)
98
102
  R.Rdict = self
99
103
  self[k] = R # overwritten in self._floatuple
100
104
  self.n += n
101
105
  if self.n != nt:
102
- raise _RdictError(n=n, nt=nt)
106
+ raise _RsError(n=n, nt=nt)
103
107
 
104
108
  def _floats(self, rs):
105
109
  # yield floats from a string of comma-separated rationals
106
110
  def _p_q(p=NN, q=1, *x):
107
111
  return (NN if x else p), q
108
112
 
109
- _get = _floats.get
110
- for r in NN(*rs.split()).split(_COMMA_):
113
+ _get = _Cs.get
114
+ for r in _MODS.basics._splituple(rs):
111
115
  p, q = _p_q(*r.split(_SLASH_))
112
116
  if p:
113
117
  f = int(p) / int(q) # fractions.Fraction?
114
118
  if not isinstance(f, float):
115
- raise _RdictError(rs, f=f, p=p, q=q, r=r)
116
- yield _get(f, f) # from .constants?
119
+ raise _RsError(rs, f=f, p=p, q=q, r=r)
120
+ yield _get(f, f) # from .constants
117
121
  else:
118
- raise _RdictError(rs, r=r)
122
+ raise _RsError(rs, r=r)
119
123
 
120
124
  def _floatuple(self, Rtuple):
121
125
  # return a tuple of floats from an C{_Rtuple}
@@ -125,13 +129,24 @@ class _Rdict(dict): # in ._CX_#, .auxLat, .rhumb.aux_
125
129
  # @see: <https://StackOverflow.com/questions/10632839/>
126
130
  # and <https://realPython.com/python-flatten-list/>
127
131
  if len(t) != n:
128
- raise _RdictError(*rs, len=len(t), n=n)
129
- self[k] = t
132
+ raise _RsError(*rs, len=len(t), n=n)
133
+ self[k] = t # replace _Rtuple with tuple instance
130
134
  return t
131
135
 
132
136
 
133
- class _RdictError(_AssertionError):
134
- '''(INTERNAL) For C{_Rdict} issues.
137
+ class _Rkey(int):
138
+ '''(INTERNAL) For C{_Rcoeffs}, C{_Rdict} and C{_Rtuple} keys.
139
+ '''
140
+ def __new__(cls, k):
141
+ if not isinstance(k, int):
142
+ raise _RsError(k=type(k))
143
+ if not 0 <= k <= 8: # 0.._MODS.auxilats.auxily.Aux.N + 2
144
+ raise _RsError(k=k)
145
+ return int.__new__(cls, k)
146
+
147
+
148
+ class _RsError(_AssertionError):
149
+ '''(INTERNAL) For C{_Rcoeffs}, C{_Rdict or} C{_Rtuple} issues.
135
150
  '''
136
151
  def __init__(self, *rs, **kwds_cause): # PYCHOK no cover
137
152
  if rs:
@@ -147,7 +162,7 @@ class _RdictError(_AssertionError):
147
162
  class _Rtuple(list): # MUST be list, NOT tuple!
148
163
  '''(INTERNAL) I{Pseudo-tuple} of float rationals used in C{_Rdict}s.
149
164
  '''
150
- Rdict = None
165
+ Rdict = None # set by _Rdict.__init__
151
166
  k_n_rs = None, 0, ()
152
167
 
153
168
  def __init__(self, k, n, *rs):
@@ -156,20 +171,26 @@ class _Rtuple(list): # MUST be list, NOT tuple!
156
171
  where C{p} and C{q} are C{int} digits only.
157
172
  '''
158
173
  try:
174
+ if not isinstance(k, _Rkey):
175
+ raise _RsError(k=type(k))
176
+ if not (isinstance(n, int) and n > 0):
177
+ raise _RsError(n=type(n))
159
178
  if not rs:
160
- raise _RdictError(rs=MISSING)
179
+ raise _RsError(rs=MISSING)
161
180
  for t in rs:
162
181
  if not isinstance(t, str):
163
- raise _RdictError(rs=type(t))
164
- if not (isinstance(n, int) and n > 0):
165
- raise _RdictError(n=type(n))
182
+ raise _RsError(rs=type(t))
166
183
  self.k_n_rs = k, n, rs
167
184
  except Exception as x:
168
- raise _RdictError(*rs, k=k, n=n, cause=x)
185
+ raise _RsError(*rs, k=k, n=n, cause=x)
169
186
 
170
187
  def __getitem__(self, i):
171
188
  return self._tuple[i]
172
189
 
190
+ if _MODS.sys_version_info2 < (3, 0):
191
+ def __getslice__(self, i, j):
192
+ return self._tuple[slice(i, j)]
193
+
173
194
  def __iter__(self):
174
195
  return iter(self._tuple)
175
196
 
@@ -178,26 +199,24 @@ class _Rtuple(list): # MUST be list, NOT tuple!
178
199
 
179
200
  @Property_RO
180
201
  def _tuple(self):
181
- # build the C{tuple} once, replace C{_Rdict}
182
- # item at C{key} with the C{tuple} and fill
183
- # this C{_Rlist} with the C{tuple} values
184
- # for the initial __getitem__ retrieval[s]
202
+ # build the C{tuple} I{once} and replace
203
+ # C{_Rdict[key]} item with the C{tuple}
185
204
  try:
186
- k, n, rs = self.k_n_rs
205
+ k, n, rs = self.k_n_rs # for except ...
187
206
  t = self.Rdict._floatuple(self)
188
- self[:] = t # MUST copy into self!
207
+ # self[:] = t # MUST copy into self?
189
208
  except Exception as x:
190
209
  if len(rs) > 1 and _QUOTE3_ in str(x):
191
210
  rs = rs[0], _ELLIPSIS4_
192
- raise _RdictError(k=k, n=n, rs=rs, cause=x)
211
+ raise _RsError(k=k, n=n, rs=rs, cause=x)
193
212
  del self.Rdict, self.k_n_rs # trash refs
194
213
  return t
195
214
 
196
215
  def append(self, arg):
197
- raise _RdictError(append=arg)
216
+ raise _RsError(append=arg)
198
217
 
199
218
  def extend(self, arg):
200
- raise _RdictError(extend=arg)
219
+ raise _RsError(extend=arg)
201
220
 
202
221
  # **) MIT License
203
222
  #
@@ -29,7 +29,7 @@ from pygeodesy.lazily import _ALL_OTHER
29
29
  # no modules: auxAngle, auxDLat, auxDST, auxily, auxLat
30
30
  __all__ = _ALL_OTHER(Aux, AuxAngle, AuxDLat, AuxDST, AuxLat,
31
31
  AuxBeta, AuxChi, AuxMu, AuxPhi, AuxTheta, AuxXi)
32
- __version__ = '24.09.04'
32
+ __version__ = '25.01.15'
33
33
 
34
34
  # **) MIT License
35
35
  #
@@ -5,7 +5,7 @@ u'''Print L{auxilats} version, etc. using C{python -m pygeodesy.auxilats}.
5
5
  '''
6
6
 
7
7
  __all__ = ()
8
- __version__ = '24.09.04'
8
+ __version__ = '25.04.04'
9
9
 
10
10
 
11
11
  def _main(**ALorder): # PYCHOK no cover
@@ -36,7 +36,7 @@ def _main(**ALorder): # PYCHOK no cover
36
36
  print(_usage(__file__))
37
37
 
38
38
 
39
- from sys import argv # .internals._isPyChecker
39
+ from sys import argv # .internals._isPyChOK
40
40
  _main(ALorder=int(argv[1])) if len(argv) == 2 and argv[1].isdigit() else _main()
41
41
 
42
42
  # % python3.12 -m pygeodesy.auxilats 8
@@ -18,7 +18,7 @@ from __future__ import division as _; del _ # PYCHOK semicolon
18
18
  from pygeodesy.auxilats.auxAngle import AuxAngle, AuxBeta, AuxChi, _AuxClass, \
19
19
  AuxMu, AuxPhi, AuxTheta, AuxXi
20
20
  from pygeodesy.auxilats.auxily import Aux, _sc, _sn
21
- from pygeodesy.auxilats._CX_Rs import _Rdict, _Rtuple
21
+ from pygeodesy.auxilats._CX_Rs import _Rdict, _Rkey, _Rtuple
22
22
  from pygeodesy.basics import _reverange, _xinstanceof, _passarg
23
23
  from pygeodesy.constants import INF, MAX_EXP, MIN_EXP, NAN, PI_2, PI_4, _EPSqrt, \
24
24
  _0_0, _0_0s, _0_1, _0_5, _1_0, _2_0, _3_0, _360_0, \
@@ -48,7 +48,7 @@ except ImportError: # Python 3.11-
48
48
  return pow(_2_0, x)
49
49
 
50
50
  __all__ = ()
51
- __version__ = '24.09.03'
51
+ __version__ = '25.01.15'
52
52
 
53
53
  _TRIPS = 1024 # XXX 2 or 3?
54
54
 
@@ -829,16 +829,16 @@ def _Newton(tphi, Zeta, _toZeta, **name):
829
829
 
830
830
 
831
831
  _AR2Coeffs = _Rdict(18,
832
- _Rtuple(4, 4, '4/315, 4/105, 4/15, -1/3'),
833
- _Rtuple(6, 6, '4/1287, 4/693, 4/15, 4/105, 4/315, -1/3'),
834
- _Rtuple(8, 8, '4/3315, 4/2145, 4/1287, 4/693, 4/315, 4/105, 4/15, -1/3'))
832
+ _Rtuple(_Rkey(4), 4, '4/315, 4/105, 4/15, -1/3'),
833
+ _Rtuple(_Rkey(6), 6, '4/1287, 4/693, 4/15, 4/105, 4/315, -1/3'),
834
+ _Rtuple(_Rkey(8), 8, '4/3315, 4/2145, 4/1287, 4/693, 4/315, 4/105, 4/15, -1/3'))
835
835
 
836
836
  _RRCoeffs = _Rdict(9,
837
- _Rtuple(4, 2, '1/64, 1/4'),
838
- _Rtuple(6, 3, '1/256, 1/64, 1/4'),
839
- _Rtuple(8, 4, '25/16384, 1/256, 1/64, 1/4')) # PYCHOK used!
837
+ _Rtuple(_Rkey(4), 2, '1/64, 1/4'),
838
+ _Rtuple(_Rkey(6), 3, '1/256, 1/64, 1/4'),
839
+ _Rtuple(_Rkey(8), 4, '25/16384, 1/256, 1/64, 1/4')) # PYCHOK used!
840
840
 
841
- del _Rdict, _Rtuple
841
+ del _Rdict, _Rkey, _Rtuple
842
842
  # assert set(_AR2Coeffs.keys()) == set(_RRCoeffs.keys())
843
843
 
844
844
  # AuxLat._Lmax = max(_AR2Coeffs.keys()) # == max(ALorder)
@@ -15,6 +15,7 @@ under the MIT/X11 License. For more information, see the U{GeographicLib
15
15
  from __future__ import division as _; del _ # PYCHOK semicolon
16
16
 
17
17
  # from pygeodesy import auxilats # _MODS
18
+ from pygeodesy.auxilats._CX_Rs import _Rkey
18
19
  from pygeodesy.constants import INF, NAN, isinf, isnan, _0_0, _0_5, _1_0, \
19
20
  _copysign_1_0, _over, _1_over
20
21
  from pygeodesy.errors import AuxError
@@ -26,19 +27,19 @@ from pygeodesy.utily import atan1
26
27
  from math import asinh, copysign
27
28
 
28
29
  __all__ = ()
29
- __version__ = '24.09.03'
30
+ __version__ = '25.01.15'
30
31
 
31
32
 
32
33
  class Aux(object):
33
34
  '''Enum-style Aux names.
34
35
  '''
35
36
  _coeffs = {}
36
- GEOGRAPHIC = PHI = GEODETIC = 0
37
- PARAMETRIC = BETA = REDUCED = 1
38
- GEOCENTRIC = THETA = 2 # all ...
39
- RECTIFYING = MU = 3 # use n^2
40
- CONFORMAL = CHI = 4 # use n
41
- AUTHALIC = XI = 5 # use n
37
+ GEOGRAPHIC = PHI = GEODETIC = _Rkey(0)
38
+ PARAMETRIC = BETA = REDUCED = _Rkey(1)
39
+ GEOCENTRIC = THETA = _Rkey(2) # all ...
40
+ RECTIFYING = MU = _Rkey(3) # use n^2
41
+ CONFORMAL = CHI = _Rkey(4) # use n
42
+ AUTHALIC = XI = _Rkey(5) # use n
42
43
  N = 6
43
44
  N2 = 36
44
45
 
@@ -228,6 +229,7 @@ def _sn(tx):
228
229
 
229
230
 
230
231
  __all__ += _ALL_DOCS(Aux.__class__)
232
+ del _Rkey
231
233
 
232
234
  # **) MIT License
233
235
  #
pygeodesy/basics.py CHANGED
@@ -37,7 +37,7 @@ from math import copysign as _copysign
37
37
  # import inspect as _inspect # _MODS
38
38
 
39
39
  __all__ = _ALL_LAZY.basics
40
- __version__ = '24.12.31'
40
+ __version__ = '25.01.17'
41
41
 
42
42
  _below_ = 'below'
43
43
  _list_tuple_types = (list, tuple)
@@ -207,6 +207,22 @@ def _enumereverse(iterable):
207
207
  yield j, iterable[j]
208
208
 
209
209
 
210
+ try:
211
+ from math import gcd as _gcd
212
+ except ImportError: # 3.4-
213
+
214
+ def _gcd(a, b): # PYCHOK redef
215
+ # <https://WikiPedia.org/wiki/Greatest_common_divisor>
216
+ a, b = int(a), int(b)
217
+ if b > a:
218
+ a, b = b, a
219
+ # if b <= 0:
220
+ # return 1
221
+ while b:
222
+ a, b = b, (a % b)
223
+ return a
224
+
225
+
210
226
  def halfs2(str2):
211
227
  '''Split a string in 2 halfs.
212
228
 
@@ -222,6 +238,15 @@ def halfs2(str2):
222
238
  return str2[:h], str2[h:]
223
239
 
224
240
 
241
+ def _integer_ratio2(x): # PYCHOK no cover
242
+ '''(INTERNAL) Return C{B{x}.as_interger_ratio()}.
243
+ '''
244
+ try: # int.as_integer_ratio in 3.8+
245
+ return x.as_integer_ratio()
246
+ except (AttributeError, OverflowError, TypeError, ValueError):
247
+ return (x if isint(x) else float(x)), 1
248
+
249
+
225
250
  def int1s(x): # PYCHOK no cover
226
251
  '''Count the number of 1-bits in an C{int}, I{unsigned}.
227
252
 
@@ -371,7 +396,7 @@ def isiterable(obj, strict=False):
371
396
  @return: C{True} if C{iterable}, C{False} otherwise.
372
397
  '''
373
398
  # <https://PyPI.org/project/isiterable/>
374
- return isiterabletype(obj) if strict else hasattr(obj, '__iter__') # map, range, set
399
+ return bool(isiterabletype(obj)) if strict else hasattr(obj, '__iter__') # map, range, set
375
400
 
376
401
 
377
402
  def isiterablen(obj, strict=False):
@@ -383,7 +408,7 @@ def isiterablen(obj, strict=False):
383
408
  @return: C{True} if C{iterable} with C{len}gth, C{False} otherwise.
384
409
  '''
385
410
  _has = isiterabletype if strict else hasattr
386
- return _has(obj, '__len__') and _has(obj, '__getitem__')
411
+ return bool(_has(obj, '__len__') and _has(obj, '__getitem__'))
387
412
 
388
413
 
389
414
  def isiterabletype(obj, method='__iter__'):
@@ -763,9 +788,13 @@ def _splituple(strs, *sep_splits): # in .mgrs, ...
763
788
  '''(INTERNAL) Split a C{comma}- or C{whitespace}-separated
764
789
  string into a C{tuple} of stripped C{str}ings.
765
790
  '''
766
- t = (strs.split(*sep_splits) if sep_splits else
767
- strs.replace(_COMMA_, _SPACE_).split()) if strs else ()
768
- return tuple(s.strip() for s in t if s)
791
+ if sep_splits:
792
+ t = (t.strip() for t in strs.split(*sep_splits))
793
+ else:
794
+ t = strs.strip()
795
+ if t:
796
+ t = t.replace(_COMMA_, _SPACE_).split()
797
+ return tuple(t) if t else ()
769
798
 
770
799
 
771
800
  def unsigned0(x):
pygeodesy/etm.py CHANGED
@@ -93,7 +93,7 @@ from pygeodesy.utm import _cmlon, _LLEB, _parseUTM5, _toBand, _toXtm8, \
93
93
  from math import asinh, degrees, radians, sinh, sqrt
94
94
 
95
95
  __all__ = _ALL_LAZY.etm
96
- __version__ = '24.11.24'
96
+ __version__ = '25.01.12'
97
97
 
98
98
  _OVERFLOW = _1_EPS**2 # ~2e+31
99
99
  _TAYTOL = pow(EPS, 0.6)
@@ -196,7 +196,7 @@ class Etm(Utm):
196
196
  def _toLLEB(self, unfalse=True, **unused): # PYCHOK signature
197
197
  '''(INTERNAL) Compute (ellipsoidal) lat- and longitude.
198
198
  '''
199
- xTM, d = self.exactTM, self.datum
199
+ d, xTM = self.datum, self.exactTM
200
200
  # double check that this and exactTM's ellipsoid match
201
201
  if xTM._E != d.ellipsoid: # PYCHOK no cover
202
202
  t = repr(d.ellipsoid)
@@ -1022,7 +1022,7 @@ class ExactTransverseMercator(_NamedBase):
1022
1022
  g_k += atan1d(tau), degrees(lam)
1023
1023
  return g_k # or (g, k, lat, lon)
1024
1024
 
1025
- _allPropertiesOf_n(22, ExactTransverseMercator, Property_RO) # PYCHOK assert
1025
+ _allPropertiesOf_n(22, ExactTransverseMercator, Property_RO) # PYCHOK assert _ROs = ...
1026
1026
  del _0_1, _allPropertiesOf_n, EPS, _1_EPS, _EWGS84
1027
1027
 
1028
1028
 
pygeodesy/fmath.py CHANGED
@@ -23,7 +23,7 @@ from math import fabs, sqrt # pow
23
23
  import operator as _operator # in .datums, .trf, .utm
24
24
 
25
25
  __all__ = _ALL_LAZY.fmath
26
- __version__ = '24.12.31'
26
+ __version__ = '25.01.09'
27
27
 
28
28
  # sqrt(2) - 1 <https://WikiPedia.org/wiki/Square_root_of_2>
29
29
  _0_4142 = 0.41421356237309504880 # ... ~ 3730904090310553 / 9007199254740992
@@ -981,7 +981,7 @@ def _root(x, p, where):
981
981
  raise ValueError(_negative_)
982
982
  except Exception as X:
983
983
  raise _xError(X, unstr(where, x))
984
- return _0_0
984
+ return _0_0 if p else _1_0
985
985
 
986
986
 
987
987
  def sqrt0(x, Error=None):