pygeodesy 24.5.15__py2.py3-none-any.whl → 24.6.1__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 (90) hide show
  1. {PyGeodesy-24.5.15.dist-info → PyGeodesy-24.6.1.dist-info}/METADATA +6 -5
  2. PyGeodesy-24.6.1.dist-info/RECORD +116 -0
  3. pygeodesy/__init__.py +4 -4
  4. pygeodesy/albers.py +41 -41
  5. pygeodesy/auxilats/__init__.py +1 -1
  6. pygeodesy/auxilats/__main__.py +2 -2
  7. pygeodesy/auxilats/auxAngle.py +32 -31
  8. pygeodesy/auxilats/auxLat.py +80 -51
  9. pygeodesy/azimuthal.py +123 -124
  10. pygeodesy/basics.py +46 -10
  11. pygeodesy/booleans.py +13 -14
  12. pygeodesy/cartesianBase.py +25 -23
  13. pygeodesy/clipy.py +3 -3
  14. pygeodesy/constants.py +3 -3
  15. pygeodesy/css.py +50 -42
  16. pygeodesy/datums.py +42 -41
  17. pygeodesy/deprecated/functions.py +9 -3
  18. pygeodesy/dms.py +6 -6
  19. pygeodesy/ecef.py +41 -41
  20. pygeodesy/ellipsoidalBase.py +41 -41
  21. pygeodesy/ellipsoidalBaseDI.py +3 -4
  22. pygeodesy/ellipsoidalGeodSolve.py +2 -2
  23. pygeodesy/ellipsoidalKarney.py +3 -3
  24. pygeodesy/ellipsoidalNvector.py +11 -12
  25. pygeodesy/ellipsoids.py +45 -38
  26. pygeodesy/elliptic.py +3 -4
  27. pygeodesy/epsg.py +4 -3
  28. pygeodesy/errors.py +52 -20
  29. pygeodesy/etm.py +68 -65
  30. pygeodesy/fmath.py +44 -49
  31. pygeodesy/formy.py +129 -115
  32. pygeodesy/frechet.py +118 -103
  33. pygeodesy/fstats.py +21 -14
  34. pygeodesy/fsums.py +124 -80
  35. pygeodesy/gars.py +10 -9
  36. pygeodesy/geodesicw.py +19 -17
  37. pygeodesy/geodesicx/__init__.py +1 -1
  38. pygeodesy/geodesicx/__main__.py +2 -2
  39. pygeodesy/geodesicx/gx.py +39 -33
  40. pygeodesy/geodesicx/gxarea.py +12 -9
  41. pygeodesy/geodesicx/gxbases.py +3 -4
  42. pygeodesy/geodesicx/gxline.py +6 -8
  43. pygeodesy/geodsolve.py +29 -28
  44. pygeodesy/geohash.py +60 -57
  45. pygeodesy/geoids.py +34 -32
  46. pygeodesy/hausdorff.py +114 -101
  47. pygeodesy/heights.py +137 -130
  48. pygeodesy/internals.py +16 -11
  49. pygeodesy/interns.py +3 -6
  50. pygeodesy/iters.py +19 -17
  51. pygeodesy/karney.py +21 -17
  52. pygeodesy/ktm.py +25 -18
  53. pygeodesy/latlonBase.py +12 -11
  54. pygeodesy/lazily.py +6 -6
  55. pygeodesy/lcc.py +24 -25
  56. pygeodesy/ltp.py +143 -113
  57. pygeodesy/ltpTuples.py +207 -150
  58. pygeodesy/mgrs.py +26 -26
  59. pygeodesy/named.py +172 -90
  60. pygeodesy/namedTuples.py +33 -25
  61. pygeodesy/nvectorBase.py +8 -8
  62. pygeodesy/osgr.py +40 -48
  63. pygeodesy/points.py +18 -18
  64. pygeodesy/props.py +29 -16
  65. pygeodesy/rhumb/__init__.py +1 -1
  66. pygeodesy/rhumb/aux_.py +13 -15
  67. pygeodesy/rhumb/bases.py +12 -5
  68. pygeodesy/rhumb/ekx.py +24 -18
  69. pygeodesy/rhumb/solve.py +13 -10
  70. pygeodesy/simplify.py +16 -16
  71. pygeodesy/solveBase.py +18 -18
  72. pygeodesy/sphericalBase.py +17 -21
  73. pygeodesy/sphericalTrigonometry.py +21 -21
  74. pygeodesy/streprs.py +5 -5
  75. pygeodesy/trf.py +13 -11
  76. pygeodesy/triaxials.py +68 -64
  77. pygeodesy/units.py +35 -35
  78. pygeodesy/unitsBase.py +24 -11
  79. pygeodesy/ups.py +66 -70
  80. pygeodesy/utily.py +3 -3
  81. pygeodesy/utm.py +183 -187
  82. pygeodesy/utmups.py +38 -38
  83. pygeodesy/utmupsBase.py +104 -106
  84. pygeodesy/vector2d.py +6 -7
  85. pygeodesy/vector3d.py +16 -17
  86. pygeodesy/vector3dBase.py +4 -5
  87. pygeodesy/webmercator.py +43 -51
  88. PyGeodesy-24.5.15.dist-info/RECORD +0 -116
  89. {PyGeodesy-24.5.15.dist-info → PyGeodesy-24.6.1.dist-info}/WHEEL +0 -0
  90. {PyGeodesy-24.5.15.dist-info → PyGeodesy-24.6.1.dist-info}/top_level.txt +0 -0
pygeodesy/mgrs.py CHANGED
@@ -42,9 +42,9 @@ from pygeodesy.errors import _AssertionError, MGRSError, _parseX, \
42
42
  _ValueError, _xkwds
43
43
  from pygeodesy.interns import NN, _0_, _A_, _AtoZnoIO_, _band_, _B_, \
44
44
  _COMMASPACE_, _datum_, _easting_, _invalid_, \
45
- _northing_, _not_, _SPACE_, _W_, _Y_, _Z_, _zone_
45
+ _northing_, _SPACE_, _W_, _Y_, _Z_, _zone_
46
46
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _PYGEODESY_GEOCONVERT_
47
- from pygeodesy.named import _NamedBase, _NamedTuple, _Pass, _xnamed
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
50
50
  from pygeodesy.streprs import enstr2, _enstr2m3, Fmt, _resolution10, _xzipairs
@@ -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.05.13'
58
+ __version__ = '24.05.31'
59
59
 
60
60
  _AN_ = 'AN' # default south pole grid tile and band B
61
61
  _AtoPx_ = _AtoZnoIO_.tillP
@@ -87,7 +87,7 @@ class Mgrs(_NamedBase):
87
87
  _zone = 0 # longitudinal or polar zone (C{int}), 0..60
88
88
 
89
89
  def __init__(self, zone=0, EN=NN, easting=0, northing=0, band=NN,
90
- datum=_WGS84, resolution=0, name=NN):
90
+ datum=_WGS84, resolution=0, **name):
91
91
  '''New L{Mgrs} Military grid reference.
92
92
 
93
93
  @arg zone: The 6° I{longitudinal} zone (C{int}), 1..60 covering
@@ -104,7 +104,7 @@ class Mgrs(_NamedBase):
104
104
  @kwarg datum: This reference's datum (L{Datum}, L{Ellipsoid},
105
105
  L{Ellipsoid2} or L{a_f2Tuple}).
106
106
  @kwarg resolution: Optional resolution (C{meter}), C{0} for default.
107
- @kwarg name: Optional name (C{str}).
107
+ @kwarg name: Optional C{B{name}=NN} (C{str}).
108
108
 
109
109
  @raise MGRSError: Invalid B{C{zone}}, B{C{EN}}, B{C{easting}},
110
110
  B{C{northing}}, B{C{band}} or B{C{resolution}}.
@@ -235,20 +235,18 @@ class Mgrs(_NamedBase):
235
235
  toUps8(a, 0, datum=self.datum, Ups=None)
236
236
  return int(u.northing / _100km) * _100km
237
237
 
238
- def parse(self, strMGRS, name=NN):
238
+ def parse(self, strMGRS, **name):
239
239
  '''Parse a string to a similar L{Mgrs} instance.
240
240
 
241
- @arg strMGRS: The MGRS reference (C{str}),
242
- see function L{parseMGRS}.
243
- @kwarg name: Optional instance name (C{str}),
244
- overriding this name.
241
+ @arg strMGRS: The MGRS reference (C{str}), see function L{parseMGRS}.
242
+ @kwarg name: Optional C{B{name}=NN} (C{str}), overriding this name.
245
243
 
246
244
  @return: The similar instance (L{Mgrs}).
247
245
 
248
246
  @raise MGRSError: Invalid B{C{strMGRS}}.
249
247
  '''
250
248
  return parseMGRS(strMGRS, datum=self.datum, Mgrs=self.classof,
251
- name=name or self.name)
249
+ name=self._name__(name))
252
250
 
253
251
  @property
254
252
  def resolution(self):
@@ -357,7 +355,7 @@ class Mgrs(_NamedBase):
357
355
  @raise MGRSError: This MGRS is a I{non-polar} UTM reference.
358
356
  '''
359
357
  if self.isUTM:
360
- raise MGRSError(zoneB=self.zoneB, txt=_not_(_polar_))
358
+ raise MGRSError(zoneB=self.zoneB, txt_not_=_polar_)
361
359
  return self._toUtmUps(Ups, center)
362
360
 
363
361
  def toUtm(self, Utm=Utm, center=False):
@@ -536,7 +534,7 @@ class _RE(object):
536
534
  _RE = _RE() # PYCHOK singleton
537
535
 
538
536
 
539
- def parseMGRS(strMGRS, datum=_WGS84, Mgrs=Mgrs, name=NN):
537
+ def parseMGRS(strMGRS, datum=_WGS84, Mgrs=Mgrs, **name):
540
538
  '''Parse a string representing a MGRS grid reference,
541
539
  consisting of C{"[zone]Band, EN, easting, northing"}.
542
540
 
@@ -544,7 +542,7 @@ def parseMGRS(strMGRS, datum=_WGS84, Mgrs=Mgrs, name=NN):
544
542
  @kwarg datum: Optional datum to use (L{Datum}).
545
543
  @kwarg Mgrs: Optional class to return the MGRS grid
546
544
  reference (L{Mgrs}) or C{None}.
547
- @kwarg name: Optional B{C{Mgrs}} name (C{str}).
545
+ @kwarg name: Optional B{C{Mgrs}} C{B{name}=NN} (C{str}).
548
546
 
549
547
  @return: The MGRS grid reference as B{C{Mgrs}} or if
550
548
  C{B{Mgrs} is None} as an L{Mgrs4Tuple}C{(zone,
@@ -582,29 +580,29 @@ def parseMGRS(strMGRS, datum=_WGS84, Mgrs=Mgrs, name=NN):
582
580
  e, n, m = _enstr2m3(*m[2:])
583
581
 
584
582
  if Mgrs is None:
585
- r = Mgrs4Tuple(zB, EN, e, n, name=name)
583
+ r = Mgrs4Tuple(zB, EN, e, n, **name)
586
584
  _ = r.toMgrs(resolution=m) # validate
587
585
  else:
588
- r = Mgrs(zB, EN, e, n, datum=datum, resolution=m, name=name)
586
+ r = Mgrs(zB, EN, e, n, datum=datum, resolution=m, **name)
589
587
  return r
590
588
 
591
589
  return _parseX(_MGRS, strMGRS, datum, Mgrs, name,
592
590
  strMGRS=strMGRS, Error=MGRSError)
593
591
 
594
592
 
595
- def toMgrs(utmups, Mgrs=Mgrs, name=NN, **Mgrs_kwds):
593
+ def toMgrs(utmups, Mgrs=Mgrs, **name_Mgrs_kwds):
596
594
  '''Convert a UTM or UPS coordinate to an MGRS grid reference.
597
595
 
598
596
  @arg utmups: A UTM or UPS coordinate (L{Utm}, L{Etm} or L{Ups}).
599
597
  @kwarg Mgrs: Optional class to return the MGRS grid reference
600
598
  (L{Mgrs}) or C{None}.
601
- @kwarg name: Optional B{C{Mgrs}} name (C{str}).
602
- @kwarg Mgrs_kwds: Optional, additional B{C{Mgrs}} keyword
603
- arguments, ignored if C{B{Mgrs} is None}.
599
+ @kwarg name_Mgrs_kwds: Optional C{B{name}=NN} (C{str}) and
600
+ optional, additional B{C{Mgrs}} keyword arguments,
601
+ ignored if C{B{Mgrs} is None}.
604
602
 
605
- @return: The MGRS grid reference as B{C{Mgrs}} or if
606
- C{B{Mgrs} is None} as an L{Mgrs6Tuple}C{(zone,
607
- EN, easting, northing, band, datum)}.
603
+ @return: The MGRS grid reference as B{C{Mgrs}} or if C{B{Mgrs}
604
+ is None} as an L{Mgrs6Tuple}C{(zone, EN, easting,
605
+ northing, band, datum)}.
608
606
 
609
607
  @raise MGRSError: Invalid B{C{utmups}}.
610
608
 
@@ -634,12 +632,14 @@ def toMgrs(utmups, Mgrs=Mgrs, name=NN, **Mgrs_kwds):
634
632
  except (IndexError, TypeError, ValueError) as x:
635
633
  raise MGRSError(B=B, E=E, N=N, utmups=utmups, cause=x)
636
634
 
635
+ t, kwds = _name2__(name_Mgrs_kwds, _or_nameof=utmups)
637
636
  if Mgrs is None:
638
- r = Mgrs4Tuple(Fmt.zone(z), EN, e, n).to6Tuple(B, utmups.datum)
637
+ r = Mgrs4Tuple(Fmt.zone(z), EN, e, n, name=t) \
638
+ .to6Tuple(B, utmups.datum)
639
639
  else:
640
- kwds = _xkwds(Mgrs_kwds, band=B, datum=utmups.datum)
640
+ kwds = _xkwds(kwds, band=B, datum=utmups.datum, name=t)
641
641
  r = Mgrs(z, EN, e, n, **kwds)
642
- return _xnamed(r, name or utmups.name)
642
+ return r
643
643
 
644
644
 
645
645
  def _um100km2(m):
pygeodesy/named.py CHANGED
@@ -19,12 +19,13 @@ from pygeodesy.errors import _AssertionError, _AttributeError, _incompatible, \
19
19
  _IndexError, _IsnotError, _KeyError, LenError, \
20
20
  _NameError, _NotImplementedError, _TypeError, \
21
21
  _TypesError, UnitError, _ValueError, _xattr, _xkwds, \
22
- _xkwds_get, _xkwds_item2, _xkwds_pop2
22
+ _xkwds_item2, _xkwds_pop2
23
23
  from pygeodesy.internals import _caller3, _dunder_nameof, _isPyPy, _sizeof, _under
24
24
  from pygeodesy.interns import MISSING, NN, _AT_, _COLON_, _COLONSPACE_, _COMMA_, \
25
- _COMMASPACE_, _doesn_t_exist_, _DOT_, _DUNDER_, _EQUAL_, \
26
- _exists_, _immutable_, _name_, _NL_, _NN_, _no_, \
27
- _other_, _s_, _SPACE_, _std_, _UNDER_, _valid_, _vs_
25
+ _COMMASPACE_, _doesn_t_exist_, _DOT_, _DUNDER_, \
26
+ _dunder_name_, _EQUAL_, _exists_, _immutable_, _name_, \
27
+ _NL_, _NN_, _no_, _other_, _s_, _SPACE_, _std_, \
28
+ _UNDER_, _valid_, _vs_
28
29
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _getenv
29
30
  from pygeodesy.props import _allPropertiesOf_n, deprecated_method, _hasProperty, \
30
31
  _update_all, property_doc_, Property_RO, property_RO, \
@@ -32,7 +33,7 @@ from pygeodesy.props import _allPropertiesOf_n, deprecated_method, _hasProperty,
32
33
  from pygeodesy.streprs import attrs, Fmt, lrstrip, pairs, reprs, unstr
33
34
 
34
35
  __all__ = _ALL_LAZY.named
35
- __version__ = '24.05.13'
36
+ __version__ = '24.05.31'
36
37
 
37
38
  _COMMANL_ = _COMMA_ + _NL_
38
39
  _COMMASPACEDOT_ = _COMMASPACE_ + _DOT_
@@ -49,65 +50,6 @@ _Units_ = '_Units_'
49
50
  _UP = 2
50
51
 
51
52
 
52
- def _xjoined_(prefix, name, enquote=True):
53
- '''(INTERNAL) Join C{pref} and non-empty C{name}.
54
- '''
55
- if name and prefix:
56
- if enquote:
57
- name = repr(name)
58
- n = _SPACE_(prefix, name)
59
- else:
60
- n = prefix or name
61
- return n
62
-
63
-
64
- def _xnamed(inst, name, force=False):
65
- '''(INTERNAL) Set the instance' C{.name = B{name}}.
66
-
67
- @arg inst: The instance (C{_Named}).
68
- @arg name: The name (C{str}).
69
- @kwarg force: Force name change (C{bool}).
70
-
71
- @return: The B{C{inst}}, named if B{C{force}}d or
72
- not named before.
73
- '''
74
- if name and isinstance(inst, _Named):
75
- if not inst.name:
76
- inst.name = name
77
- elif force:
78
- inst.rename(name)
79
- return inst
80
-
81
-
82
- def _xother3(inst, other, name=_other_, up=1, **name_other):
83
- '''(INTERNAL) Get C{name} and C{up} for a named C{other}.
84
- '''
85
- if name_other: # and other is None
86
- name, other = _xkwds_item2(name_other)
87
- elif other and len(other) == 1:
88
- other = other[0]
89
- else:
90
- raise _AssertionError(name, other, txt=classname(inst, prefixed=True))
91
- return other, name, up
92
-
93
-
94
- def _xotherError(inst, other, name=_other_, up=1):
95
- '''(INTERNAL) Return a C{_TypeError} for an incompatible, named C{other}.
96
- '''
97
- n = _callname(name, classname(inst, prefixed=True), inst.name, up=up + 1)
98
- return _TypeError(name, other, txt=_incompatible(n))
99
-
100
-
101
- def _xvalid(name, underOK=False):
102
- '''(INTERNAL) Check valid attribute name C{name}.
103
- '''
104
- return bool(name and isstr(name)
105
- and name != _name_
106
- and (underOK or not name.startswith(_UNDER_))
107
- and (not iskeyword(name))
108
- and isidentifier(name))
109
-
110
-
111
53
  class ADict(dict):
112
54
  '''A C{dict} with both key I{and} attribute access to
113
55
  the C{dict} items.
@@ -259,18 +201,18 @@ class _Named(object):
259
201
  '''
260
202
  return _xnamed(self.__class__(*args, **kwds), self.name)
261
203
 
262
- def copy(self, deep=False, name=NN):
204
+ def copy(self, deep=False, **name):
263
205
  '''Make a shallow or deep copy of this instance.
264
206
 
265
207
  @kwarg deep: If C{True} make a deep, otherwise
266
208
  a shallow copy (C{bool}).
267
- @kwarg name: Optional, non-empty name (C{str}).
209
+ @kwarg name: Optional, non-empty C{B{name}=NN} (C{str}).
268
210
 
269
211
  @return: The copy (C{This class}).
270
212
  '''
271
213
  c = _xcopy(self, deep=deep)
272
214
  if name:
273
- c.rename(name)
215
+ _ = c.rename(name)
274
216
  return c
275
217
 
276
218
  def _DOT_(self, *names):
@@ -282,7 +224,8 @@ class _Named(object):
282
224
  '''Duplicate this instance, replacing some attributes.
283
225
 
284
226
  @kwarg deep: If C{True} duplicate deep, otherwise shallow.
285
- @kwarg items: Attributes to be changed (C{any}).
227
+ @kwarg items: Attributes to be changed (C{any}), including
228
+ optional C{B{name}} (C{str}).
286
229
 
287
230
  @return: The duplicate (C{This class}).
288
231
 
@@ -292,7 +235,7 @@ class _Named(object):
292
235
  m, items = _xkwds_pop2(items, name=n)
293
236
  d = _xdup(self, deep=deep, **items)
294
237
  if m != n:
295
- d.rename(m)
238
+ d.rename(m) # zap _Named_Property_ROs
296
239
  # if items:
297
240
  # _update_all(d)
298
241
  return d
@@ -341,11 +284,11 @@ class _Named(object):
341
284
 
342
285
  @name.setter # PYCHOK setter!
343
286
  def name(self, name):
344
- '''Set the name (C{str}).
287
+ '''Set the C{B{name}=NN} (C{str}).
345
288
 
346
289
  @raise NameError: Can't rename, use method L{rename}.
347
290
  '''
348
- m, n = self._name, str(name)
291
+ m, n = self._name, _name__(name)
349
292
  if not m:
350
293
  self._name = n
351
294
  elif n != m:
@@ -361,6 +304,11 @@ class _Named(object):
361
304
  # _Named.name.fset(self, name), but NOT
362
305
  # _Named(self).name = name
363
306
 
307
+ def _name__(self, name): # usually **name
308
+ '''(INTERNAL) Get the C{name} or this C{name}.
309
+ '''
310
+ return _name__(name, _or_nameof=self) # nameof(self)
311
+
364
312
  @Property_RO
365
313
  def named(self):
366
314
  '''Get the name I{or} class name or C{""} (C{str}).
@@ -408,12 +356,22 @@ class _Named(object):
408
356
 
409
357
  @return: The previous name (C{str}).
410
358
  '''
411
- m, n = self._name, str(name)
359
+ m, n = self._name, _name__(name)
412
360
  if n != m:
413
361
  self._name = n
414
362
  _update_attrs(self, *_Named_Property_ROs)
415
363
  return m
416
364
 
365
+ def renamed(self, name):
366
+ '''Change the name.
367
+
368
+ @arg name: The new name (C{str}).
369
+
370
+ @return: This instance (C{str}).
371
+ '''
372
+ _ = self.rename(name)
373
+ return self
374
+
417
375
  @property_RO
418
376
  def sizeof(self):
419
377
  '''Get the current size in C{bytes} of this instance (C{int}).
@@ -443,16 +401,17 @@ class _Named(object):
443
401
  # '''
444
402
  # return _DOT_(self, unstr(which, *args, **kwds))
445
403
 
446
- def _xnamed(self, inst, name=NN, force=False):
404
+ def _xnamed(self, inst, name=NN, **force):
447
405
  '''(INTERNAL) Set the instance' C{.name = self.name}.
448
406
 
449
407
  @arg inst: The instance (C{_Named}).
450
- @kwarg name: Optional name, overriding C{self.name} (C{str}).
451
- @kwarg force: Force name change (C{bool}).
408
+ @kwarg name: The name (C{str}).
409
+ @kwarg force: If C{True}, force rename (C{bool}).
452
410
 
453
- @return: The B{C{inst}}, named if not named before.
411
+ @return: The B{C{inst}}, renamed if B{C{force}}d
412
+ or if not named before.
454
413
  '''
455
- return _xnamed(inst, name or self.name, force=force)
414
+ return _xnamed(inst, name, **force)
456
415
 
457
416
  def _xrenamed(self, inst):
458
417
  '''(INTERNAL) Rename the instance' C{.name = self.name}.
@@ -466,7 +425,7 @@ class _Named(object):
466
425
  if not isinstance(inst, _Named):
467
426
  raise _IsnotError(_valid_, inst=inst)
468
427
 
469
- inst.rename(self.name)
428
+ _ = inst.rename(self.name)
470
429
  return inst
471
430
 
472
431
  _Named_Property_ROs = _allPropertiesOf_n(5, _Named, Property_RO) # PYCHOK once
@@ -559,16 +518,17 @@ class _NamedBase(_Named):
559
518
 
560
519
 
561
520
  class _NamedDict(ADict, _Named):
562
- '''(INTERNAL) Named C{dict} with key I{and} attribute
563
- access to the items.
521
+ '''(INTERNAL) Named C{dict} with key I{and} attribute access
522
+ to the items.
564
523
  '''
565
524
  def __init__(self, *args, **kwds):
566
- if args: # args override kwds
525
+ if args: # is args[0] a dict?
567
526
  if len(args) != 1: # or not isinstance(args[0], dict)
527
+ kwds = _name1__(kwds)
568
528
  t = unstr(self.classname, *args, **kwds) # PYCHOK no cover
569
529
  raise _ValueError(args=len(args), txt=t)
570
- kwds = _xkwds(dict(args[0]), **kwds)
571
- n, kwds = _xkwds_pop2(kwds, name=NN)
530
+ kwds = _xkwds(dict(args[0]), **kwds) # args[0] overrides kwds
531
+ n, kwds = _name2__(**kwds)
572
532
  if n:
573
533
  _Named.name.fset(self, n) # see _Named.name
574
534
  ADict.__init__(self, kwds)
@@ -640,7 +600,7 @@ class _NamedEnum(_NamedDict):
640
600
  @arg Classes: Additional, acceptable classes or C{type}s.
641
601
  '''
642
602
  self._item_Classes = (Class,) + Classes
643
- n = _xkwds_get(name, name=NN) or NN(Class.__name__, _s_)
603
+ n = _name__(**name) or NN(Class.__name__, _s_) # _dunder_nameof
644
604
  if n and _xvalid(n, underOK=True):
645
605
  _Named.name.fset(self, n) # see _Named.name
646
606
 
@@ -881,9 +841,11 @@ class _NamedEnumItem(_NamedBase):
881
841
  def name(self, name):
882
842
  '''Set the name, unless already registered (C{str}).
883
843
  '''
844
+ name = _name__(name) or _NN_
884
845
  if self._enum:
885
- raise _NameError(str(name), self, txt=_registered_) # XXX _TypeError
886
- self._name = str(name)
846
+ raise _NameError(name, self, txt=_registered_) # XXX _TypeError
847
+ if name:
848
+ self._name = name
887
849
 
888
850
  def _register(self, enum, name):
889
851
  '''(INTERNAL) Add this item as B{C{enum.name}}.
@@ -891,6 +853,7 @@ class _NamedEnumItem(_NamedBase):
891
853
  @note: Don't register if name is empty or doesn't
892
854
  start with a letter.
893
855
  '''
856
+ name = _name__(name)
894
857
  if name and _xvalid(name, underOK=True):
895
858
  self.name = name
896
859
  if name[:1].isalpha(): # '_...' not registered
@@ -1043,7 +1006,7 @@ class _NamedTuple(tuple, _Named):
1043
1006
 
1044
1007
  iteritems = items
1045
1008
 
1046
- def _kwdself(self, iteration=None, name=NN, **unused):
1009
+ def _kwdself(self, iteration=None, **name):
1047
1010
  '''(INTERNAL) Set C{__new__} keyword arguments.
1048
1011
  '''
1049
1012
  if iteration is not None:
@@ -1144,7 +1107,8 @@ class _NamedTuple(tuple, _Named):
1144
1107
  if (issubclassof(xTuple, _NamedTuple) and
1145
1108
  (len(self._Names_) + len(items)) == len(xTuple._Names_) and
1146
1109
  self._Names_ == xTuple._Names_[:len(self)]):
1147
- return xTuple(self + items, **_xkwds(name, name=self.name)) # *(self + items)
1110
+ n = _name__(**name) or self.name
1111
+ return xTuple(self + items, name=n) # *(self + items)
1148
1112
  c = NN(self.classname, repr(self._Names_)) # PYCHOK no cover
1149
1113
  x = NN(xTuple.__name__, repr(xTuple._Names_)) # PYCHOK no cover
1150
1114
  raise TypeError(_SPACE_(c, _vs_, x))
@@ -1232,9 +1196,9 @@ def modulename(clas, prefixed=None): # in .basics._xversion
1232
1196
  @return: The B{C{class}}'s C{[module.]class} name (C{str}).
1233
1197
  '''
1234
1198
  try:
1235
- n = clas.__name__
1199
+ n = clas.__name__
1236
1200
  except AttributeError:
1237
- n = '__name__' # _DUNDER_(NN, _name_, NN)
1201
+ n = _dunder_name_
1238
1202
  if prefixed or (classnaming() if prefixed is None else False):
1239
1203
  try:
1240
1204
  m = clas.__module__.rsplit(_DOT_, 1)
@@ -1244,6 +1208,61 @@ def modulename(clas, prefixed=None): # in .basics._xversion
1244
1208
  return n
1245
1209
 
1246
1210
 
1211
+ # def _name__(name=NN, name__=None, _or_nameof=None, **kwds):
1212
+ # '''(INTERNAL) Get single keyword argument C{B{name}=NN|None}.
1213
+ # '''
1214
+ # if kwds: # "unexpected keyword arguments ..."
1215
+ # m = _MODS.errors
1216
+ # raise m._UnexpectedError(**kwds)
1217
+ # if name: # is given
1218
+ # n = _name__(**name) if isinstance(name, dict) else str(name)
1219
+ # elif name__ is not None:
1220
+ # n = getattr(name__, _dunder_name_, NN) # _xattr(name__, __name__=NN)
1221
+ # else:
1222
+ # n = name # NN or None or {} or any False type
1223
+ # if _or_nameof is not None and not n:
1224
+ # n = getattr(_or_nameof, _name_, NN) # _xattr(_or_nameof, name=NN)
1225
+ # return n # str or None or {}
1226
+
1227
+
1228
+ def _name__(name=NN, **kwds):
1229
+ '''(INTERNAL) Get single keyword argument C{B{name}=NN|None}.
1230
+ '''
1231
+ if name or kwds:
1232
+ name, kwds = _name2__(name, **kwds)
1233
+ if kwds: # "unexpected keyword arguments ..."
1234
+ m = _MODS.errors
1235
+ raise m._UnexpectedError(**kwds)
1236
+ return name if name or name is None else NN
1237
+
1238
+
1239
+ def _name1__(kwds_name, **name__or_nameof):
1240
+ '''(INTERNAL) Resolve and set the C{B{name}=NN}.
1241
+ '''
1242
+ if kwds_name or name__or_nameof:
1243
+ n, kwds_name = _name2__(kwds_name, **name__or_nameof)
1244
+ kwds_name.update(name=n)
1245
+ return kwds_name
1246
+
1247
+
1248
+ def _name2__(name=NN, name__=None, _or_nameof=None, **kwds):
1249
+ '''(INTERNAL) Get the C{B{name}=NN|None} and other C{kwds}.
1250
+ '''
1251
+ if name: # is given
1252
+ if isinstance(name, dict):
1253
+ kwds.update(name) # kwds = _xkwds(kwds, **name)?
1254
+ n, kwds = _name2__(**kwds)
1255
+ else:
1256
+ n = str(name)
1257
+ elif name__ is not None:
1258
+ n = getattr(name__, _dunder_name_, NN) # _xattr(name__, __name__=NN)
1259
+ else:
1260
+ n = name if name is None else NN
1261
+ if _or_nameof is not None and not n:
1262
+ n = getattr(_or_nameof, _name_, NN) # _xattr(_or_nameof, name=NN)
1263
+ return n, kwds # (str or None or {}), dict
1264
+
1265
+
1247
1266
  def nameof(inst):
1248
1267
  '''Get the name of an instance.
1249
1268
 
@@ -1322,6 +1341,69 @@ def _Pass(arg, **unused): # PYCHOK no cover
1322
1341
  return arg
1323
1342
 
1324
1343
 
1344
+ def _xjoined_(prefix, name=NN, enquote=True, **name__or_nameof):
1345
+ '''(INTERNAL) Join C{prefix} and non-empty C{name}.
1346
+ '''
1347
+ if name__or_nameof:
1348
+ name = _name__(name, **name__or_nameof)
1349
+ if name and prefix:
1350
+ if enquote:
1351
+ name = repr(name)
1352
+ t = _SPACE_(prefix, name)
1353
+ else:
1354
+ t = prefix or name
1355
+ return t
1356
+
1357
+
1358
+ def _xnamed(inst, name=NN, force=False, **name__or_nameof):
1359
+ '''(INTERNAL) Set the instance' C{.name = B{name}}.
1360
+
1361
+ @arg inst: The instance (C{_Named}).
1362
+ @kwarg name: The name (C{str}).
1363
+ @kwarg force: If C{True}, force rename (C{bool}).
1364
+
1365
+ @return: The B{C{inst}}, renamed if B{C{force}}d
1366
+ or if not named before.
1367
+ '''
1368
+ if name__or_nameof:
1369
+ name = _name__(name, **name__or_nameof)
1370
+ if name and isinstance(inst, _Named):
1371
+ if not inst.name:
1372
+ inst.name = name
1373
+ elif force:
1374
+ inst.rename(name)
1375
+ return inst
1376
+
1377
+
1378
+ def _xother3(inst, other, name=_other_, up=1, **name_other):
1379
+ '''(INTERNAL) Get C{name} and C{up} for a named C{other}.
1380
+ '''
1381
+ if name_other: # and other is None
1382
+ name, other = _xkwds_item2(name_other)
1383
+ elif other and len(other) == 1:
1384
+ name, other = _name__(name), other[0]
1385
+ else:
1386
+ raise _AssertionError(name, other, txt=classname(inst, prefixed=True))
1387
+ return other, name, up
1388
+
1389
+
1390
+ def _xotherError(inst, other, name=_other_, up=1):
1391
+ '''(INTERNAL) Return a C{_TypeError} for an incompatible, named C{other}.
1392
+ '''
1393
+ n = _callname(name, classname(inst, prefixed=True), inst.name, up=up + 1)
1394
+ return _TypeError(name, other, txt=_incompatible(n))
1395
+
1396
+
1397
+ def _xvalid(name, underOK=False):
1398
+ '''(INTERNAL) Check valid attribute name C{name}.
1399
+ '''
1400
+ return bool(name and isstr(name)
1401
+ and name != _name_
1402
+ and (underOK or not name.startswith(_UNDER_))
1403
+ and (not iskeyword(name))
1404
+ and isidentifier(name))
1405
+
1406
+
1325
1407
  __all__ += _ALL_DOCS(_Named,
1326
1408
  _NamedBase, # _NamedDict,
1327
1409
  _NamedEnum, _NamedEnumItem,