pygeodesy 24.10.10__py2.py3-none-any.whl → 24.11.11__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.
Files changed (76) hide show
  1. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/METADATA +12 -12
  2. PyGeodesy-24.11.11.dist-info/RECORD +118 -0
  3. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +14 -14
  5. pygeodesy/__main__.py +5 -5
  6. pygeodesy/albers.py +12 -17
  7. pygeodesy/azimuthal.py +51 -61
  8. pygeodesy/basics.py +60 -62
  9. pygeodesy/booleans.py +87 -79
  10. pygeodesy/cartesianBase.py +6 -6
  11. pygeodesy/constants.py +23 -19
  12. pygeodesy/css.py +7 -8
  13. pygeodesy/datums.py +3 -3
  14. pygeodesy/deprecated/__init__.py +1 -1
  15. pygeodesy/deprecated/classes.py +9 -9
  16. pygeodesy/deprecated/functions.py +6 -6
  17. pygeodesy/dms.py +250 -270
  18. pygeodesy/ecef.py +11 -14
  19. pygeodesy/ellipsoidalBase.py +106 -121
  20. pygeodesy/ellipsoidalBaseDI.py +114 -118
  21. pygeodesy/ellipsoidalExact.py +35 -37
  22. pygeodesy/ellipsoidalNvector.py +4 -4
  23. pygeodesy/ellipsoidalVincenty.py +2 -2
  24. pygeodesy/ellipsoids.py +10 -51
  25. pygeodesy/elliptic.py +14 -14
  26. pygeodesy/errors.py +28 -28
  27. pygeodesy/etm.py +92 -68
  28. pygeodesy/fmath.py +42 -40
  29. pygeodesy/formy.py +7 -6
  30. pygeodesy/fsums.py +72 -51
  31. pygeodesy/geodesici.py +43 -40
  32. pygeodesy/geodesicw.py +17 -16
  33. pygeodesy/geodesicx/__init__.py +2 -2
  34. pygeodesy/geodesicx/gxarea.py +3 -2
  35. pygeodesy/geodsolve.py +79 -39
  36. pygeodesy/geohash.py +2 -2
  37. pygeodesy/geoids.py +32 -31
  38. pygeodesy/heights.py +2 -2
  39. pygeodesy/internals.py +201 -147
  40. pygeodesy/interns.py +23 -20
  41. pygeodesy/karney.py +62 -13
  42. pygeodesy/ktm.py +11 -13
  43. pygeodesy/latlonBase.py +18 -20
  44. pygeodesy/lazily.py +210 -218
  45. pygeodesy/lcc.py +4 -4
  46. pygeodesy/ltp.py +10 -10
  47. pygeodesy/ltpTuples.py +74 -75
  48. pygeodesy/mgrs.py +20 -21
  49. pygeodesy/named.py +15 -10
  50. pygeodesy/nvectorBase.py +1 -1
  51. pygeodesy/osgr.py +9 -12
  52. pygeodesy/points.py +2 -2
  53. pygeodesy/props.py +35 -14
  54. pygeodesy/resections.py +9 -10
  55. pygeodesy/rhumb/__init__.py +1 -1
  56. pygeodesy/rhumb/bases.py +5 -5
  57. pygeodesy/rhumb/solve.py +9 -10
  58. pygeodesy/simplify.py +5 -5
  59. pygeodesy/solveBase.py +7 -25
  60. pygeodesy/sphericalBase.py +20 -23
  61. pygeodesy/sphericalNvector.py +103 -145
  62. pygeodesy/sphericalTrigonometry.py +68 -73
  63. pygeodesy/streprs.py +5 -5
  64. pygeodesy/trf.py +6 -4
  65. pygeodesy/triaxials.py +46 -9
  66. pygeodesy/units.py +5 -4
  67. pygeodesy/ups.py +6 -6
  68. pygeodesy/utily.py +2 -2
  69. pygeodesy/utm.py +7 -7
  70. pygeodesy/vector2d.py +13 -13
  71. pygeodesy/vector3d.py +19 -21
  72. pygeodesy/vector3dBase.py +21 -19
  73. pygeodesy/webmercator.py +4 -4
  74. pygeodesy/wgrs.py +4 -4
  75. PyGeodesy-24.10.10.dist-info/RECORD +0 -118
  76. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/top_level.txt +0 -0
pygeodesy/azimuthal.py CHANGED
@@ -49,7 +49,7 @@ from pygeodesy.ellipsoidalBase import LatLonEllipsoidalBase as _LLEB, \
49
49
  _xinstanceof
50
50
  from pygeodesy.datums import _spherical_datum, _WGS84
51
51
  from pygeodesy.errors import _ValueError, _xdatum, _xkwds
52
- from pygeodesy.fmath import euclid, hypot as _hypot, Fsum
52
+ from pygeodesy.fmath import euclid, fdot_, hypot as _hypot, Fsum
53
53
  # from pygeodesy.fsums import Fsum # from .fmath
54
54
  # from pygeodesy.formy import antipode # _MODS
55
55
  from pygeodesy.interns import _azimuth_, _datum_, _lat_, _lon_, _scale_, \
@@ -70,7 +70,7 @@ from pygeodesy.utily import asin1, atan1, atan2b, atan2d, sincos2, \
70
70
  from math import acos, atan2, degrees, fabs, sin, sqrt
71
71
 
72
72
  __all__ = _ALL_LAZY.azimuthal
73
- __version__ = '24.07.25'
73
+ __version__ = '24.11.07'
74
74
 
75
75
  _EPS_K = _EPStol * _0_1 # Karney's eps_ or _EPSmin * _0_1?
76
76
  _over_horizon_ = 'over horizon'
@@ -154,10 +154,10 @@ class _AzimuthalBase(_NamedBase):
154
154
  s0, c0 = self._sc0
155
155
 
156
156
  cb *= ca
157
- k, t = _k_t_2(s0 * sa + c0 * cb)
157
+ k, t = _k_t_2(fdot_(s0, sa, c0, cb))
158
158
  if t:
159
159
  r = k * self.radius
160
- y = r * (c0 * sa - s0 * cb)
160
+ y = r * fdot_(c0, sa, -s0, cb)
161
161
  e, n, z, _ = _enzh4(r * sb * ca, y, None)
162
162
  else: # 0 or 180
163
163
  e = n = z = _0_0
@@ -233,11 +233,11 @@ class _AzimuthalBase(_NamedBase):
233
233
  Lon_(lon0=lon0, Error=AzimuthalError))
234
234
  self._sc0 = sincos2d(self.lat0)
235
235
 
236
- def reverse(self, x, y, LatLon=None, **name_LatLon_kwds): # PYCHOK no cover
236
+ def reverse(self, x, y, **name_LatLon_and_kwds):
237
237
  '''I{Must be overloaded}.'''
238
- self._notOverloaded(x, y, LatLon=LatLon, **name_LatLon_kwds)
238
+ self._notOverloaded(x, y, **name_LatLon_and_kwds) # PYCHOK no cover
239
239
 
240
- def _reverse(self, x, y, _c, lea, LatLon, **name_LatLon_kwds):
240
+ def _reverse(self, x, y, _c, lea, LatLon=None, **name_LatLon_kwds):
241
241
  '''(INTERNAL) Azimuthal (spherical) reverse C{x, y} to C{lat, lon}.
242
242
  '''
243
243
  e, n, z, r = _enzh4(x, y)
@@ -379,15 +379,14 @@ class Equidistant(_AzimuthalBase):
379
379
 
380
380
  return self._forward(lat, lon, name, _k_t)
381
381
 
382
- def reverse(self, x, y, LatLon=None, **name_LatLon_kwds):
382
+ def reverse(self, x, y, **name_LatLon_and_kwds):
383
383
  '''Convert an azimuthal equidistant location to geodetic lat- and longitude.
384
384
 
385
385
  @arg x: Easting of the location (C{meter}).
386
386
  @arg y: Northing of the location (C{meter}).
387
- @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
388
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} forthe location and
389
- optional, additional B{C{LatLon}} keyword arguments,
390
- ignored if C{B{LatLon} is None}.
387
+ @kwarg name_LatLon_and_kwds: Optional C{B{name}=NN} and class C{B{LatLon}=None}
388
+ to use and optionally, additional B{C{LatLon}} keyword arguments,
389
+ ignored if C{B{LatLon} is None}.
391
390
 
392
391
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
393
392
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
@@ -401,7 +400,7 @@ class Equidistant(_AzimuthalBase):
401
400
  def _c(c):
402
401
  return c if c > EPS else None
403
402
 
404
- return self._reverse(x, y, _c, False, LatLon, **name_LatLon_kwds)
403
+ return self._reverse(x, y, _c, False, **name_LatLon_and_kwds)
405
404
 
406
405
 
407
406
  def equidistant(lat0, lon0, datum=_WGS84, exact=False, geodsolve=False, **name):
@@ -505,9 +504,8 @@ class _EquidistantBase(_AzimuthalGeodesic):
505
504
  @arg x: Easting of the location (C{meter}).
506
505
  @arg y: Northing of the location (C{meter}).
507
506
  @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
508
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location and
509
- optional, additional B{C{LatLon}} keyword arguments,
510
- ignored if C{B{LatLon} is None}.
507
+ @kwarg name_LatLon_kwds: Optional C{B{name}=NN} and optionally, additional
508
+ B{C{LatLon}} keyword arguments, ignored if C{B{LatLon} is None}.
511
509
 
512
510
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
513
511
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
@@ -670,15 +668,14 @@ class Gnomonic(_AzimuthalBase):
670
668
 
671
669
  return self._forward(lat, lon, name, _k_t)
672
670
 
673
- def reverse(self, x, y, LatLon=None, **name_LatLon_kwds):
671
+ def reverse(self, x, y, **name_LatLon_and_kwds):
674
672
  '''Convert an azimuthal equidistant location to geodetic lat- and longitude.
675
673
 
676
674
  @arg x: Easting of the location (C{meter}).
677
675
  @arg y: Northing of the location (C{meter}).
678
- @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
679
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location and
680
- optional, additional B{C{LatLon}} keyword arguments,
681
- ignored if C{B{LatLon} is None}.
676
+ @kwarg name_LatLon_and_kwds: Optional C{B{name}=NN} and class C{B{LatLon}=None}
677
+ for the location and optionally, additional B{C{LatLon}} keyword
678
+ arguments, ignored if C{B{LatLon} is None}.
682
679
 
683
680
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
684
681
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
@@ -692,7 +689,7 @@ class Gnomonic(_AzimuthalBase):
692
689
  def _c(c):
693
690
  return atan1(c) if c > EPS else None
694
691
 
695
- return self._reverse(x, y, _c, False, LatLon, **name_LatLon_kwds)
692
+ return self._reverse(x, y, _c, False, **name_LatLon_and_kwds)
696
693
 
697
694
 
698
695
  def gnomonic(lat0, lon0, datum=_WGS84, exact=False, geodsolve=False, **name):
@@ -787,20 +784,18 @@ class _GnomonicBase(_AzimuthalGeodesic):
787
784
  @arg x: Easting of the location (C{meter}).
788
785
  @arg y: Northing of the location (C{meter}).
789
786
  @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
790
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location and
791
- optional, additional B{C{LatLon}} keyword arguments,
792
- ignored if C{B{LatLon} is None}.
787
+ @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location and optionally,
788
+ additional B{C{LatLon}} keyword arguments, ignored if C{B{LatLon} is None}.
793
789
 
794
790
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
795
791
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
796
792
 
797
793
  @raise AzimuthalError: No convergence.
798
794
 
799
- @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon}
800
- in the range C{[-180..180] degrees}. The C{azimuth} is clockwise
801
- from true North. The scale is C{1 / reciprocal**2} in C{radial}
802
- direction and C{1 / reciprocal} in the direction perpendicular
803
- to this.
795
+ @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon} in the range
796
+ C{[-180..180] degrees}. The C{azimuth} is clockwise from true North. The
797
+ scale is C{1 / reciprocal**2} in C{radial} direction and C{1 / reciprocal}
798
+ in the direction perpendicular to this.
804
799
  '''
805
800
  e, n, z, q = _enzh4(x, y)
806
801
 
@@ -974,30 +969,28 @@ class LambertEqualArea(_AzimuthalBase):
974
969
 
975
970
  return self._forward(lat, lon, name, _k_t)
976
971
 
977
- def reverse(self, x, y, LatLon=None, **name_LatLon_kwds):
972
+ def reverse(self, x, y, **name_LatLon_and_kwds):
978
973
  '''Convert an azimuthal Lambert-equal-area location to geodetic lat- and longitude.
979
974
 
980
975
  @arg x: Easting of the location (C{meter}).
981
976
  @arg y: Northing of the location (C{meter}).
982
- @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
983
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location
984
- and optional, additional B{C{LatLon}} keyword
985
- arguments, ignored if C{B{LatLon} is None}.
977
+ @kwarg name_LatLon_and_kwds: Optional C{B{name}=NN} and class C{B{LatLon}=None}
978
+ to use and optionally, additional B{C{LatLon}} keyword arguments,
979
+ ignored if C{B{LatLon} is None}.
986
980
 
987
981
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
988
982
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
989
983
 
990
- @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon}
991
- in the range C{[-180..180] degrees}. The C{scale} of the
992
- projection is C{1} in I{radial} direction, C{azimuth} clockwise
993
- from true North and is C{1 / reciprocal} in the direction
994
- perpendicular to this.
984
+ @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon} in the
985
+ range C{[-180..180] degrees}. The C{scale} of the projection is C{1}
986
+ in I{radial} direction, C{azimuth} clockwise from true North and is C{1
987
+ / reciprocal} in the direction perpendicular to this.
995
988
  '''
996
989
  def _c(c):
997
990
  c *= _0_5
998
991
  return (asin1(c) * _2_0) if c > EPS else None
999
992
 
1000
- return self._reverse(x, y, _c, True, LatLon, **name_LatLon_kwds)
993
+ return self._reverse(x, y, _c, True, **name_LatLon_and_kwds)
1001
994
 
1002
995
 
1003
996
  class Orthographic(_AzimuthalBase):
@@ -1028,29 +1021,27 @@ class Orthographic(_AzimuthalBase):
1028
1021
 
1029
1022
  return self._forward(lat, lon, name, _k_t)
1030
1023
 
1031
- def reverse(self, x, y, LatLon=None, **name_LatLon_kwds):
1024
+ def reverse(self, x, y, **name_LatLon_and_kwds):
1032
1025
  '''Convert an azimuthal orthographic location to geodetic lat- and longitude.
1033
1026
 
1034
1027
  @arg x: Easting of the location (C{meter}).
1035
1028
  @arg y: Northing of the location (C{meter}).
1036
- @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
1037
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location and
1038
- optional, additional B{C{LatLon}} keyword arguments,
1039
- ignored if C{B{LatLon} is None}.
1029
+ @kwarg name_LatLon_and_kwds: Optional C{B{name}=NN} and class C{B{LatLon}=None}
1030
+ to use and optionally, additional B{C{LatLon}} keyword arguments,
1031
+ ignored if C{B{LatLon} is None}.
1040
1032
 
1041
1033
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
1042
1034
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
1043
1035
 
1044
- @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon}
1045
- in the range C{[-180..180] degrees}. The C{scale} of the
1046
- projection is C{1} in I{radial} direction, C{azimuth} clockwise
1047
- from true North and is C{1 / reciprocal} in the direction
1048
- perpendicular to this.
1036
+ @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon} in the
1037
+ range C{[-180..180] degrees}. The C{scale} of the projection is C{1}
1038
+ in I{radial} direction, C{azimuth} clockwise from true North and is C{1
1039
+ / reciprocal} in the direction perpendicular to this.
1049
1040
  '''
1050
1041
  def _c(c):
1051
1042
  return asin1(c) if c > EPS else None
1052
1043
 
1053
- return self._reverse(x, y, _c, False, LatLon, **name_LatLon_kwds)
1044
+ return self._reverse(x, y, _c, False, **name_LatLon_and_kwds)
1054
1045
 
1055
1046
 
1056
1047
  class Stereographic(_AzimuthalBase):
@@ -1101,28 +1092,27 @@ class Stereographic(_AzimuthalBase):
1101
1092
  self._k0 = Scalar_(factor, name=n, low=EPS, high=2) # XXX high=1, 2, other?
1102
1093
  self._k02 = self._k0 * _2_0
1103
1094
 
1104
- def reverse(self, x, y, LatLon=None, **name_LatLon_kwds):
1095
+ def reverse(self, x, y, **name_LatLon_and_kwds):
1105
1096
  '''Convert an azimuthal stereographic location to geodetic lat- and longitude.
1106
1097
 
1107
1098
  @arg x: Easting of the location (C{meter}).
1108
1099
  @arg y: Northing of the location (C{meter}).
1109
- @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
1110
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location and
1111
- optional, additional B{C{LatLon}} keyword arguments,
1112
- ignored if C{B{LatLon} is None}.
1100
+ @kwarg name_LatLon_and_kwds: Optional C{B{name}=NN} and class C{B{LatLon}=None}
1101
+ to use and optionally, additional B{C{LatLon}} keyword arguments,
1102
+ ignored if C{B{LatLon} is None}.
1113
1103
 
1114
1104
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
1115
1105
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
1116
1106
 
1117
1107
  @note: The C{lat} will be in range C{[-90..90] degrees}, C{lon} in range
1118
- C{[-180..180] degrees} and C{azimuth} clockwise from true North.
1119
- The C{scale} of the projection is C{1} in I{radial} direction and
1120
- is C{1 / reciprocal} in the direction perpendicular to this.
1108
+ C{[-180..180] degrees} and C{azimuth} clockwise from true North. The
1109
+ C{scale} of the projection is C{1} in I{radial} direction and is C{1
1110
+ / reciprocal} in the direction perpendicular to this.
1121
1111
  '''
1122
1112
  def _c(c):
1123
1113
  return (atan2(c, self._k02) * _2_0) if c > EPS else None
1124
1114
 
1125
- return self._reverse(x, y, _c, False, LatLon, **name_LatLon_kwds)
1115
+ return self._reverse(x, y, _c, False, **name_LatLon_and_kwds)
1126
1116
 
1127
1117
 
1128
1118
  __all__ += _ALL_DOCS(_AzimuthalBase, _AzimuthalGeodesic, _EquidistantBase, _GnomonicBase)
pygeodesy/basics.py CHANGED
@@ -20,30 +20,28 @@ from pygeodesy.errors import _AttributeError, _ImportError, _NotImplementedError
20
20
  _TypeError, _TypesError, _ValueError, _xAssertionError, \
21
21
  _xkwds_get1
22
22
  # from pygeodesy.fsums import _isFsum_2Tuple # _MODS
23
- from pygeodesy.internals import _0_0, _enquote, _passarg, _version_info
23
+ from pygeodesy.internals import _0_0, _enquote, _getenv, _passarg, _PYGEODESY, \
24
+ _version_info
24
25
  from pygeodesy.interns import MISSING, NN, _1_, _by_, _COMMA_, _DOT_, _DEPRECATED_, \
25
26
  _ELLIPSIS4_, _EQUAL_, _in_, _invalid_, _N_A_, _not_, \
26
27
  _not_scalar_, _odd_, _SPACE_, _UNDER_, _version_
27
28
  # from pygeodesy.latlonBase import LatLonBase # _MODS
28
- from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS, _getenv, \
29
- LazyImportError, _sys_version_info2
29
+ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, LazyImportError
30
30
  # from pygeodesy.named import classname, modulename, _name__ # _MODS
31
31
  # from pygeodesy.nvectorBase import NvectorBase # _MODS
32
32
  # from pygeodesy.props import _update_all # _MODS
33
33
  # from pygeodesy.streprs import Fmt # _MODS
34
- # from pygeodesy.unitsBase import _NamedUnit, Str # _MODS
35
34
 
36
35
  from copy import copy as _copy, deepcopy as _deepcopy
37
36
  from math import copysign as _copysign
38
- import inspect as _inspect
37
+ # import inspect as _inspect # _MODS
39
38
 
40
39
  __all__ = _ALL_LAZY.basics
41
- __version__ = '24.09.28'
40
+ __version__ = '24.11.02'
42
41
 
43
- _below_ = 'below'
44
- _list_tuple_types = (list, tuple)
45
- _PYGEODESY_XPACKAGES_ = 'PYGEODESY_XPACKAGES'
46
- _required_ = 'required'
42
+ _below_ = 'below'
43
+ _list_tuple_types = (list, tuple)
44
+ _required_ = 'required'
47
45
 
48
46
  try: # Luciano Ramalho, "Fluent Python", O'Reilly, 2016 p. 395, 2022 p. 577+
49
47
  from numbers import Integral as _Ints, Real as _Scalars # .units
@@ -113,28 +111,29 @@ except NameError: # Python 3+
113
111
  return ub
114
112
 
115
113
 
116
- def _args_kwds_count2(func, exelf=True):
117
- '''(INTERNAL) Get a C{func}'s args and kwds count as 2-tuple
118
- C{(nargs, nkwds)}, including arg C{self} for methods.
119
-
120
- @kwarg exelf: If C{True}, exclude C{self} in the C{args}
121
- of a method (C{bool}).
122
- '''
123
- try: # PYCHOK no cover
124
- a = k = 0
125
- for _, p in _inspect.signature(func).parameters.items():
126
- if p.kind is p.POSITIONAL_OR_KEYWORD:
127
- if p.default is p.empty:
128
- a += 1
129
- else:
130
- k += 1
131
- except AttributeError: # .signature new Python 3+
132
- s = _inspect.getargspec(func)
133
- k = len(s.defaults or ())
134
- a = len(s.args) - k
135
- if exelf and a > 0 and _inspect.ismethod(func):
136
- a -= 1
137
- return a, k
114
+ # def _args_kwds_count2(func, exelf=True): # in .formy
115
+ # '''(INTERNAL) Get a C{func}'s args and kwds count as 2-tuple
116
+ # C{(nargs, nkwds)}, including arg C{self} for methods.
117
+ #
118
+ # @kwarg exelf: If C{True}, exclude C{self} in the C{args}
119
+ # of a method (C{bool}).
120
+ # '''
121
+ # i = _MODS.inspect
122
+ # try:
123
+ # a = k = 0
124
+ # for _, p in i.signature(func).parameters.items():
125
+ # if p.kind is p.POSITIONAL_OR_KEYWORD:
126
+ # if p.default is p.empty:
127
+ # a += 1
128
+ # else:
129
+ # k += 1
130
+ # except AttributeError: # Python 2-
131
+ # s = i.getargspec(func)
132
+ # k = len(s.defaults or ())
133
+ # a = len(s.args) - k
134
+ # if exelf and a > 0 and i.ismethod(func):
135
+ # a -= 1
136
+ # return a, k
138
137
 
139
138
 
140
139
  def _args_kwds_names(func, splast=False):
@@ -147,10 +146,11 @@ def _args_kwds_names(func, splast=False):
147
146
  @note: Python 2 may I{not} include the C{*args} nor the
148
147
  C{**kwds} names.
149
148
  '''
149
+ i = _MODS.inspect
150
150
  try:
151
- args_kwds = _inspect.signature(func).parameters.keys()
152
- except AttributeError: # .signature new Python 3+
153
- args_kwds = _inspect.getargspec(func).args
151
+ args_kwds = i.signature(func).parameters.keys()
152
+ except AttributeError: # Python 2-
153
+ args_kwds = i.getargspec(func).args
154
154
  if splast and args_kwds: # PYCHOK no cover
155
155
  args_kwds = list(args_kwds)
156
156
  t = args_kwds[-1:]
@@ -222,7 +222,7 @@ def halfs2(str2):
222
222
  return str2[:h], str2[h:]
223
223
 
224
224
 
225
- def int1s(x):
225
+ def int1s(x): # PYCHOK no cover
226
226
  '''Count the number of 1-bits in an C{int}, I{unsigned}.
227
227
 
228
228
  @note: C{int1s(-B{x}) == int1s(abs(B{x}))}.
@@ -266,14 +266,10 @@ def isCartesian(obj, ellipsoidal=None):
266
266
  return isinstanceof(obj, _MODS.cartesianBase.CartesianBase)
267
267
 
268
268
 
269
- if _FOR_DOCS: # XXX avoid epydoc Python 2.7 error
270
-
271
- def isclass(obj):
272
- '''Is B{C{obj}}ect a C{Class} or C{type}?
273
- '''
274
- return _inspect.isclass(obj)
275
- else:
276
- isclass = _inspect.isclass
269
+ def isclass(obj): # XXX avoid epydoc Python 2.7 error
270
+ '''Is B{C{obj}}ect a C{Class} or C{type}?
271
+ '''
272
+ return _MODS.inspect.isclass(obj)
277
273
 
278
274
 
279
275
  def iscomplex(obj, both=False):
@@ -511,7 +507,7 @@ def issubclassof(Sub, *Supers):
511
507
  if isclass(Sub):
512
508
  t = tuple(S for S in Supers if isclass(S))
513
509
  if t:
514
- return bool(issubclass(Sub, t))
510
+ return bool(issubclass(Sub, t)) # built-in
515
511
  return None
516
512
 
517
513
 
@@ -711,9 +707,9 @@ def splice(iterable, n=2, **fill):
711
707
  yield t # 1 slice, all
712
708
 
713
709
 
714
- def _splituple(strs, *sep_splits): # in .mgrs, .osgr, .webmercator
710
+ def _splituple(strs, *sep_splits): # in .mgrs, ...
715
711
  '''(INTERNAL) Split a C{comma}- or C{whitespace}-separated
716
- string into a C{tuple} of stripped strings.
712
+ string into a C{tuple} of stripped C{str}ings.
717
713
  '''
718
714
  t = (strs.split(*sep_splits) if sep_splits else
719
715
  strs.replace(_COMMA_, _SPACE_).split()) if strs else ()
@@ -740,11 +736,11 @@ def _xcopy(obj, deep=False):
740
736
  return _deepcopy(obj) if deep else _copy(obj)
741
737
 
742
738
 
743
- def _xcoverage(where, *required):
739
+ def _xcoverage(where, *required): # in .__main__ # PYCHOK no cover
744
740
  '''(INTERNAL) Import C{coverage} and check required version.
745
741
  '''
746
742
  try:
747
- _xpackage(_xcoverage)
743
+ _xpackages(_xcoverage)
748
744
  import coverage
749
745
  except ImportError as x:
750
746
  raise _xImportError(x, where)
@@ -780,7 +776,7 @@ def _xgeographiclib(where, *required):
780
776
  '''(INTERNAL) Import C{geographiclib} and check required version.
781
777
  '''
782
778
  try:
783
- _xpackage(_xgeographiclib)
779
+ _xpackages(_xgeographiclib)
784
780
  import geographiclib
785
781
  except ImportError as x:
786
782
  raise _xImportError(x, where, Error=LazyImportError)
@@ -828,7 +824,7 @@ def _xiterablen(obj):
828
824
  def _xiterror(obj, _xwhich):
829
825
  '''(INTERNAL) Helper for C{_xinterable} and C{_xiterablen}.
830
826
  '''
831
- t = _not_(_xwhich.__name__[2:]) # _dunder_nameof
827
+ t = _not_(_xwhich.__name__[2:]) # _DUNDER_nameof
832
828
  raise _TypeError(repr(obj), txt=t)
833
829
 
834
830
 
@@ -836,7 +832,7 @@ def _xnumpy(where, *required):
836
832
  '''(INTERNAL) Import C{numpy} and check required version.
837
833
  '''
838
834
  try:
839
- _xpackage(_xnumpy)
835
+ _xpackages(_xnumpy)
840
836
  import numpy
841
837
  except ImportError as x:
842
838
  raise _xImportError(x, where)
@@ -851,14 +847,16 @@ def _xor(x, *xs):
851
847
  return x
852
848
 
853
849
 
854
- def _xpackage(_xpkg):
850
+ def _xpackages(_xpkgf):
855
851
  '''(INTERNAL) Check dependency to be excluded.
856
852
  '''
857
- n = _xpkg.__name__[2:] # _dunder_nameof
858
- if n in _XPACKAGES:
859
- x = _SPACE_(n, _in_, _PYGEODESY_XPACKAGES_)
860
- e = _enquote(_getenv(_PYGEODESY_XPACKAGES_, NN))
861
- raise ImportError(_EQUAL_(x, e))
853
+ if _XPACKAGES: # PYCHOK no cover
854
+ n = _xpkgf.__name__[2:] # _DUNDER_nameof, less '_x'
855
+ if n.lower() in _XPACKAGES:
856
+ E = _PYGEODESY(_xpackages)
857
+ x = _SPACE_(n, _in_, E)
858
+ e = _enquote(_getenv(E, NN))
859
+ raise ImportError(_EQUAL_(x, e))
862
860
 
863
861
 
864
862
  def _xscalar(**names_values):
@@ -873,7 +871,7 @@ def _xscipy(where, *required):
873
871
  '''(INTERNAL) Import C{scipy} and check required version.
874
872
  '''
875
873
  try:
876
- _xpackage(_xscipy)
874
+ _xpackages(_xscipy)
877
875
  import scipy
878
876
  except ImportError as x:
879
877
  raise _xImportError(x, where)
@@ -905,7 +903,7 @@ def _xversion(package, where, *required, **name):
905
903
  if required:
906
904
  t = _version_info(package)
907
905
  if t[:len(required)] < required:
908
- t = _SPACE_(package.__name__, # _dunder_nameof
906
+ t = _SPACE_(package.__name__, # _DUNDER_nameof
909
907
  _version_, _DOT_(*t),
910
908
  _below_, _DOT_(*required),
911
909
  _req_d_by(where, **name))
@@ -925,14 +923,14 @@ def _xzip(*args, **strict): # PYCHOK no cover
925
923
  return zip(*args)
926
924
 
927
925
 
928
- if _sys_version_info2 < (3, 10): # see .errors
926
+ if _MODS.sys_version_info2 < (3, 10): # see .errors
929
927
  _zip = zip # PYCHOK exported
930
928
  else: # Python 3.10+
931
929
 
932
930
  def _zip(*args):
933
931
  return zip(*args, strict=True)
934
932
 
935
- _XPACKAGES = _splituple(_getenv(_PYGEODESY_XPACKAGES_, NN).lower())
933
+ _XPACKAGES = _splituple(_getenv(_PYGEODESY(_xpackages), NN).lower()) # test/bases._X_OK
936
934
 
937
935
  # **) MIT License
938
936
  #