Coverage for pygeodesy/named.py : 85%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*-
C{_NamedStr} and C{_NamedTuple} with nameable instances and several subclasses thereof.
In addition, the items in a C{_NamedDict} are accessable as attributes and the items in a C{_NamedTuple} can be named to be accessable as attributes, similar to standard Python C{namedtuple}s.
Results previously returned as tuples by C{pygeodesy} functions and class methods are now instances of some C{...Tuple} class, all sub-classes of C{_NamedTuple} defined here.
@newfield example: Example, Examples '''
# XXX 'FsumDelta2Tuple' is in _ALL_LAZY.named # '_NamedDict', '_NamedEnum', '_NamedEnumItem', # '_NamedInt', '_NamedStr', '_NamedTuple', 'Bearing2Tuple', 'Bounds2Tuple', 'Bounds4Tuple', 'ClipCS3Tuple', 'ClipSH3Tuple', 'Curvature2Tuple', 'Destination2Tuple', 'Distance2Tuple', 'Distance3Tuple', 'Distance4Tuple', 'EasNor2Tuple', 'EasNor3Tuple', 'EasNorAziRk4Tuple', 'EasNorExact4Tuple', 'EasNorRadius3Tuple', 'Elevation2Tuple', 'GeoidHeight2Tuple', 'GeoidHeight5Tuple', 'LatLon2Tuple', 'LatLon3Tuple', 'LatLon4Tuple', 'LatLonAziRk4Tuple', 'LatLonDatum3Tuple', 'LatLonDatum5Tuple', 'LatLonExact4Tuple', 'LatLonPrec3Tuple', 'LatLonPrec5Tuple', 'Mgrs4Tuple', 'Mgrs6Tuple', 'NearestOn3Tuple', 'NearestOn5Tuple', 'Ned3Tuple', 'Neighbors8Dict', 'PhiLam2Tuple', 'PhiLam3Tuple', 'Point3Tuple', 'Points2Tuple', 'Shape2Tuple', 'UtmUps2Tuple', 'UtmUps4Tuple', 'UtmUps5Tuple', 'UtmUps8Tuple', 'UtmUpsLatLon5Tuple', 'Vector3Tuple', 'Vector4Tuple')
'''(INTERNAL) Copy attribute values from B{C{other}} to B{C{inst}}.
@param inst: Instance to copy attribute values to. @param other: Instance to copy attribute values from. @param attrs: Attribute names (C{str}s).
@return: The B{C{inst}}, updated.
@raise AttributeError: An B{C{attr}} doesn't exist or is not settable. ''' raise AttributeError('.%s invalid: %r' % (a, o))
'''(INTERNAL) Set the instance' C{.name = }B{C{name}}.
@param inst: The instance (C{_Named}). @param name: The name (C{str}).
@return: The B{C{inst}}, named if not named before. '''
'''(INTERNAL) Root class for named objects. '''
return '<%s at %#x>' % (self.named2, id(self))
def classname(self): '''Get this object's C{[module.]class} name (C{str}), see property C{classnaming} and function C{classnaming}. '''
def classnaming(self): '''Get the class naming (C{bool}). '''
def classnaming(self, prefixed): '''Set the class naming for C{[module.].class} names.
@param prefixed: Include the module name (C{bool}). ''' self._classnaming = bool(prefixed)
'''Create another instance of this very class.
@param args: Optional, positional arguments. @keyword kwds: Optional, keyword arguments.
@return: New instance (B{self.__class__}). '''
'''Make a shallow or deep copy of this instance.
@keyword deep: If C{True} make a deep, otherwise a shallow copy (C{bool}).
@return: The copy (C{This class} or subclass thereof). '''
def name(self): '''Get the name (C{str}). '''
def name(self, name): '''Set the name.
@param name: New name (C{str}). ''' # to set the name ffrom a sub-class, use # self.name = name or # _Named.name.fset(self, name), but # not _Named(self).name = name
def named(self): '''Get the name I{or} class name or C{""} (C{str}). '''
def named2(self): '''Get the class name I{and/or} thename or C{""} (C{str}). ''' n, c = self.name, self.classname return ('%s %r' % (c, n)) if c and n else (c or n)
'''Raise an error for a method or property not overloaded. ''' n = '%s %s.%s' % (self._notOverloaded.__name__, self.classname, name) raise AssertionError(unStr(n, *args, **kwds))
'''Default C{str(self)}. ''' return str(self)
'''Default C{repr(self)}. ''' return repr(self)
'''(INTERNAL) Rename the instance' C{.name = self.name}.
@param inst: The instance (C{_Named}).
@return: The B{C{inst}}, named if not named before. ''' raise _IsNotError('valid', inst=inst)
inst.name = self.name
'''(INTERNAL) Set the instance' C{.name = self.name}.
@param inst: The instance (C{_Named}). @keyword name: Optional name, overriding C{self.name} (C{str}).
@return: The B{C{inst}}, named if not named before. '''
'''(INTERNAL) Base class with name. '''
'''(INTERNAL) To be overloaded. ''' pass
# def notImplemented(self, attr): # '''Raise error for a missing method, function or attribute. # # @param attr: Attribute name (C{str}). # # @raise NotImplementedError: No such attribute. # ''' # c = self.__class__.__name__ # return NotImplementedError('%s.%s' % (c, attr))
'''Check this and an other instance for type compatiblility.
@param other: The other instance (any C{type}). @keyword name: Optional, name for other (C{str}).
@return: C{None}.
@raise TypeError: Mismatch of this and B{C{other}} C{type}. ''' isinstance(other, self.__class__)): raise TypeError('type(%s) mismatch: %s vs %s' % (name, classname(other), self.classname))
'''(INTERNAL) Must be overloaded.
@param kwds: Optional, keyword arguments. ''' self._notOverloaded(self.toStr.__name__, **kwds)
# def toStr(self, *args, **kwds): # if kwds or args: # t = list('%s=%r' % t for t in sorted(kwds.items())) # if args: # t = map(repr, args) + t # s = ', '.join(t) # else: # s = super(self.__class__, self).__str__() # return s
'''(INTERNAL) To be overloaded.
@keyword kwds: Optional, keyword arguments.
@return: L{toStr}() plus keyword arguments (as C{str}). '''
# def toStr2(self, *args, **kwds) # if args or kwds: # s = self.toStr(*args, **kwds) # else: # s = super(self.__class__, self).__repr__() # return '%s(%s)' % (self.named, s) # clip(s)
'''(INTERNAL) Named C{dict} with key I{and} attribute access to the items. '''
_Named.name.fset(self, kwds.pop(_NAME_)) # see _Named.name raise ValueError('%s(%s) invalid: %r' % (self.classname, 'args', args,))
if name in dict.keys(self): dict.pop(name) elif name == _NAME_: dict.__setattr__(self, name, '') else: dict.__delattr__(self, name)
except KeyError: if name == _NAME_: return _Named.name.fget(self) return dict.__getattr__(self, name)
raise KeyError('%s[%r]' % (self.classname, key))
t = ', '.join('%s=%r' % t for t in self.items()) return '%s(%s)' % (self.name, t)
dict.__setitem__(self, name, value) # self[name] = value else:
raise KeyError('%s[%r] = %r' % (self.classname, key, value))
return dict.__repr__(self) # dict.__str__(self) fails
'''8-Dict C{(N, NE, E, SE, S, SW, W, NW)} of L{Geohash}es, providing key I{and} attribute access to the items. '''
'''(INTERNAL) Enum-like C{_NamedDict} with attribute access restricted to valid keys. '''
'''New C{_NamedEnum}.
@param name: Name (C{str}). '''
except KeyError: if name == _NAME_: return _NamedDict.name.fget(self) raise AttributeError("%s.%s doesn't exist" % (self.named, name))
return '\n'.join('%s.%s: %r,' % (self.name, n, v) for n, v in sorted(self.items()))
return (self.name + '.') + ', .'.join(sorted(self.keys()))
'''(INTERNAL) Check names against given, registered names. ''' and self.find(v) == a
'''Find a registered item.
@param item: The item to look for (any C{type}).
@return: If found the B{C{item}}'s name (C{str}), C{None} otherwise. '''
'''Registed a new item.
@param item: The item (any C{type}).
@return: The item name (C{str}).
@raise NameError: An B{C{item}} already registered with that name or the B{C{item}} has no, an empty or an invalid name.
@raise TypeError: The B{C{item}} type invalid. ''' raise TypeError('%s.%s: %r' % ('item', 'type', item))
raise ValueError except (AttributeError, ValueError): raise NameError('%s.%s %s: %r' % ('item', 'name', 'invalid', item)) raise NameError('%s.%s %s: %r' % (self.named, n, 'exists', item))
'''Remove a registered item.
@param name_or_item: Name (C{str}) of or the item (any C{type}).
@return: The unregistered item.
@raise NameError: No item with that B{C{name}}.
@raise ValueError: No such item. ''' raise ValueError('no such %r' % (name_or_item,)) except KeyError: raise NameError('no %s.%r' % (self.named, name))
'''(INTERNAL) Base class for items in a C{_NamedEnum} registery. '''
'''Compare this and an other item.
@return: C{True} if different, C{False} otherwise. '''
'''(INTERNAL) Format. '''
'''(INTERNAL) Add this item as B{C{enum.name}}.
@note: Don't register if name is empty or doesn't start with a letter. '''
def name(self): '''Get the I{registered, immutable} name (C{str}). '''
def name(self, name): '''Set the name, unless already registered.
@param name: New name (C{str}). ''' raise ValueError('%s, %s: %r' % ('registered', 'immutable', self))
'''Remove this instance from its C{_NamedEnum} registry.
@raise AssertionError: Mismatch of this and registered item.
@raise NameError: This item is unregistered. ''' enum = self._enum if enum and self.name and self.name in enum: item = enum.unregister(self.name) if item is not self: raise AssertionError('%r vs %r' % (item, self))
'''(INTERNAL) Named C{int}. ''' return "%s(%s)" % (self.named, int.__repr__(self))
return int.__str__(self)
'''(INTERNAL) Named C{str}. '''
'''(INTERNAL) Named C{tuple} with index I{and} attribute access to the items.
@note: This class is similar to Python's C{namedtuple}, but limited and lighter in setup and weight. '''
'''New L{_NamedTuple} initialized with B{C{positional}} arguments. ''' raise TypeError('%s.%s inot valid: %r' % (self.classname, '_Names_', ns)) raise ValueError('%s(%s) not valid: %r[%s] vs %s' % (self.classname, 'args', args, len(args), len(ns))) raise NameError('%s.%s not valid: %r' % (self.classname, '_Names_', _NAME_))
if name in self._Names_: raise TypeError('%s not mutable: %s .%s' % (self.classname, 'del', name)) elif name == _NAME_: tuple.__setattr__(self, name, '') else: tuple.__delattr__(self, name)
raise IndexError('%s.%s not valid: %r' % (self.classname, '<name>', name))
raise TypeError('%s not mutable: %s=%r' % (self.classname, name, value)) else:
'''Get the items as C{name, value} pairs (C{2-tuple}s). '''
'''(INTERNAL) Extend this C{_Tuple} with C{items} to an other C{namedTuple}. ''' (len(self._Names_) + len(items)) == len(namedTuple._Names_) and self._Names_ == namedTuple._Names_[:len(self)]): raise TypeError('%s%r vs %s%r' % (self.classname, self._Names_, namedTuple.__name__, namedTuple._Names_))
'''2-Tuple C{(initial, final)} bearings, both in compass C{degrees360}. '''
'''2-Tuple C{(latlonSW, latlonNE)} with the bounds' lower-left and upper-right corner as C{LatLon} instance. '''
'''4-Tuple C{(latS, lonW, latN, lonE)} with the bounds' lower-left C{(LatS, LowW)} and upper-right C{(latN, lonE)} corner lat- and longitudes. '''
'''3-Tuple C{(start, end, index)} for each edge of a I{clipped} path with the C{start} and C{end} points (C{LatLon}) of the portion of the edge inside or on the clip box and the C{index} (C{int}) of the edge in the original path. '''
'''3-Tuple C{(start, end, original)} for each edge of a I{clipped} polygon, the C{start} and C{end} points (C{LatLon}) of the portion of the edge inside or on the clip region and the C{original} indicates whether the edge is part of the original polygon or part of the clip region (C{bool}). '''
'''2-Tuple C{(meridional, prime_vertical)} of radii of curvature, both in C{meter}. '''
'''2-Tuple C{(destination, final)}, C{destination} in C{LatLon} and C{final} bearing in compass C{degrees360}. '''
'''2-Tuple C{(distance, initial)}, C{distance} in C{meter} and C{initial} bearing in compass C{degrees360}. '''
'''3-Tuple C{(distance, initial, final)}, C{distance} in C{meter} and C{initial} and C{final} bearing, both in compass C{degrees360}. '''
'''4-Tuple C{(distance2, delta_lat, delta_lon, unroll_lon2)} with the distance in C{degrees squared}, the latitudinal C{delta_lat} = B{C{lat2}}-B{C{lat1}}, the wrapped, unrolled and adjusted longitudinal C{delta_lon} = B{C{lon2}}-B{C{lon1}} and the C{unroll_lon2} unrollment for B{C{lon2}}.
@note: Use Function L{degrees2m} to convert C{degrees squared} to C{meter} as M{degrees2m(sqrt(distance2), ...)} or M{degrees2m(hypot(delta_lat, delta_lon), ...)}. '''
'''2-Tuple C{(easting, northing)}, both in C{meter}. '''
'''3-Tuple C{(easting, northing, height)}, all in C{meter}. '''
'''4-Tuple C{(easting, northing, azimuth, reciprocal)} for the Cassini-Soldner location with C{easting} and C{northing} in C{meters}, the C{azimuth} of easting direction azimuth and C{reciprocal} the reciprocal of azimuthal northing scale reciprocal, both in C{degrees}. '''
'''4-Tuple C{(easting, northing, convergence, scale)} in C{meter}, C{meter}, {degrees} and C{scalar}. '''
'''3-Tuple C{(easting, northing, radius)}, all in C{meter}. '''
'''2-Tuple C{(elevation, data_source)} in C{meter} and C{str}. '''
'''2-Tuple C{(height, model_name)}, geoid C{height} in C{meter} and C{model_name} as C{str}. '''
'''5-Tuple C{(lat, lon, egm84, egm96, egm2008)} for U{GeoidHeights.dat <https://SourceForge.net/projects/geographiclib/files/testdata/>} tests with the heights for 3 different EGM grids with C{-90.0 <= lat <= 90.0} and C{-180.0 <= lon <= 180.0} degrees (and C{lon} converted from the original C{0.0 <= EasterLon <= 360.0}). '''
'''2-Tuple C{(lat, lon)} in C{degrees[90]} and C{degrees[180]}. '''
'''(INTERNAL) Extend to a L{LatLon3Tuple}. '''
'''(INTERNAL) Extend to a L{LatLon4Tuple}. '''
'''3-Tuple C{(lat, lon, height)} in C{degrees[90]}, C{degrees[180]} and C{meter}. '''
'''(INTERNAL) Extend to a L{LatLon4Tuple}. '''
'''4-Tuple C{(lat, lon, height, datum)} in C{degrees90}, C{degrees180}, C{meter} and L{Datum}. '''
'''4-Tuple C{(lat, lon, azimuth, reciprocal)}, all in C{degrees} where C{azimuth} is the azimuth of easting direction and C{reciprocal} the reciprocal of azimuthal northing scale. '''
'''3-Tuple C{(lat, lon, datum)} in C{degrees[90]}, C{degrees[180]} and L{Datum}. '''
'''5-Tuple C{(lat, lon, datum, convergence, scale)} in C{degrees[90]}, C{degrees[180]}, L{Datum}, {degrees} and C{float}. '''
'''4-Tuple C{(lat, lon, convergence, scale)} in C{degrees}, C{degrees180}, C{degrees} and C{sclar}. '''
'''3-Tuple C{(lat, lon, precision)} in C{degrees}, C{degrees} and C{int}. '''
'''5-Tuple C{(lat, lon, precision, height, radius)} in C{degrees}, C{degrees}, C{int} and C{height} or C{radius} in C{meter} (or C{None} if missing). '''
'''4-Tuple C{(zone, digraph, easting, northing)}, C{zone} and C{digraph} as C{str}, C{easting} and C{northing} in C{meter}. '''
'''6-Tuple C{(zone, digraph, easting, northing, band, datum)}, C{zone}, C{digraph} and C{band} as C{str}, C{easting} and C{northing} in C{meter} and C{datum} a L{Datum}. '''
'''3-Tuple C{(closest, distance, angle)} of the C{closest} point on the polygon, either a C{LatLon} instance or a L{LatLon3Tuple}C{(lat, lon, height)} and the C{distance} and C{angle} to the C{closest} point are in C{meter} respectively compass C{degrees360}. '''
'''5-Tuple C{(lat, lon, distance, angle, height)} all in C{degrees}, except C{height}. The C{distance} is the L{equirectangular_} distance between the closest and the reference B{C{point}} in C{degrees}. The C{angle} from the reference B{C{point}} to the closest point is in compass C{degrees360}, see function L{compassAngle}. The C{height} is the (interpolated) height at the closest point in C{meter} or C{0}. '''
'''3-Tuple C{(north, east, down)}, all in C{degrees}. '''
'''2-Tuple C{(phi, lam)} with latitude C{phi} in C{radians[PI_2]} and longitude C{lam} in C{radians[PI]}.
@note: Using C{phi/lambda} for lat-/longitude in radians follows Chris Veness' U{convention <https://www.Movable-Type.co.UK/scripts/latlong.html>}. '''
'''(INTERNAL) Extend to a L{PhiLam3Tuple}. '''
'''3-Tuple C{(phi, lam, height)} with latitude C{phi} in C{radians[PI_2]}, longitude C{lam} in C{radians[PI]} and C{height} in C{meter}.
@note: Using C{phi/lamda} for lat-/longitude in radians follows Chris Veness' U{convention <https://www.Movable-Type.co.UK/scripts/latlong.html>}. '''
'''3-Tuple C{(x, y, ll)} in C{meter}, C{meter} and C{LatLon}. '''
'''2-Tuple C{(number, points)} with the C{number} of points and -possible reduced- C{list} or C{tuple} of C{points}. '''
'''2-Tuple C{(nrows, ncols)}, the number of rows and columns, both C{int}. '''
'''2-Tuple C{(zone, hemipole)} as C{int} and C{str}, where C{zone} is C{1..60} for UTM or C{0} for UPS and C{hemipole} C{'N'|'S'} is the UTM hemisphere or the UPS pole. '''
'''4-Tuple C{(zone, hemipole, easting, northing)} as C{str}, C{str}, C{meter} and C{meter}. '''
'''5-Tuple C{(zone, hemipole, easting, northing, band)} as C{int}, C{str}, C{meter}, C{meter} and C{band} letter, where C{zone} is C{1..60} for UTM or C{0} for UPS, C{hemipole} C{'N'|'S'} is the UTM hemisphere or the UPS pole and {band} is C{""} or the (longitudinal) UTM band C{'C'|'D'..'W'|'X'} or the (polar) UPS band C{'A'|'B'|'Y'|'Z'}. '''
'''8-Tuple C{(zone, hemipole, easting, northing, band, datum, convergence, scale)} as C{int}, C{str}, C{meter}, C{meter}, C{band} letter, C{Datum}, C{degrees} and C{float}, where C{zone} is C{1..60} for UTM or C{0} for UPS, C{hemipole} C{'N'|'S'} is the UTM hemisphere or the UPS pole and {band} is C{""} or the (longitudinal) UTM band C{'C'|'D'..'W'|'X'} or the (polar) UPS band C{'A'|'B'|'Y'|'Z'}. ''' 'band', 'datum', 'convergence', 'scale')
'''5-Tuple C{(zone, band, hemipole, lat, lon)} as C{int}, C{str}, C{str}, C{degrees90} and C{degrees180}, where C{zone} is C{1..60} for UTM or C{0} for UPS, {band} is C{""} or the (longitudinal) UTM band C{'C'|'D'..'W'|'X'} or (polar) UPS band C{'A'|'B'|'Y'|'Z'} and C{hemipole} C{'N'|'S'} is the UTM hemisphere or the UPS pole. '''
'''3-Tuple C{(x, y, z)} of (geocentric) components, all in C{meter} or C{units}. '''
'''(INTERNAL) Extend to a L{Vector4Tuple}. '''
'''4-Tuple C{(x, y, z, h)} of (geocentric) components, all in C{meter} or C{units}. '''
'''Return the instance' class name optionally prefixed with the module name.
@param inst: The object (any C{type}). @keyword prefixed: Include the module name (C{bool}), see function L{classnaming}.
@return: The B{C{inst}}'s C{[module.]class} name (C{str}). ''' except AttributeError: n = 'Nn' if prefixed is None else False): try: m = inst.__module__ n = '.'.join(m.split('.')[-1:] + [n]) except AttributeError: pass
'''Get/set the default naming for C{[module.]class} names.
@keyword prefixed: Include the module name (C{bool}).
@return: Previous class naming setting (C{bool}). ''' t = _Named._classnaming if prefixed in (True, False): _Named._classnaming = prefixed return t
'''Return the string representation of an instance.
@param inst: The instance (any C{type}). @param args: Optional positional arguments. @keyword kwds: Optional keyword arguments.
@return: The B{C{inst}}'s representation (C{str}). '''
'''Get the name of an instance.
@param inst: The object (any C{type}).
@return: The instance' name (C{str}) or C{""}. '''
if __name__ == '__main__':
from pygeodesy.lazily import _FOR_DOCS if not _FOR_DOCS: raise NameError('usage: %s' % ('env PYGEODESY_FOR_DOCS=1 python ...',))
ls = set(locals().keys()) - \ set(('fStr', 'ls', 'n', 'property_RO', 'issubclassof', 'unStr')) for n in __all__: if n not in ls: raise NameError('%s %r not in %s' % ('__all__', n, 'locals')) for n in ls: if n not in __all__ and not n.startswith('_'): raise NameError('%s %r not in %s' % ('locals', n, '__all__'))
print('all %s %s OK' % (len(ls), 'locals'))
# **) MIT License # # Copyright (C) 2016-2020 -- mrJean1 at Gmail -- All Rights Reserved. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE.
# % env PYGEODESY_FOR_DOCS=1 python -m pygeodesy.named # all 71 locals OK |