def _all(globalocals): from pygeodesy.interns import _dot_ # PYCHOK expected # collect all public module and attribute names and check # that modules are imported from this package, 'pygeodesy' # (but the latter only when not bundled with PyInstaller or # Py2Exe, since the file-layout is different. Courtesy of # GilderGeek<https://GitHub.com/mrJean1/PyGeodesy/issues/31>) ns = list(lazily._ALL_INIT) # XXX ps = () if _isfrozen else set([_pygeodesy] + __name__.split('.')) for mod, attrs in lazily._ALL_LAZY.enums(): if mod not in globalocals: raise ImportError('missing %s: %s' % ('module', _dot_(_pygeodesy, mod))) ns.append(mod) # check that all other public attributes do exist if attrs and isinstance(attrs, tuple): for a in attrs: if a not in globalocals: raise ImportError('missing %s: %s' % ('attribute', _dot_(mod, a))) ns.extend(attrs) # XXX if ps: # check that mod is a _pygeodesy module # XXX m = globalocals[mod] # assert(m.__name__ == mod) # XXX f = getattr(m, '__file__', NN) # XXX d = dirname(abspath(f)) if f else pygeodesy_abspath # XXX p = getattr(m, '__package__', NN) or _pygeodesy # XXX if p not in ps or d != pygeodesy_abspath: # XXX raise ImportError('foreign module: %s from %r' % (_dot_(p, mod), f or p)) return tuple(set(ns)) # remove duplicates, only R_M?
def _all_missing2(_all_): '''(INTERNAL) Get deltas between pygeodesy.__all__ and lazily._all_imports. ''' _alzy = _all_imports(**_NamedEnum_RO((a, ()) for a in _ALL_INIT)) return ((_dot_('lazily', _all_imports.__name__), _COMMA_SPACE_.join(a for a in _all_ if a not in _alzy)), (_dot_('pygeodesy', '__all__'), _COMMA_SPACE_.join(a for a in _alzy if a not in _all_)))
def __new__(cls, *args): '''New L{_NamedTuple} initialized with B{C{positional}} arguments. ''' self = tuple.__new__(cls, args) ns = self._Names_ if not (isinstance(ns, tuple) and len(ns) > 1): # XXX > 0 raise _TypeError(_dot_(self.classname, _Names_), ns) if len(ns) != len(args) or not ns: raise LenError(cls, args=len(args), ns=len(ns)) if _name_ in ns: t = unstr(_dot_(self.classname, _Names_), *ns) raise _NameError(_name_, _name_, txt=t) return self
def __getattr__(name): # __getattr__ only for Python 3.7+ # only called once for each undefined pygeodesy attribute if name in imports: # importlib.import_module() implicitly sets sub-modules # on this module as appropriate for direct imports (see # note in the _lazy_import.__doc__ above). mod, _, attr = imports[name].partition(_DOT_) if mod not in imports: raise LazyImportError('no module', txt=_dot_(parent, mod)) imported = import_module(import_ + mod, parent) # XXX '.' + mod if imported.__package__ not in (parent, '__main__', ''): raise LazyImportError(_dot_(mod, '__package__'), imported.__package__) # import the module or module attribute if attr: imported = getattr(imported, attr, _Missing) elif name != mod: imported = getattr(imported, name, _Missing) if imported is _Missing: raise LazyImportError('no attribute', txt=_dot_(mod, attr or name)) elif name in ('__all__', ): # XXX '__dir__', '__members__'? imported = _ALL_INIT + tuple(imports.keys()) mod = NN else: raise LazyImportError('no module or attribute', txt=_dot_(parent, name)) setattr(package, name, imported) if isLazy > 1: z = NN if mod and mod != name: z = ' from .%s' % (mod, ) if isLazy > 2: # sys._getframe(1) ... 'importlib._bootstrap' line 1032, # may throw a ValueError('call stack not deep enough') try: f = sys._getframe(2) # get importing file and line n = f.f_code.co_filename if cwdir and n.startswith(cwdir): n = n[len(cwdir):] z = '%s by %s line %d' % (z, n, f.f_lineno) except ValueError: # PYCHOK no cover pass print('# lazily imported %s%s' % (_dot_(parent, name), z)) return imported # __getattr__
def __getattr__(self, attr): try: return self[attr] except KeyError: t = '%s %s' % (_dot_(self._name, attr), _doesn_t_exist_ ) # PYCHOK _name raise AttributeError(t)
def discrete(self, points, fraction=None): '''Compute the C{forward, discrete Fréchet} distance. @arg points: Second set of points (C{LatLon}[], L{Numpy2LatLon}[], L{Tuple2LatLon}[] or C{other}[]). @kwarg fraction: Index fraction (C{float} in L{EPS}..L{EPS1}) to interpolate intermediate B{C{points}} or use C{None}, C{0} or C{1} for no intermediate B{C{points}} and no I{fractional} indices. @return: A L{Frechet6Tuple}C{(fd, fi1, fi2, r, n, units)}. @raise FrechetError: Insufficient number of B{C{points}} or an invalid B{C{point}} or B{C{fraction}}. @raise RecursionError: Recursion depth exceeded, see U{sys.getrecursionlimit() <https://docs.Python.org/3/library/sys.html#sys.getrecursionlimit>}. ''' n2, ps2 = self._points2(points) f2 = _fraction(fraction, n2) p2 = self.points_fraction if f2 < EPS1 else self.points_ # PYCHOK expected f1 = self.fraction p1 = self.points_fraction if f1 < EPS1 else self.points_ # PYCHOK expected def dF(fi1, fi2): return self.distance(p1(self._ps1, fi1), p2(ps2, fi2)) try: return _frechet_(self._n1, f1, n2, f2, dF, self.units) except TypeError as x: t = _dot_(self.classname, self.discrete.__name__) raise FrechetError(t, txt=str(x))
def __getattr__(self, name): try: return tuple.__getitem__(self, self._Names_.index(name)) except IndexError: raise _IndexError(_dot_(self.classname, '<name>'), name) except ValueError: return tuple.__getattribute__(self, name)
def _notError(inst, name, args, kwds): # PYCHOK no cover '''(INTERNAL) Format an error message. ''' n = _dot_(classname(inst, prefixed=True), _dunder_name(name, name)) m = _COMMA_SPACE_.join( modulename(c, prefixed=True) for c in inst.__class__.__mro__[1:-1]) t = '%s, MRO(%s)' % (unstr(n, *args, **kwds), m) return t
def _callname(name, class_name, self_name, up=1): # imported by .points '''(INTERNAL) Assemble the name for an invokation. ''' n, c = class_name, callername(up=up + 1) if c: n = _dot_(n, _item_ps(c, name)) if self_name: n = '%s %r' % (n, self_name) return n
def __setattr__(self, name, value): if name in self._Names_: raise _TypeError(_dot_(self.classname, name), value, txt=_immutable_) elif name in (_name_, _name): _Named.__setattr__(self, name, value) # XXX _Named.name.fset(self, value) else: tuple.__setattr__(self, name, value)
def __delattr__(self, name): if name in self._Names_: raise _TypeError('del', _dot_(self.classname, name), txt=_immutable_) elif name in (_name_, _name): _Named.__setattr__(self, name, '') # XXX _Named.name.fset(self, '') else: tuple.__delattr__(self, name)
def __getattr__(name): # __getattr__ only for Python 3.7+ # only called once for each undefined pygeodesy attribute if name in imports: # importlib.import_module() implicitly sets sub-modules # on this module as appropriate for direct imports (see # note in the _lazy_import.__doc__ above). mod, _, attr = imports[name].partition(_DOT_) if mod not in imports: raise LazyImportError('no module', txt=_dot_(parent, mod)) imported = import_module(import_ + mod, parent) # XXX '.' + mod if imported.__package__ not in (parent, '__main__', NN): raise LazyImportError(_dot_(mod, '__package__'), imported.__package__) # import the module or module attribute if attr: imported = getattr(imported, attr, _Missing) elif name != mod: imported = getattr(imported, name, _Missing) if imported is _Missing: raise LazyImportError('no attribute', txt=_dot_(mod, attr or name)) elif name in ('__all__', ): # XXX '__dir__', '__members__'? imported = _ALL_INIT + tuple(imports.keys()) mod = NN else: raise LazyImportError('no module or attribute', txt=_dot_(parent, name)) setattr(package, name, imported) if isLazy > 1: z = NN if mod and mod != name: z = ' from .%s' % (mod, ) if isLazy > 2: try: # see _caller3 _, f, s = _caller3(2) z = '%s by %s line %d' % (z, f, s) except ValueError: # PYCHOK no cover pass print('# lazily imported %s%s' % (_dot_(parent, name), z)) return imported # __getattr__
def clipCS3(points, lowerleft, upperright, closed=False, inull=False): '''Clip a path against a rectangular clip box using the U{Cohen-Sutherland <https://WikiPedia.org/wiki/Cohen-Sutherland_algorithm>} algorithm. @arg points: The points (C{LatLon}[]). @arg lowerleft: Bottom-left corner of the clip box (C{LatLon}). @arg upperright: Top-right corner of the clip box (C{LatLon}). @kwarg closed: Optionally, close the path (C{bool}). @kwarg inull: Optionally, include null edges if inside (C{bool}). @return: Yield a L{ClipCS3Tuple}C{(start, end, index)} for each edge of the clipped path. @raise ClipError: The B{C{lowerleft}} and B{C{upperright}} corners specify an invalid clip box. @raise PointsError: Insufficient number of B{C{points}}. ''' cs = _CS(lowerleft, upperright, name=clipCS3.__name__) n, pts = _points2(points, closed, inull) i, m = _imdex2(closed, n) cmbp = cs.code4(pts[i]) for i in range(m, n): c1, m1, b1, p1 = cmbp c2, m2, b2, p2 = cmbp = cs.code4(pts[i]) if c1 & c2: # edge outside continue if not cs.edge(p1, p2): if inull: # null edge if not c1: yield ClipCS3Tuple(p1, p1, i) elif not c2: yield ClipCS3Tuple(p2, p2, i) continue for _ in range(5): if c1: # clip p1 c1, m1, b1, p1 = m1(b1, p1) elif c2: # clip p2 c2, m2, b2, p2 = m2(b2, p2) else: # inside if inull or _neq(p1, p2): yield ClipCS3Tuple(p1, p2, i) break if c1 & c2: # edge outside break else: # PYCHOK no cover raise _AssertionError(_dot_(cs.name, 'for_else'))
def intersect(self, p1, p2, edge): # compute intersection # of polygon edge p1 to p2 and the current clip edge, # where p1 and p2 are known to NOT be located on the # same side or on top of the current clip edge # <https://StackOverflow.com/questions/563198/ # how-do-you-detect-where-two-line-segments-intersect> fy = float(p2.lat - p1.lat) fx = float(p2.lon - p1.lon) fp = fy * self._dx - fx * self._dy if abs(fp) < EPS: # PYCHOK no cover raise _AssertionError(_dot_(self.name, self.intersect.__name__)) r = fsum_(self._xy, -p1.lat * self._dx, p1.lon * self._dy) / fp y = p1.lat + r * fy x = p1.lon + r * fx return _LLi_(y, x, p1.classof, edge)
def modulename(clas, prefixed=None): '''Return the class name optionally prefixed with the module name. @arg clas: The class (any C{class}). @kwarg prefixed: Include the module name (C{bool}), see function C{classnaming}. @return: The B{C{class}}'s C{[module.]class} name (C{str}). ''' try: n = clas.__name__ except AttributeError: n = '--' if prefixed or (classnaming() if prefixed is None else False): try: m = clas.__module__.rsplit(_DOT_, 1) n = _dot_(*(m[1:] + [n])) except AttributeError: pass return n
def register(self, item): '''Registed a new item. @arg 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. ''' try: n = item.name if not (n and n.replace(_UNDERSCORE_, NN).isalnum() and isstr(n)): raise ValueError except (AttributeError, ValueError, TypeError) as x: raise _NameError(_dot_('item', _name_), item, txt=str(x)) if n in self: raise _NameError(self._dot_(n), item, txt='exists') if not (self._item_Classes and isinstance(item, self._item_Classes)): raise _TypesError(self._dot_(n), item, *self._item_Classes) self[n] = item
def _lazy_import2(_package_): # MCCABE 15 '''Check for and set up lazy importing. @arg _package_: The name of the package (C{str}) performing the imports, to help facilitate resolving relative imports, usually C{__package__}. @return: 2-Tuple C{(package, getattr)} of the importing package for easy reference within itself and the callable to be set to `__getattr__`. @raise LazyImportError: Lazy import not supported or not enabled, an import failed or the package name or module name or attribute name is invalid or does not exist. @note: This is the original function U{modutil.lazy_import <https://GitHub.com/brettcannon/modutil/blob/master/modutil.py>} modified to handle the C{__all__} and C{__dir__} attributes and call C{importlib.import_module(<module>.<name>, ...)} without causing a C{ModuleNotFoundError}. @see: The original U{modutil<https://PyPi.org/project/modutil>} and U{PEP 562<https://www.Python.org/dev/peps/pep-0562>}. ''' if _sys.version_info[:2] < (3, 7): # not supported before 3.7 t = 'no ' + _dot_(_package_, _lazy_import2.__name__) raise LazyImportError(t, txt='Python ' + _sys.version.split()[0]) import_module, package, parent = _lazy_init3(_package_) import_ = _dot_(_package_, NN) # namespace imports = _all_imports() def __getattr__(name): # __getattr__ only for Python 3.7+ # only called once for each undefined pygeodesy attribute if name in imports: # importlib.import_module() implicitly sets sub-modules # on this module as appropriate for direct imports (see # note in the _lazy_import.__doc__ above). mod, _, attr = imports[name].partition(_DOT_) if mod not in imports: raise LazyImportError('no module', txt=_dot_(parent, mod)) imported = import_module(import_ + mod, parent) # XXX '.' + mod if imported.__package__ not in (parent, '__main__', NN): raise LazyImportError(_dot_(mod, '__package__'), imported.__package__) # import the module or module attribute if attr: imported = getattr(imported, attr, _Missing) elif name != mod: imported = getattr(imported, name, _Missing) if imported is _Missing: raise LazyImportError('no attribute', txt=_dot_(mod, attr or name)) elif name in ('__all__', ): # XXX '__dir__', '__members__'? imported = _ALL_INIT + tuple(imports.keys()) mod = NN else: raise LazyImportError('no module or attribute', txt=_dot_(parent, name)) setattr(package, name, imported) if isLazy > 1: z = NN if mod and mod != name: z = ' from .%s' % (mod, ) if isLazy > 2: try: # see _caller3 _, f, s = _caller3(2) z = '%s by %s line %d' % (z, f, s) except ValueError: # PYCHOK no cover pass print('# lazily imported %s%s' % (_dot_(parent, name), z)) return imported # __getattr__ return package, __getattr__ # _lazy_import2
def _dot_(self, name): '''(INTERNAL) Period-join C{self.name} and C{name}. ''' return _dot_(self.name, name)
def __setattr__(self, attr, value): t = 'Read_Only %s = %r' % (_dot_(self._name, attr), value ) # PYCHOK _name raise TypeError(t)
def name2(self): '''Get the conic and datum names as "conic.datum" (C{str}). ''' return _dot_(self.name, self.datum.name)
def nop4(self, b, p): # PYCHOK no cover if p: # should never get here raise _AssertionError(_dot_(self.name, self.nop4.__name__)) return _CS._IN, self.nop4, b, p
def toLatLon(self, LatLon=None, datum=Datums.WGS84): '''Convert this OSGR coordinate to an (ellipsoidal) geodetic point. While OS grid references are based on the OSGB36 datum, the I{Ordnance Survey} have deprecated the use of OSGB36 for lat-/longitude coordinates (in favour of WGS84). Hence, this method returns WGS84 by default with OSGB36 as an option, U{see<https://www.OrdnanceSurvey.co.UK/blog/2014/12/2>}. I{Note formulation implemented here due to Thomas, Redfearn, etc. is as published by OS, but is inferior to Krüger as used by e.g. Karney 2011.} @kwarg LatLon: Optional ellipsoidal class to return the geodetic point (C{LatLon}) or C{None}. @kwarg datum: Optional datum to convert to (L{Datum}, L{Ellipsoid}, L{Ellipsoid2}, L{Ellipsoid2} or L{a_f2Tuple}). @return: The geodetic point (B{C{LatLon}}) or a L{LatLonDatum3Tuple}C{(lat, lon, datum)} if B{C{LatLon}} is C{None}. @raise OSGRError: No convergence. @raise TypeError: If B{C{LatLon}} is not ellipsoidal or B{C{datum}} is invalid or conversion failed. @example: >>> from pygeodesy import ellipsoidalVincenty as eV >>> g = Osgr(651409.903, 313177.270) >>> p = g.toLatLon(eV.LatLon) # 52°39′28.723″N, 001°42′57.787″E >>> # to obtain (historical) OSGB36 lat-/longitude point >>> p = g.toLatLon(eV.LatLon, datum=Datums.OSGB36) # 52°39′27.253″N, 001°43′04.518″E ''' if self._latlon: return self._latlon3(LatLon, datum) E = self.datum.ellipsoid # _Datums_OSGB36.ellipsoid, Airy130 a_F0 = E.a * _F0 b_F0 = E.b * _F0 e, n = self.easting, self.northing n_N0 = n - _N0 a, m = _A0, n_N0 sa = Fsum(a) for self._iteration in range(1, _TRIPS): a = sa.fsum_(m / a_F0) m = n_N0 - b_F0 * _M(E.Mabcd, a) # meridional arc if abs(m) < _10um: break else: t = _dot_(_item_ps(self.classname, self.toStr(prec=-3)), self.toLatLon.__name__) raise OSGRError(_no_convergence_, txt=t) sa, ca = sincos2(a) s = E.e2s2(sa) # r, v = E.roc2_(sa, _F0) v = a_F0 / sqrt(s) # nu r = v * E.e12 / s # rho = a_F0 * E.e12 / pow(s, 1.5) == a_F0 * E.e12 / (s * sqrt(s)) vr = v / r # == s / E.e12 x2 = vr - 1 # η2 ta = tan(a) v3, v5, v7 = fpowers(v, 7, 3) # PYCHOK false! ta2, ta4, ta6 = fpowers(ta**2, 3) # PYCHOK false! tar = ta / r V4 = (a, tar / (2 * v), tar / (24 * v3) * fdot( (1, 3, -9), 5 + x2, ta2, ta2 * x2), tar / (720 * v5) * fdot( (61, 90, 45), 1, ta2, ta4)) csa = 1.0 / ca X5 = (_B0, csa / v, csa / (6 * v3) * fsum_(vr, ta2, ta2), csa / (120 * v5) * fdot( (5, 28, 24), 1, ta2, ta4), csa / (5040 * v7) * fdot( (61, 662, 1320, 720), 1, ta2, ta4, ta6)) d, d2, d3, d4, d5, d6, d7 = fpowers(e - _E0, 7) # PYCHOK false! a = fdot(V4, 1, -d2, d4, -d6) b = fdot(X5, 1, d, -d3, d5, -d7) r = _LLEB(degrees90(a), degrees180(b), datum=self.datum, name=self.name) r._iteration = self._iteration # only ellipsoidal LatLon self._latlon = r return self._latlon3(LatLon, datum)
if __name__ == '__main__': from sys import argv, exit # PYCHOK shadows exit from pygeodesy.lazily import _FOR_DOCS if not _FOR_DOCS: exit('%s\n' % (' '.join('usage: env PYGEODESY_FOR_DOCS=1 python -m'.split() + argv), )) ls = locals() for n in __all__: if n not in ls: raise NameError('%s %r not in %s' % ('__all__', n, _dot_('named', 'locals'))) for n, o in ls.items(): if n not in __all__ and not n.startswith(_UNDERSCORE_) \ and getattr(o, '__module__', '') == __name__: raise NameError('%s %r not in %s' % ('locals', n, _dot_('named', '__all__'))) print('%s: %s vs %s OK' % (argv[0], '__all__', '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