pygeodesy 24.8.24__py2.py3-none-any.whl → 24.9.9__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/internals.py CHANGED
@@ -207,6 +207,13 @@ class _MODS_Base(object):
207
207
  l3.insert(0, pypy)
208
208
  return l3
209
209
 
210
+ @_Property_RO
211
+ def _Str_Bytes(self):
212
+ '''Get all C{str} and C{bytes} types.
213
+ '''
214
+ import pygeodesy.basics as m
215
+ return m._Strs + m._Bytes # + (range, map)
216
+
210
217
  @_Property_RO
211
218
  def streprs(self):
212
219
  '''Get module C{pygeodesy.streprs}, I{once}.
@@ -254,6 +261,12 @@ def _enquote(strs, quote=_QUOTE2_, white=NN): # in .basics, .solveBase
254
261
  return strs
255
262
 
256
263
 
264
+ def _fper(p, q, per=100.0, prec=1):
265
+ '''Format a percentage C{B{p} * B{per} / B{q}} (C{str}).
266
+ '''
267
+ return '%.*f%%' % (prec, (float(p) * per / float(q)))
268
+
269
+
257
270
  def _headof(name):
258
271
  '''(INTERNAL) Get the head name of qualified C{name} or the C{name}.
259
272
  '''
@@ -292,6 +305,13 @@ def _isNix(): # in test/bases.py
292
305
  return _MODS.nix2[0]
293
306
 
294
307
 
308
+ def _isPyChecker():
309
+ '''(INTERNAL) Is C{PyChecker} running? (C{bool}).
310
+ '''
311
+ # .../pychecker/checker.py --limit 0 --stdlib pygeodesy/<mod>/<name>.py
312
+ return _sys.argv[0].endswith('/pychecker/checker.py')
313
+
314
+
295
315
  def _isPyPy(): # in test/bases.py
296
316
  '''(INTERNAL) Is this C{PyPy}? (C{bool})
297
317
  '''
@@ -343,12 +363,30 @@ def machine():
343
363
  return _MODS.bits_machine2[1]
344
364
 
345
365
 
366
+ def _Math_K_2():
367
+ '''(INTERNAL) Return the I{Karney} Math setting.
368
+ '''
369
+ return _MODS.karney._wrapped.Math_K_2
370
+
371
+
346
372
  def _name_version(pkg):
347
373
  '''(INTERNAL) Return C{pskg.__name__ + ' ' + .__version__}.
348
374
  '''
349
375
  return _SPACE_(pkg.__name__, pkg.__version__)
350
376
 
351
377
 
378
+ def _name_binary(path):
379
+ '''(INTERNAL) Return C{(basename + ' ' + version)} of an executable.
380
+ '''
381
+ if path:
382
+ try:
383
+ _, r = _MODS.solveBase._popen2((path, '--version'))
384
+ return _SPACE_(_os_path.basename(path), r.split()[-1])
385
+ except (IndexError, IOError, OSError):
386
+ pass
387
+ return NN
388
+
389
+
352
390
  def _osversion2(sep=NN): # in .lazily, test/bases.versions
353
391
  '''(INTERNAL) Get the O/S name and release as C{2-list} or C{str}.
354
392
  '''
@@ -463,15 +501,17 @@ def _secs2str(secs): # in .geoids, ../test/bases.py
463
501
  return t
464
502
 
465
503
 
466
- def _sizeof(obj):
504
+ def _sizeof(obj, deep=True):
467
505
  '''(INTERNAL) Recursively size an C{obj}ect.
468
506
 
469
- @return: The C{obj} size in bytes (C{int}),
470
- ignoring class attributes and
471
- counting duplicates only once or
472
- C{None}.
507
+ @kwarg deep: If C{True}, include the size of all
508
+ C{.__dict__.values()} (C{bool}).
473
509
 
474
- @note: With C{PyPy}, the size is always C{None}.
510
+ @return: The C{obj} size in bytes (C{int}), ignoring
511
+ class attributes and counting instances only
512
+ once or C{None}.
513
+
514
+ @note: With C{PyPy}, the returned size is always C{None}.
475
515
  '''
476
516
  try:
477
517
  _zB = _sys.getsizeof
@@ -491,9 +531,10 @@ def _sizeof(obj):
491
531
  if isinstance(o, dict):
492
532
  z += _zR(s, o.keys())
493
533
  z += _zR(s, o.values())
494
- elif _isiterablen(o): # not map, ...
534
+ elif _isiterablen(o) and not \
535
+ isinstance(o, _MODS._Str_Bytes):
495
536
  z += _zR(s, o)
496
- else:
537
+ elif deep:
497
538
  try: # size instance' attr values only
498
539
  z += _zR(s, o.__dict__.values())
499
540
  except AttributeError: # None, int, etc.
@@ -611,7 +652,7 @@ def _versions(sep=_SPACE_):
611
652
 
612
653
 
613
654
  __all__ = tuple(map(_dunder_nameof, (machine, print_, printf)))
614
- __version__ = '24.08.24'
655
+ __version__ = '24.09.04'
615
656
 
616
657
  if _dunder_ismain(__name__): # PYCHOK no cover
617
658
 
pygeodesy/interns.py CHANGED
@@ -200,6 +200,7 @@ _distant_ = _Prefix('distant') # PYCHOK OK
200
200
  _doesn_t_exist_ = "doesn't exist" # PYCHOK OK
201
201
  _DOT_ = Str_('.') # PYCHOK OK
202
202
  _dunder_name_ = '__name__' # PYCHOK _DUNDER_(NN, _name_, NN)
203
+ _duplicate_ = 'duplicate' # PYCHOK OK
203
204
  _e_ = 'e' # PYCHOK OK
204
205
  _E_ = 'E' # PYCHOK OK
205
206
  _earth_ = 'earth' # PYCHOK OK
@@ -347,7 +348,7 @@ _Python_ = _Python_('Python') # PYCHOK singleton
347
348
  _python_ = 'python' # PYCHOK OK
348
349
  _QUOTE1_ = "'" # PYCHOK OK
349
350
  _QUOTE2_ = '"' # PYCHOK OK
350
- # _QUOTE3_ = "'''" # PYCHOK OK
351
+ _QUOTE3_ = "'''" # PYCHOK OK
351
352
  # _QUOTE6_ = '"""' # PYCHOK OK
352
353
  _R_ = 'R' # PYCHOK OK
353
354
  _radians_ = 'radians' # PYCHOK OK
@@ -440,7 +441,7 @@ _LR_PAIRS = {_LANGLE_: _RANGLE_,
440
441
 
441
442
  __all__ = (_NN_, # NOT MISSING!
442
443
  Str_.__name__) # classes
443
- __version__ = '24.08.22'
444
+ __version__ = '24.08.30'
444
445
 
445
446
  if __name__ == '__main__':
446
447
 
pygeodesy/karney.py CHANGED
@@ -10,7 +10,9 @@ C{attribute} name.
10
10
 
11
11
  With env variable C{PYGEODESY_GEOGRAPHICLIB} left undefined or set to C{"2"}, modules L{geodesicw},
12
12
  L{geodesicx} and this module will use U{GeographicLib 2.0+<https://GeographicLib.SourceForge.io/C++/doc/>}
13
- and newer transcoding, otherwise C{1.52} or older.
13
+ and newer transcoding, otherwise C{1.52} or older. Set C{PYGEODESY_GEOGRAPHICLIB=2.4} to default to the
14
+ C{Jacobi amplitude} instead of C{Bulirsch}' function in methods L{ExactTransverseMercator.forward
15
+ <pygeodesy.ExactTransverseMercator.forward>} and L{reverse <pygeodesy.ExactTransverseMercator.reverse>}.
14
16
 
15
17
  Karney-based functionality
16
18
  ==========================
@@ -145,8 +147,8 @@ from pygeodesy.basics import _copysign, isint, neg, unsigned0, _xgeographiclib,
145
147
  _zip, _version_info
146
148
  from pygeodesy.constants import NAN, _isfinite as _math_isfinite, _0_0, \
147
149
  _1_16th, _1_0, _2_0, _180_0, _N_180_0, _360_0
148
- from pygeodesy.errors import GeodesicError, _ValueError, _xkwds, _xkwds_get1
149
- from pygeodesy.fmath import cbrt, fremainder, norm2
150
+ from pygeodesy.errors import GeodesicError, _ValueError, _xkwds
151
+ from pygeodesy.fmath import cbrt, fremainder, norm2 # Fhorner, Fsum
150
152
  # from pygeodesy.internals import _version_info # from .basics
151
153
  from pygeodesy.interns import NN, _2_, _a12_, _area_, _azi1_, _azi2_, _azi12_, \
152
154
  _composite_, _lat1_, _lat2_, _lon1_, _lon2_, \
@@ -154,7 +156,8 @@ from pygeodesy.interns import NN, _2_, _a12_, _area_, _azi1_, _azi2_, _azi12_, \
154
156
  _UNDER_, _X_, _BAR_ # PYCHOK used!
155
157
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _getenv
156
158
  from pygeodesy.named import ADict, _NamedBase, _NamedTuple, notImplemented, _Pass
157
- from pygeodesy.props import deprecated_method, Property_RO, property_ROnce
159
+ from pygeodesy.props import deprecated_method, Property_RO, property_RO, \
160
+ property_ROnce
158
161
  from pygeodesy.units import Azimuth as _Azi, Degrees as _Deg, Lat, Lon, \
159
162
  Meter as _M, Meter2 as _M2, Number_
160
163
  from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
@@ -162,9 +165,11 @@ from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
162
165
  # from math import fabs # from .utily
163
166
 
164
167
  __all__ = _ALL_LAZY.karney
165
- __version__ = '24.07.25'
168
+ __version__ = '24.09.10'
166
169
 
167
- _K_2_0 = _getenv('PYGEODESY_GEOGRAPHICLIB', _2_) == _2_
170
+ _K_2_0 = _getenv('PYGEODESY_GEOGRAPHICLIB', _2_)
171
+ _K_2_4 = _K_2_0 == '2.4'
172
+ _K_2_0 = _K_2_0 == _2_ or _K_2_4
168
173
  _perimeter_ = 'perimeter'
169
174
 
170
175
 
@@ -285,7 +290,7 @@ class Caps(object):
285
290
 
286
291
  Caps = Caps() # PYCHOK singleton
287
292
  '''I{Enum}-style masks to be bit-C{or}'ed to specify geodesic or
288
- rhumb capabilities (C{caps}) and expected results (C{outmask}).
293
+ rhumb capabilities (C{caps}) and results (C{outmask}).
289
294
 
290
295
  C{AREA} - compute area C{S12},
291
296
 
@@ -569,6 +574,11 @@ class _kWrapped(object): # in .geodesicw
569
574
  M = None
570
575
  return M
571
576
 
577
+ @property_RO
578
+ def Math_K_2(self):
579
+ return ('_K_2_4' if _K_2_4 else
580
+ ('_K_2_0' if _K_2_0 else '_K_1_0')) if self.Math else NN
581
+
572
582
  _wrapped = _kWrapped() # PYCHOK singleton, .datum, .test/base.py
573
583
 
574
584
 
@@ -805,25 +815,44 @@ def _polygon(geodesic, points, closed, line, wrap):
805
815
  return gP.Compute(False, True)[1 if line else 2]
806
816
 
807
817
 
818
+ try:
819
+ from math import fma as _fma # since 3.13
820
+
821
+ def _poly_fma(x, s, *cs):
822
+ for c in cs:
823
+ s = _fma(s, x, c)
824
+ return s
825
+
826
+ except ImportError: # Python 3.12-
827
+
828
+ def _poly_fma(x, s, *cs): # PYCHOK redef
829
+ t = _0_0
830
+ for c in cs:
831
+ s, t, _ = _sum3(s * x, t * x, c)
832
+ return s + t
833
+
834
+ # def _poly_fma(x, *cs):
835
+ # S = Fhorner(x, *cs, incx=False)
836
+ # return float(S)
837
+
838
+ # def _poly_fma(x, s, *cs): # scalar x, s, cs
839
+ # S = Fsum(s)._fma_scalar(None, x, *cs)
840
+ # return float(S)
841
+
808
842
  def _polynomial(x, cs, i, j): # PYCHOK shared
809
843
  '''(INTERNAL) Like C++ C{GeographicLib.Math.hpp.polyval} but with a
810
- different signature and cascaded summation as C{karney._sum2_}.
844
+ signature and cascaded summation different from C{karney._sum3}.
811
845
 
812
- @return: M{sum(cs[k] * x**(j - k - 1) for k in range(i, j)}
846
+ @return: M{sum(x**(j - k - 1) * cs[k] for k in range(i, j)}
813
847
  '''
814
- # assert 0 <= i <= j <= len(cs)
815
- # try:
816
- # return _wrapped.Math.polyval(j - i - 1, cs, i, x)
817
- # except AttributeError:
818
- # s, t = cs[i], _0_0
819
- # for c in cs[i+1:j]:
820
- # s, t = _sum2_(s * x, t * x, c)
821
- # return s # + t
822
- s = cs[i]
823
- i += 1
824
- if x and i < j:
825
- s, _ = _sum2_(s, _0_0, x=x, *cs[i:j])
826
- return s # + t
848
+ if (i + 1) < j <= len(cs): # load _Rtuple._tuple
849
+ try:
850
+ r = _wrapped.Math.polyval(j - i - 1, cs, i, x)
851
+ except AttributeError:
852
+ r = _poly_fma(x, *cs[i:j])
853
+ else:
854
+ r = cs[i]
855
+ return float(r)
827
856
 
828
857
 
829
858
  def _remainder(x, y):
@@ -875,67 +904,60 @@ def _sincos2de(deg, t):
875
904
  return sincos2d(deg, adeg=t)
876
905
 
877
906
 
878
- def _sum2(u, v): # mimick geomath.Math.sum, actually sum2
907
+ def _sum2(a, b): # mimick geomath.Math.sum, actually sum2
879
908
  '''Error-free summation like C{geomath.Math.sum}.
880
909
 
881
- @return: 2-Tuple C{(B{u} + B{v}, residual)}.
910
+ @return: 2-Tuple C{(B{a} + B{b}, residual)}.
882
911
 
883
- @note: The C{residual} can be the same as B{C{u}} or B{C{v}}.
912
+ @note: The C{residual} can be the same as B{C{a}} or B{C{b}}.
884
913
 
885
- @see: U{Algorithm 3.1<https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}.
914
+ @see: U{TwoSum<https://accurate-algorithms.readthedocs.io/en/latest/ch04summation.html>}
915
+ and I{Knuth}'s U{Algorithm 3.1<https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}.
886
916
  '''
887
917
  try:
888
- return _wrapped.Math.sum(u, v)
918
+ return _wrapped.Math.sum(a, b)
889
919
  except AttributeError:
890
- s = u + v
891
- r = s - v
892
- t = s - r
893
920
  # if Algorithm_3_1:
894
- # t = (u - t) + (v + r)
921
+ s = a + b
922
+ r = s - b
923
+ t = s - r
895
924
  # elif C_CPP: # Math::sum C/C++
896
- # r -= u
897
- # t -= v
898
- # t += r
899
- # t = -t
925
+ # r -= a; t -= b; t += r; t = -t
900
926
  # else:
901
- t = (u - r) + (v - t)
927
+ t = (a - r) + (b - t)
928
+ # assert fabs(s) >= fabs(t)
902
929
  return s, t
903
930
 
904
931
 
905
- def _sum2_(s, t, *vs, **x):
906
- '''Accumulate any B{C{vs}} into a previous C{_sum2(s, t)}.
907
-
908
- @kwarg x: Optional polynomial C{B{x}=1} (C{scalar}).
932
+ def _sum3(s, t, *xs):
933
+ '''Accumulate any B{C{xs}} into a previous C{_sum2(s, t)}.
909
934
 
910
- @return: 2-Tuple C{(B{s} + B{t} + sum(B{vs}), residual)}.
935
+ @return: 3-Tuple C{(s, t, n)} where C{s} is the sum of B{s}, B{t} and all
936
+ B{xs}, C{t} the residual and C{n} the number of zero C{xs}.
911
937
 
912
938
  @see: I{Karney's} C++ U{Accumulator<https://GeographicLib.SourceForge.io/
913
939
  C++/doc/Accumulator_8hpp_source.html>} comments for more details and
914
940
  function C{_sum2} above.
915
941
 
916
- @note: NOT "error-free", see C{pygeodesy.test/testKarney.py}.
942
+ @note: Not "error-free", see C{pygeodesy.test/testKarney.py}.
917
943
  '''
918
- x = _xkwds_get1(x, x=_1_0)
919
- p = x != _1_0
920
-
921
- _s2, _u0 = _sum2, unsigned0
922
- for v in vs:
923
- if p:
924
- s *= x
925
- t *= x
926
- if v:
927
- t, u = _s2(t, v) # start at the least-
944
+ z = 0
945
+ for x in xs:
946
+ if x:
947
+ t, r = _sum2(t, x) # start at the least-
928
948
  if s:
929
- s, t = _s2(s, t) # significant end
949
+ s, t = _sum2(s, t) # -significant end
930
950
  if s:
931
- t += u # accumulate u into t
932
- # elif t: # s == 0 implies t == 0
933
- # raise _AssertionError(t=t, txt_not_=_0_)
951
+ t += r # accumulate r into t
934
952
  else:
935
- s = _u0(u) # result is u, t = 0
953
+ # assert t == 0 # s == 0 implies t == 0
954
+ s = unsigned0(r) # result is r, t = 0
936
955
  else:
937
- s, t = _u0(t), u
938
- return s, t
956
+ s, t = unsigned0(t), r
957
+ else:
958
+ z += 1
959
+ # assert fabs(s) >= fabs(t)
960
+ return s, t, z
939
961
 
940
962
 
941
963
  def _tand(x):
@@ -955,7 +977,8 @@ def _unroll2(lon1, lon2, wrap=False): # see .ellipsoidalBaseDI._intersects2
955
977
  '''
956
978
  if wrap:
957
979
  d, t = _diff182(lon1, lon2)
958
- lon2, _ = _sum2_(d, t, lon1) # (lon1 + d) + t
980
+ lon2, t, _ = _sum3(d, t, lon1) # (lon1 + d) + t
981
+ lon2 += t
959
982
  else:
960
983
  lon2 = _norm180(lon2)
961
984
  return (lon2 - lon1), lon2
pygeodesy/ktm.py CHANGED
@@ -67,7 +67,7 @@ from cmath import polar
67
67
  from math import atan2, asinh, cos, cosh, degrees, fabs, sin, sinh, sqrt, tanh
68
68
 
69
69
  __all__ = _ALL_LAZY.ktm
70
- __version__ = '24.07.16'
70
+ __version__ = '24.08.31'
71
71
 
72
72
 
73
73
  class KTMError(_ValueError):
@@ -505,11 +505,11 @@ def _Xs(_Coeffs, m, E, RA=False): # in .rhumb.ekx
505
505
  # constant, it cancels when evaluating a definite
506
506
  # integral. Don't bother computing it, it is unused
507
507
  # in C{_Cyxgk4} above and C{rhumb.ekx._sincosSeries}.
508
- _X, _p = X.append, _polynomial
509
- i = (m + 2) if RA else 0
508
+ i = (m + 2) if RA else 0
509
+ _p = _polynomial
510
510
  for r in _reverange(m): # [m-1 ... 0]
511
511
  j = i + r + 1
512
- _X(_p(n, Cs, i, j) * n_ / Cs[j])
512
+ X.append(_p(n, Cs, i, j) * n_ / Cs[j])
513
513
  i = j + 1
514
514
  n_ *= n
515
515
  X = tuple(X)
pygeodesy/lazily.py CHANGED
@@ -255,7 +255,7 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
255
255
  fmath=_i('Fdot', 'Fhorner', 'Fhypot', 'Fpolynomial', 'Fpowers', 'Fcbrt', 'Froot', 'Fsqrt',
256
256
  'bqrt', 'cbrt', 'cbrt2', 'euclid', 'euclid_',
257
257
  'facos1', 'fasin1', 'fatan', 'fatan1', 'fatan2', 'favg',
258
- 'fdot', 'fdot3', 'fmean', 'fmean_', 'fhorner', 'fidw', 'fpolynomial',
258
+ 'fdot', 'fdot3', 'fma', 'fmean', 'fmean_', 'fhorner', 'fidw', 'fpolynomial',
259
259
  'fpowers', 'fprod', 'frandoms', 'frange', 'freduce', 'fremainder',
260
260
  'hypot', 'hypot_', 'hypot1', 'hypot2', 'hypot2_',
261
261
  'norm2', 'norm_', 'sqrt0', 'sqrt3', 'sqrt_a', 'zcrt', 'zqrt'),
@@ -280,7 +280,7 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
280
280
  'FrechetVincentys', 'Frechet6Tuple',
281
281
  'frechet_'),
282
282
  fstats=_i('Fcook', 'Flinear', 'Fwelford'),
283
- fsums=_i('Fsum', 'DivMod2Tuple', 'Fsum2Tuple', 'ResidualError',
283
+ fsums=_i('Fsum', 'Fsum2product', 'DivMod2Tuple', 'Fsum2Tuple', 'ResidualError',
284
284
  'fsum', 'fsum_', 'fsumf_', 'fsum1', 'fsum1_', 'fsum1f_'),
285
285
  gars=_i('Garef', 'GARSError'),
286
286
  geodesici=_i('Intersectool', 'Intersectool5Tuple', 'Intersect7Tuple',
@@ -486,6 +486,11 @@ class _ALL_MODS(_internals._MODS_Base):
486
486
  except KeyError:
487
487
  return _getmodule(name, parent)
488
488
 
489
+ def imported(self, name):
490
+ '''Return module or package C{name} if already imported.
491
+ '''
492
+ return _sys.modules.get(name, None)
493
+
489
494
  def into(self, **mod_dunder_name_):
490
495
  '''Lazily import module C{mod} into module C{_dunder_name_}
491
496
  and set C{_dunder_name_._mod} to module C{mod}, I{once}.
@@ -521,7 +526,7 @@ class _ALL_MODS(_internals._MODS_Base):
521
526
  _internals._MODS = _ALL_MODS = _ALL_MODS() # PYCHOK singleton
522
527
 
523
528
  __all__ = _ALL_LAZY.lazily
524
- __version__ = '24.08.18'
529
+ __version__ = '24.09.09'
525
530
 
526
531
 
527
532
  def _ALL_OTHER(*objs):
pygeodesy/mgrs.py CHANGED
@@ -43,7 +43,7 @@ from pygeodesy.errors import _AssertionError, MGRSError, _parseX, \
43
43
  from pygeodesy.interns import NN, _0_, _A_, _AtoZnoIO_, _band_, _B_, \
44
44
  _COMMASPACE_, _datum_, _easting_, _invalid_, \
45
45
  _northing_, _SPACE_, _W_, _Y_, _Z_, _zone_
46
- from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _PYGEODESY_GEOCONVERT_
46
+ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
47
47
  from pygeodesy.named import _name2__, _NamedBase, _NamedTuple, _Pass
48
48
  from pygeodesy.namedTuples import EasNor2Tuple, UtmUps5Tuple
49
49
  from pygeodesy.props import deprecated_property_RO, property_RO, Property_RO
@@ -55,7 +55,7 @@ from pygeodesy.utm import toUtm8, _to3zBlat, Utm, _UTM_ZONE_MAX, _UTM_ZONE_MIN
55
55
  # from pygeodesy.utmupsBase import _UTM_ZONE_MAX, _UTM_ZONE_MIN # from .utm
56
56
 
57
57
  __all__ = _ALL_LAZY.mgrs
58
- __version__ = '24.06.11'
58
+ __version__ = '24.09.04'
59
59
 
60
60
  _AN_ = 'AN' # default south pole grid tile and band B
61
61
  _AtoPx_ = _AtoZnoIO_.tillP
@@ -652,51 +652,56 @@ def _um100km2(m):
652
652
 
653
653
  if __name__ == '__main__':
654
654
 
655
- from pygeodesy.ellipsoidalVincenty import fabs, LatLon
656
- # from pygeodesy.internals import printf # from .lazily
657
- from pygeodesy.lazily import _getenv, printf
655
+ def _main():
658
656
 
659
- # from math import fabs # from .ellipsoidalVincenty
660
- from os import access as _access, linesep as _NL, X_OK as _X_OK
657
+ from pygeodesy.ellipsoidalVincenty import fabs, LatLon
658
+ from pygeodesy.internals import _fper, printf
659
+ from pygeodesy.lazily import _getenv, _PYGEODESY_GEOCONVERT_
661
660
 
662
- # <https://GeographicLib.sourceforge.io/C++/doc/GeoConvert.1.html>
663
- _GeoConvert = _getenv(_PYGEODESY_GEOCONVERT_, '/opt/local/bin/GeoConvert')
664
- if _access(_GeoConvert, _X_OK):
665
- GC_m = _GeoConvert, '-m' # -m converts latlon to MGRS
666
- printf(' using: %s ...', _SPACE_.join(GC_m))
667
- from pygeodesy.solveBase import _popen2
668
- else:
669
- GC_m = _popen2 = None
661
+ # from math import fabs # from .ellipsoidalVincenty
662
+ from os import access as _access, linesep as _NL, X_OK as _X_OK
670
663
 
671
- e = n = 0
672
- try:
673
- for lat in range(-90, 91, 1):
674
- printf('%6s: lat %s ...', n, lat, end=NN, flush=True)
675
- nl = _NL
676
- for lon in range(-180, 181, 1):
677
- m = LatLon(lat, lon).toMgrs()
678
- if _popen2:
679
- t = '%s %s' % (lat, lon)
680
- g = _popen2(GC_m, stdin=t)[1]
681
- t = m.toStr() # sep=NN
682
- if t != g:
664
+ # <https://GeographicLib.sourceforge.io/C++/doc/GeoConvert.1.html>
665
+ _GeoConvert = _getenv(_PYGEODESY_GEOCONVERT_, '/opt/local/bin/GeoConvert')
666
+ if _access(_GeoConvert, _X_OK):
667
+ GC_m = _GeoConvert, '-m' # -m converts latlon to MGRS
668
+ printf(' using: %s ...', _SPACE_.join(GC_m))
669
+ from pygeodesy.solveBase import _popen2
670
+ else:
671
+ GC_m = _popen2 = None
672
+
673
+ e = n = 0
674
+ try:
675
+ for lat in range(-90, 91, 1):
676
+ printf('%6s: lat %s ...', n, lat, end=NN, flush=True)
677
+ nl = _NL
678
+ for lon in range(-180, 181, 1):
679
+ m = LatLon(lat, lon).toMgrs()
680
+ if _popen2:
681
+ t = '%s %s' % (lat, lon)
682
+ g = _popen2(GC_m, stdin=t)[1]
683
+ t = m.toStr() # sep=NN
684
+ if t != g:
685
+ e += 1
686
+ printf('%s%6s: %s: %r vs %r (lon %s)', nl, -e, m, t, g, lon)
687
+ nl = NN
688
+ t = m.toLatLon(LatLon=LatLon)
689
+ d = max(fabs(t.lat - lat), fabs(t.lon - lon))
690
+ if d > 1e-9 and -90 < lat < 90 and -180 < lon < 180:
683
691
  e += 1
684
- printf('%s%6s: %s: %r vs %r (lon %s)', nl, -e, m, t, g, lon)
692
+ printf('%s%6s: %s: %s vs %s %.6e', nl, -e, m, t.latlon,
693
+ (float(lat), float(lon)), d)
685
694
  nl = NN
686
- t = m.toLatLon(LatLon=LatLon)
687
- d = max(fabs(t.lat - lat), fabs(t.lon - lon))
688
- if d > 1e-9 and -90 < lat < 90 and -180 < lon < 180:
689
- e += 1
690
- printf('%s%6s: %s: %s vs %s %.6e', nl, -e, m, t.latlon, (float(lat), float(lon)), d)
691
- nl = NN
692
- n += 1
693
- if nl:
694
- printf(' OK')
695
- except KeyboardInterrupt:
696
- printf(nl)
697
-
698
- p = e * 100.0 / n
699
- printf('%6s: %s errors (%.2f%%)', n, (e if e else 'no'), p)
695
+ n += 1
696
+ if nl:
697
+ printf(' OK')
698
+ except KeyboardInterrupt:
699
+ printf(nl)
700
+
701
+ printf('%6s: %s errors (%s)', n, (e if e else 'no'), _fper(e, n, prec=2))
702
+
703
+ _main()
704
+
700
705
 
701
706
  # % python3 -m pygeodesy.mgrs
702
707
  # using: /opt/local/bin/GeoConvert -m ...
pygeodesy/named.py CHANGED
@@ -34,7 +34,7 @@ from pygeodesy.streprs import attrs, Fmt, lrstrip, pairs, reprs, unstr
34
34
  # from pygeodesy.units import _toUnit # _MODS
35
35
 
36
36
  __all__ = _ALL_LAZY.named
37
- __version__ = '24.08.13'
37
+ __version__ = '24.09.02'
38
38
 
39
39
  _COMMANL_ = _COMMA_ + _NL_
40
40
  _COMMASPACEDOT_ = _COMMASPACE_ + _DOT_
@@ -891,6 +891,9 @@ class _NamedEnumItem(_NamedBase):
891
891
  raise _AssertionError(t)
892
892
 
893
893
 
894
+ # from pygeodesy.props import _NamedProperty
895
+
896
+
894
897
  class _NamedTuple(tuple, _Named):
895
898
  '''(INTERNAL) Base for named C{tuple}s with both index I{and}
896
899
  attribute name access to the items.
pygeodesy/props.py CHANGED
@@ -25,12 +25,11 @@ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, \
25
25
  from functools import wraps as _wraps
26
26
 
27
27
  __all__ = _ALL_LAZY.props
28
- __version__ = '24.07.23'
28
+ __version__ = '24.09.02'
29
29
 
30
30
  _class_ = 'class'
31
31
  _dont_use_ = _DEPRECATED_ + ", don't use."
32
32
  _function_ = 'function'
33
- _get_and_set_ = 'get and set'
34
33
  _has_been_ = 'has been' # PYCHOK used!
35
34
  _method_ = 'method'
36
35
  _not_an_inst_ = _not_(_an_, 'instance')
@@ -396,7 +395,9 @@ class property_ROver(_property_RO___):
396
395
  # No __doc__ on purpose
397
396
 
398
397
  def _fget(self, inst):
399
- '''Get the C{property} value I{once} and overwrite C{self}, this C{property} instance.
398
+ '''Get the C{property} value I{once} and overwrite C{self},
399
+ this C{property} instance in the (super-)class of C{self}
400
+ where this property is define as a L{property_ROver}.
400
401
  '''
401
402
  v = self.method(inst)
402
403
  n = self.name
@@ -411,8 +412,8 @@ class property_ROver(_property_RO___):
411
412
  return v
412
413
 
413
414
 
414
- class _NamedProperty(property):
415
- '''Class C{property} with retrievable name.
415
+ class _NamedProperty(property): # in .named
416
+ '''Class C{property} with a C{.name} attribute.
416
417
  '''
417
418
  @Property_RO
418
419
  def name(self):
@@ -445,7 +446,7 @@ def property_doc_(doc):
445
446
  def _documented_property(method):
446
447
  '''(INTERNAL) Return the documented C{property}.
447
448
  '''
448
- t = _get_and_set_ if doc.startswith(_SPACE_) else NN
449
+ t = 'get and set' if doc.startswith(_SPACE_) else NN
449
450
  return _NamedProperty(method, None, None, NN('Property to ', t, doc))
450
451
 
451
452
  return _documented_property
@@ -9,7 +9,7 @@ u'''Package of lazily imported C{rhumb} modules L{rhumb.aux_}, L{rhumb.ekx} and
9
9
  from pygeodesy.lazily import _ALL_LAZY, _ALL_OTHER, _lazy_import_as, _unLazy0
10
10
 
11
11
  __all__ = _ALL_LAZY.rhumb
12
- __version__ = '24.06.18'
12
+ __version__ = '24.09.02'
13
13
 
14
14
  if _unLazy0: # or _isfrozen
15
15
  from pygeodesy.rhumb.aux_ import RhumbAux, RhumbLineAux