def _all(globalocals): from pygeodesy.interns import NN as _NN, _attribute_, _COMMASPACE_, \ _DOT_, _module_, _s_ # PYCHOK expected from pygeodesy.streprs import Fmt as _Fmt # 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(_DOT_)) for mod, attrs in lazily._ALL_LAZY.enums(): if mod not in globalocals: t = _DOT_(_pygeodesy_, mod) raise ImportError('missing %s%s: %s' % (_module_, _NN, t)) ns.append(mod) # check that all other public attributes do exist if attrs and isinstance(attrs, tuple): t = tuple(a for a in attrs if a not in globalocals) if t: s = _Fmt.SQUARE(_s_, len(t)) if len(t) > 1 else _NN t = _COMMASPACE_.join( _DOT_(_pygeodesy_, mod, a) for a in t) raise ImportError('missing %s%s: %s' % (_attribute_, s, t)) 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
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 _notError(inst, name, args, kwds): # PYCHOK no cover '''(INTERNAL) Format an error message. ''' n = _DOT_(classname(inst, prefixed=True), _dunder_name(name, name)) m = _COMMASPACE_.join( modulename(c, prefixed=True) for c in inst.__class__.__mro__[1:-1]) return _COMMASPACE_(unstr(n, *args, **kwds), Fmt.PAREN(_MRO_, m))
def _immutable(inst, value): '''Throws an C{AttributeError}, always. ''' from pygeodesy.named import classname s = _DOT_(repr(inst), self.name) s = _EQUALSPACED_(s, repr(value)) t = _SPACE_(_immutable_, classname(self)) raise _AttributeError(s, txt=t)
def __getattr__(self, name): '''Get the value of an attribute or item by B{C{name}}. ''' try: return tuple.__getitem__(self, self._Names_.index(name)) except IndexError: raise _IndexError(_DOT_(self.classname, Fmt.ANGLE(_name_)), name) except ValueError: return tuple.__getattribute__(self, name)
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, Fmt.PAREN(c, name)) if self_name: n = _SPACE_(n, repr(self_name)) return n
def __setattr__(self, name, value): '''Set attribute or item B{C{name}} to B{C{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): '''Delete an attribute by B{C{name}}. @note: Items can not be deleted. ''' if name in self._Names_: raise _TypeError(_del_, _DOT_(self.classname, name), txt=_immutable_) elif name in (_name_, _name): _Named.__setattr__(self, name, NN) # XXX _Named.name.fset(self, NN) else: tuple.__delattr__(self, name)
def _validate(self, _OK=False): # see .EcefMatrix '''(INTERNAL) One-time check of C{_Names_} and C{_Units_} for each C{_NamedUnit} I{sub-class separately}. ''' ns = self._Names_ if not (isinstance(ns, tuple) and len(ns) > 1): # XXX > 0 raise _TypeError(_DOT_(self.classname, _Names_), ns) for i, n in enumerate(ns): if not _xvalid(n, _OK=_OK): t = Fmt.SQUARE(_Names_, i) raise _ValueError(_DOT_(self.classname, t), n) us = self._Units_ if not isinstance(us, tuple): raise _TypeError(_DOT_(self.classname, _Units_), us) if len(us) != len(ns): raise LenError(self.__class__, _Units_=len(us), _Names_=len(ns)) for i, u in enumerate(us): if not (u is None or callable(u)): t = Fmt.SQUARE(_Units_, i) raise _TypeError(_DOT_(self.classname, t), u) self.__class__._validated = True
def clipCS4(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, retain null edges if inside (C{bool}). @return: Yield a L{ClipCS4Tuple}C{(start, end, i, j)} for each edge of the I{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=clipCS4.__name__) n, pts = _pts2(points, closed, inull) i, m = _imdex2(closed, n) cmbp = cs.code4(pts[i]) for j in range(m, n): c1, m1, b1, p1 = cmbp c2, m2, b2, p2 = cmbp = cs.code4(pts[j]) if c1 & c2: # edge outside pass elif cs.edge(p1, p2): 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 ClipCS4Tuple(p1, p2, i, j) break if c1 & c2: # edge outside break else: # PYCHOK no cover raise _AssertionError(_DOT_(cs.name, 'for_else')) elif inull and not c1: # null edge yield ClipCS4Tuple(p1, p1, i, j) elif inull and not c2: yield ClipCS4Tuple(p2, p2, i, j) i = j
def _all_imports(**more): '''(INTERNAL) Build C{dict} of all lazy imports. ''' # imports naming conventions stored below - [<key>] = <from>: # import <module> - [<module>] = <module> # from <module> import <attr> - [<attr>] = <module> # from pygeodesy import <attr> - [<attr>] = <attr> # from <module> import <attr> as <name> - [<name>] = <module>.<attr> imports = _Dict() imports_add = imports.add for ALL in (_ALL_LAZY, _ALL_OVERRIDDEN, more): for mod, attrs in ALL.items(): if isinstance(attrs, tuple) and not mod.startswith(_UNDER_): imports_add(mod, mod) for attr in attrs: attr, _, as_attr = attr.partition(' as ') if as_attr: imports_add(as_attr, _DOT_(mod, attr), _deprecated_) else: imports_add(attr, mod) return imports
def convertRefFrame(self, reframe2): '''Convert this point to an other reference frame. @arg reframe2: Reference frame to convert I{to} (L{RefFrame}). @return: The converted point (ellipsoidal C{LatLon}) or this point if conversion is C{nil}. @raise TRFError: No B{C{.reframe}} or no conversion available from B{C{.reframe}} to B{C{reframe2}}. @raise TypeError: The B{C{reframe2}} is not a L{RefFrame}. @example: >>> p = LatLon(51.4778, -0.0016, reframe=RefFrames.ETRF2000) # default Datums.WGS84 >>> p.convertRefFrame(RefFrames.ITRF2014) # 51.477803°N, 000.001597°W, +0.01m ''' from pygeodesy.trf import RefFrame, _reframeTransforms _xinstanceof(RefFrame, reframe2=reframe2) if not self.reframe: t = _SPACE_(_DOT_(repr(self), 'reframe'), MISSING) raise TRFError(_no_(_conversion_), txt=t) ts = _reframeTransforms(reframe2, self.reframe, self.epoch) if ts: c = self.toCartesian() for t in ts: c = c._applyHelmert(t, False) ll = c.toLatLon(datum=self.datum, LatLon=self.classof, epoch=self.epoch, reframe=reframe2) # ll.reframe, ll.epoch = reframe2, self.epoch else: ll = self return ll
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 isstr(n) and isidentifier(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 __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(_DOT_(_pygeodesy_, mod), parent) pkg = getattr(imported, _p_a_c_k_a_g_e_, None) if pkg not in packages: # invalid package raise LazyImportError(_DOT_(mod, _p_a_c_k_a_g_e_), repr(pkg)) # 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 (_a_l_l_,): # XXX '_d_i_r_', '_m_e_m_b_e_r_s_'? 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 C{_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 _error(arg): n = _DOT_(Fstr.__name__, self.name or self) return _SPACE_(n, _PERCENT_, repr(arg))
def _DOT_(self, attr): return _DOT_(self._name, attr) # PYCHOK _name
def _lazy_import2(_pygeodesy_): # MCCABE 15 '''Check for and set up C{lazy import}. @arg _pygeodesy_: 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_(_pygeodesy_, _lazy_import2.__name__)) raise LazyImportError(t, txt=_Python_(_sys)) import_module, package, parent = _lazy_init3(_pygeodesy_) packages = (parent, '__main__', NN, _DOT_(parent, _deprecated_)) 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(_DOT_(_pygeodesy_, mod), parent) pkg = getattr(imported, _p_a_c_k_a_g_e_, None) if pkg not in packages: # invalid package raise LazyImportError(_DOT_(mod, _p_a_c_k_a_g_e_), repr(pkg)) # 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 (_a_l_l_,): # XXX '_d_i_r_', '_m_e_m_b_e_r_s_'? 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 C{_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 _all_missing2(_all_): '''(INTERNAL) Get diffs between pygeodesy.__all__ and lazily._all_imports. ''' _alzy = _all_imports(**_NamedEnum_RO((a, ()) for a in _ALL_INIT)) return ((_DOT_('lazily', _all_imports.__name__), _COMMASPACE_.join(a for a in _all_ if a not in _alzy)), (_DOT_('pygeodesy', _a_l_l_), _COMMASPACE_.join(a for a in _alzy if a not in _all_)))
def _DOT_(self, *names): '''(INTERNAL) Period-join C{self.name} and C{names}. ''' return _DOT_(self.name, *names)
def named4(self): '''Get the C{package.module.class} name I{and/or} the name or C{""} (C{str}). ''' return _xjoined_(_DOT_(self.__module__, self.__class__.__name__), self.name)