def callername(up=1, dflt=NN, source=False): '''Get the name of the calling callable. @kwarg up: Number of call stack frames up (C{int}). @kwarg dflt: Default return value (C{any}). @kwarg source: Include source file name and line number (C{bool}). @return: Name of the non-internal callable (C{str}) or B{C{dflt}} if none found. ''' try: from sys import _getframe for u in range(up, up + 32): f = _getframe(u) n = f.f_code.co_name if n and (n.startswith(_DUNDER_) or not n.startswith(_UNDERSCORE_)): if source: from os.path import basename n = NN.join( (n, _AT_, basename(f.f_code.co_filename), _COLON_, str(f.f_lineno))) return n except (AttributeError, ImportError): pass return dflt
def encode(lat, lon, precision=3, height=None, radius=None): # MCCABE 14 '''Encode a lat-/longitude as a C{georef} of the given precision. @arg lat: Latitude (C{degrees}). @arg lon: Longitude (C{degrees}). @kwarg precision: Optional, the desired C{georef} resolution and length (C{int} 0..11). @kwarg height: Optional, height in C{meter}, see U{Designation of area <https://WikiPedia.org/wiki/World_Geographic_Reference_System>}. @kwarg radius: Optional, radius in C{meter}, see U{Designation of area <https://WikiPedia.org/wiki/World_Geographic_Reference_System>}. @return: The C{georef} (C{str}). @raise RangeError: Invalid B{C{lat}} or B{C{lon}}. @raise WGRSError: Invalid B{C{precision}}, B{C{height}} or B{C{radius}}. @note: The B{C{precision}} value differs from U{Georef<https:// GeographicLib.SourceForge.io/html/classGeographicLib_1_1Georef.html>}. The C{georef} length is M{2 * (precision + 1)} and the C{georef} resolution is I{15°} for B{C{precision}} 0, I{1°} for 1, I{1′} for 2, I{0.1′} for 3, I{0.01′} for 4, ... M{10**(2 - precision)}. ''' def _option(name, m, m2_, K): f = Scalar_(m, name=name, Error=WGRSError) return '%s%d' % (name[0].upper(), int(m2_(f * K) + 0.5)) def _pstr(p, x): return '%0*d' % (p, x) p = _2Precision(precision) lat, lon, _ = _2fllh(lat, lon) if lat == 90: lat *= EPS1_2 xt, xd, x = _2divmod3(lon, _LonOrig_M_) yt, yd, y = _2divmod3(lat, _LatOrig_M_) g = _LonTile[xt], _LatTile[yt] if p > 0: g += _DegChar[xd], _DegChar[yd] p -= 1 if p > 0: d = pow(_Base, _MaxPrec - p) x = _pstr(p, x // d) y = _pstr(p, y // d) g += x, y if radius is not None: # R before H g += _option(_radius_, radius, m2NM, 1.0), if height is not None: # H is last g += _option(_height_, height, m2ft, 1e-3), return NN.join(g) # XXX Georef(''.join(g))
def _DDDMMSS_(strDDDMMSS, suffix, sep, clip): S = suffix.upper() if isstr(strDDDMMSS): t = strDDDMMSS.strip() if sep: t = t.replace(sep, NN).strip() s = t[:1] # sign or digit P = t[-1:] # compass point, digit or dot t = t.lstrip(_PLUSMINUS_).rstrip(S).strip() f = t.split(_DOT_) d = len(f[0]) f = NN.join(f) if 1 < d < 8 and f.isdigit() and ( (P in S and s.isdigit()) or (P.isdigit() and s in '-0123456789+' # PYCHOK indent and S in ((_NS_, _EW_) + _WINDS))): # check [D]DDMMSS form and compass point X = _EW_ if (d & 1) else _NS_ if not (P in X or (S in X and (P.isdigit() or P == _DOT_))): t = 'DDDMMSS'[d & 1 ^ 1:d | 1], X[:1], X[1:] raise ParseError('form %s applies %s-%s' % t) f = 0 # fraction else: # try other forms return _DMS2deg(strDDDMMSS, S, sep, clip) else: # float or int to [D]DDMMSS[.fff] f = float(strDDDMMSS) s = _MINUS_ if f < 0 else NN P = _0_ # anything except _SW_ f, i = modf(abs(f)) t = Fmt.f(i, prec=0) # str(i) == 'i.0' d = len(t) # bump number of digits to match # the given, valid compass point if S in (_NS_ if (d & 1) else _EW_): t = _0_ + t d += 1 # P = S # elif d > 1: # P = (_EW_ if (d & 1) else _NS_)[0] if d < 4: # [D]DD[.ddd] if f: t = float(t) + f t = t, 0, 0 else: f += float(t[d - 2:]) if d < 6: # [D]DDMM[.mmm] t = t[:d - 2], f, 0 else: # [D]DDMMSS[.sss] t = t[:d - 4], t[d - 4:d - 2], f d = _dms2deg(s, P, *map2(float, t)) return clipDegrees(d, float(clip)) if clip else d
def encode(lat, lon, precision=1): # MCCABE 14 '''Encode a lat-/longitude as a C{garef} of the given precision. @arg lat: Latitude (C{degrees}). @arg lon: Longitude (C{degrees}). @kwarg precision: Optional, the desired C{garef} resolution and length (C{int} 0..2). @return: The C{garef} (C{str}). @raise RangeError: Invalid B{C{lat}} or B{C{lon}}. @raise GARSError: Invalid B{C{precision}}. @note: The C{garef} length is M{precision + 5} and the C{garef} resolution is B{30′} for B{C{precision}} 0, B{15′} for 1 and B{5′} for 2, respectively. ''' def _digit(x, y, m): return _Digits[m * (m - y - 1) + x + 1], def _str(chars, x, n): s, b = [], len(chars) for i in range(n): x, i = divmod(x, b) s.append(chars[i]) return tuple(reversed(s)) p = _2Precision(precision) lat, lon = _2fll(lat, lon) if lat == 90: lat *= EPS1_2 ix, x = _2divmod2(lon, _LonOrig_M_) iy, y = _2divmod2(lat, _LatOrig_M_) g = _str(_Digits, ix + 1, _LonLen) + _str(_Letters, iy, _LatLen) if p > 0: ix, x = divmod(x, _M3) iy, y = divmod(y, _M3) g += _digit(ix, iy, _M2) if p > 1: g += _digit(x, y, _M3) return NN.join(g)
def _error_init(Error, inst, name_value, fmt_name_value='%s (%r)', txt=_invalid_, **name_values): # by .lazily '''(INTERNAL) Format an error text and initialize an C{Error} instance. @arg Error: The error super-class (C{Exception}). @arg inst: Sub-class instance to be initialized (C{_Exception}). @arg name_value: Either just a value or several name, value, ... positional arguments (C{str}, any C{type}), in particular for name conflicts with keyword arguments of C{error_init} or which can't be used as C{name=value} keyword arguments. @kwarg name_value_fmt: Format for (name, value) (C{str}). @kwarg txt: Optional explanation of the error (C{str}). @kwarg name_values: One or more B{C{name=value}} pairs overriding any B{C{name_value}} positional arguments. ''' if name_values: t = _or(*(fmt_name_value % t for t in name_values.items())) # XXX sorted elif len(name_value) > 1: t = _or(*(fmt_name_value % t for t in zip(name_value[0::2], name_value[1::2]))) elif name_value: t = str(name_value[0]) else: t = '%s %s' % (_Missing, _Missing) if txt is None: x = NN else: x = str(txt) or _invalid_ c = _COMMA_ if _COLON_ in t else _COLON_ t = NN.join((t, c, _SPACE_, x)) Error.__init__(inst, t) # inst.__x_txt__ = x # hold explanation _cause_(inst) # no Python 3+ exception chaining _ename_(inst)
def callername(up=1, dflt=NN, source=False): '''Get the name of the calling callable. @kwarg up: Number of call stack frames up (C{int}). @kwarg dflt: Default return value (C{any}). @kwarg source: Include source file name and line number (C{bool}). @return: Name of the non-internal callable (C{str}) or B{C{dflt}} if none found. ''' try: # see .lazily._caller3 for u in range(up, up + 32): n, f, s = _caller3(u) if n and (n.startswith(_DUNDER_) or not n.startswith(_UNDERSCORE_)): if source: n = NN.join((n, _AT_, f, _COLON_, str(s))) return n except (AttributeError, ValueError): # PYCHOK no cover pass return dflt
def _toDMS(deg, form, prec, sep, ddd, suff): # MCCABE 15 by .units.py '''(INTERNAL) Convert degrees to C{str}, with/-out sign and/or suffix. ''' try: deg = float(deg) except (TypeError, ValueError) as x: raise _ValueError(deg=deg, txt=str(x)) form = form.lower() sign = form[:1] if sign in _MINUS_PLUS_: form = form[1:] else: sign = S_NUL if prec is None: z = p = _F_prec.get(form, 6) else: z = int(prec) p = abs(z) w = p + (1 if p else 0) d = abs(deg) if form in _F_symb: s_deg = s_min = s_sec = S_NUL # no symbols else: s_deg, s_min, s_sec = S_DEG, S_MIN, S_SEC F = _F_case.get(form, F_DMS) if F is F_DMS: # 'deg+min+sec' d, s = divmod(round(d * 3600, p), 3600) m, s = divmod(s, 60) t = NN.join((_0wpF(ddd, 0, d), s_deg, sep, _0wpF(2, 0, m), s_min, sep, _0wpF(w + 2, p, s))) s = s_sec elif F is F_DM: # 'deg+min' d, m = divmod(round(d * 60, p), 60) t = NN.join((_0wpF(ddd, 0, d), s_deg, sep, _0wpF(w + 2, p, m))) s = s_min elif F is F_D: # 'deg' t = _0wpF(ddd + w, p, d) s = s_deg elif F is F_RAD: t = '%.*F' % (p, radians(d)) s = S_RAD else: # F in (F__E, F__F, F__G) t = ('%.*' + F) % (p, d) s = S_NUL if z > 1: t = fstrzs(t, ap1z=F is F__G) if sign: if deg < 0: t = _MINUS_ + t elif deg > 0 and sign == _PLUS_: t = _PLUS_ + t elif suff: # and deg: # zero suffix? s += sep + suff return t + s