Coverage for pygeodesy/named.py : 94%

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 -*-
Classes C{_Named}, C{_NamedDict} and C{_NamedTuple} and several subclasses thereof, all with nameable instances.
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.
@see: Module L{pygeodesy.namedTuples} for the C{Named-Tuples}. '''
issubclassof, _xcopy _IndexError, _IsnotError, LenError, _NameError, \ _NotImplementedError, _TypeError, _TypesError, \ _ValueError, UnitError, _xkwds, _xkwds_popitem _doesn_t_exist_, _DOT_, _DUNDER_, _dunder_name, \ _EQUAL_, _EQUALSPACED_, _exists_, _immutable_, \ _name_, _other_, _s_, _SPACE_, _UNDER_, _valid_, _vs_ property_doc_, property_RO, _update_all
# __DUNDER gets mangled in class
'''(INTERNAL) Join C{pref} and non-empty C{name}. '''
'''(INTERNAL) Set the instance' C{.name = B{name}}.
@arg inst: The instance (C{_Named}). @arg name: The name (C{str}). @kwarg force: Force name change (C{bool}).
@return: The B{C{inst}}, named if B{C{force}}d or not named before. '''
'''(INTERNAL) Get C{name} and C{up} for a named C{other}. ''' else: raise _AssertionError(name, other, txt=classname(inst, prefixed=True))
'''(INTERNAL) Return a C{_TypeError} for an incompatible, named C{other}. '''
'''(INTERNAL) Check valid attribute name C{name}. ''' and name != _name_ and (_OK or not name.startswith(_UNDER_)) and (not iskeyword(name)) and isidentifier(name)) else False
'''(INTERNAL) An C{dict} with both key I{and} attribute access to the C{dict} items. ''' '''Get an attribute or item by B{C{name}}. ''' raise _AttributeError(item=name, txt=_doesn_t_exist_)
'''Default C{repr(self)}. ''' return self.toRepr()
'''Default C{str(self)}. '''
'''Add one or several new items or replace existing ones.
@kwarg attrs: One or more C{name=value} pairs. '''
'''Like C{repr(dict)} but with C{name} prefix and with C{floats} formatting by C{fstr}. '''
'''Like C{str(dict)} but with C{floats} formatting by C{fstr}. '''
'''(INTERNAL) Root class for named objects. '''
'''Default C{repr(self)}. '''
'''Default C{str(self)}. '''
'''Join attributes as I{name=value} strings, with C{float}s formatted by function L{fstr}.
@arg names: The attribute names (C{str}s). @kwarg pairs_kwds: Keyword argument for function L{pairs}, except C{B{Nones}=True} to in- or exclude missing or C{None}-valued attributes.
@return: All C{name=value} pairs, joined (C{str}).
@see: Functions L{pygeodesy.attrs}. '''
'''Get this object's C{[module.]class} name (C{str}), see property C{.classnaming} and function C{classnaming}. '''
'''Get the class naming (C{bool}), see function C{classnaming}. '''
'''Set the class naming for C{[module.].class} names.
@arg prefixed: Include the module name (C{bool}). '''
'''Create another instance of this very class.
@arg args: Optional, positional arguments. @kwarg kwds: Optional, keyword arguments.
@return: New instance (B{self.__class__}). '''
'''Make a shallow or deep copy of this instance.
@kwarg deep: If C{True} make a deep, otherwise a shallow copy (C{bool}). @kwarg name: Optional, non-empty name (C{str}).
@return: The copy (C{This class} or subclass thereof). ''' c._name = str(name) # c.rename(name) updates all
'''(INTERNAL) Period-join C{self.name} and C{names}. '''
'''Get the name (C{str}). '''
'''Set the name.
@arg name: New name (C{str}).
@raise NameError: Can't rename, use L{rename}. ''' elif n != m: n = repr(n) c = self.classname t = _DOT_(c, Fmt.PAREN(self.rename.__name__, n)) t = _COMMASPACE_(repr(m), _SPACE_(_use_, t)) n = _DOT_(c, _EQUALSPACED_(_name_, n)) raise _NameError(n, txt=t) # to set the name from a sub-class, use # self.name = name or # _Named.name.fset(self, name), but not # _Named(self).name = name
'''Get the name I{or} class name or C{""} (C{str}). '''
'''Get the C{class} name I{and/or} the name or C{""} (C{str}). '''
'''Get the I{prefixed} C{class} name I{and/or} the name or C{""} (C{str}). '''
'''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)
'''Change the name.
@arg name: The new name (C{str}).
@return: The old name (C{str}). '''
'''Default C{repr(self)}. ''' return repr(self)
'''Default C{str(self)}. ''' return str(self)
def toStr2(self, **kwds): # PYCHOK no cover '''DEPRECATED, used method C{toRepr}.''' return self.toRepr(**kwds)
'''(INTERNAL) Set the instance' C{.name = self.name}.
@arg inst: The instance (C{_Named}). @kwarg name: Optional name, overriding C{self.name} (C{str}). @kwarg force: Force name change (C{bool}).
@return: The B{C{inst}}, named if not named before. '''
'''(INTERNAL) Rename the instance' C{.name = self.name}.
@arg inst: The instance (C{_Named}).
@return: The B{C{inst}}, named if not named before. ''' if not isinstance(inst, _Named): raise _IsnotError(_valid_, inst=inst)
inst.rename(self.name) return inst
'''(INTERNAL) Base class with name. '''
'''Default C{repr(self)}. '''
'''Default C{str(self)}. '''
# def notImplemented(self, attr): # '''Raise error for a missing method, function or attribute. # # @arg attr: Attribute name (C{str}). # # @raise NotImplementedError: No such attribute. # ''' # c = self.__class__.__name__ # return NotImplementedError(_DOT_(c, attr))
'''Refined class comparison, invoked as C{.others(other=other)}, C{.others(name=other)} or C{.others(other, name='other')}.
@arg other: The other instance (any C{type}). @kwarg name_other_up: Overriding C{name=other} and C{up=1} keyword arguments.
@return: The B{C{other}} iff compatible with this instance's C{class} or C{type}.
@raise TypeError: Mismatch of the B{C{other}} and this instance's C{class} or C{type}. ''' isinstance(self, other0.__class__):
isinstance(other, self.__class__):
raise _xotherError(self, other, name=name, up=up + 1)
'''(INTERNAL) I{Could be overloaded}.
@kwarg kwds: Optional, keyword arguments.
@return: C{toStr}() with keyword arguments (as C{str}). '''
# def toRepr(self, **kwds) # if kwds: # s = NN.join(reprs((self,), **kwds)) # else: # super().__repr__ only for Python 3+ # s = super(self.__class__, self).__repr__() # return Fmt.PAREN(self.named, s) # clips(s)
def toStr(self, **kwds): # PYCHOK no cover '''(INTERNAL) I{Must be overloaded}, see function C{notOverloaded}. ''' notOverloaded(self, **kwds)
# def toStr(self, **kwds): # if kwds: # s = NN.join(strs((self,), **kwds)) # else: # super().__str__ only for Python 3+ # s = super(self.__class__, self).__str__() # return s
'''(INTERNAL) Overwrite L{Property_RO} values. ''' else: raise _AssertionError(n, v, txt=repr(self))
'''(INTERNAL) Zap cached instance attributes. '''
'''(INTERNAL) Named C{dict} with key I{and} attribute access to the items. '''
t = unstr(self.classname, *args, **kwds) # PYCHOK no cover raise _ValueError(args=len(args), txt=t)
'''Delete an attribute or item by B{C{name}}. ''' _Dict.pop(name) # _Dict.__setattr__(self, name, NN) else:
'''Get an attribute or item by B{C{name}}. ''' return _Named.name.fget(self) raise _AttributeError(item=self._DOT_(name), txt=_doesn_t_exist_)
'''Get the value of an item by B{C{key}}. ''' raise KeyError(Fmt.SQUARE(self.classname, key))
'''Default C{repr(self)}. '''
'''Set attribute or item B{C{name}} to B{C{value}}. ''' _Dict.__setitem__(self, name, value) # self[name] = value else:
'''Set item B{C{key}} to B{C{value}}. ''' raise KeyError(_EQUAL_(Fmt.SQUARE(self.classname, key), repr(value)))
'''Default C{str(self)}. '''
'''Like C{repr(dict)} but with C{name} prefix and with C{floats} formatting by C{fstr}. '''
'''Like C{str(dict)} but with C{floats} formatting by C{fstr}. '''
'''(INTERNAL) Enum-like C{_NamedDict} with attribute access restricted to valid keys. '''
'''New C{_NamedEnum}.
@arg Class: Initial class or type acceptable as items values (C{type}). @arg Classes: Additional, acceptable classes or C{type}s. '''
'''Get the value of an attribute or item by B{C{name}}. ''' return _NamedDict.name.fget(self) raise _AttributeError(item=self._DOT_(name), txt=_doesn_t_exist_)
'''Default C{repr(self)}. '''
'''Default C{str(self)}. '''
'''(INTERNAL) Check attribute name against given, registered name. ''' # assert not hasattr(self.__class__, n) elif isinstance(v, self._item_Classes): # PYCHOK no cover assert self[n] is v and getattr(self, n) \ and self.find(v) == n else: raise _TypeError(v, name=n)
'''Find a registered item.
@arg item: The item to look for (any C{type}). @kwarg dflt: Value to return if not found (any C{type}).
@return: The B{C{item}}'s name if found (C{str}), or C{{dflt}} if there is no such I{registered} B{C{item}}. '''
'''Get the value of a I{registered} item.
@arg name: The name of the item (C{str}). @kwarg dflt: Value to return (any C{type}).
@return: The item with B{C{name}} if found, or B{C{dflt}} if there is no item I{registered} with that B{C{name}}. ''' # getattr needed to instantiate L{_LazyNamedEnumItem}
'''Yield all or only the I{registered} items.
@kwarg all: Use C{True} to yield {all} items or C{False} for only the currently I{registered} ones. ''' # instantiate any remaining L{_LazyNamedEnumItem}s, # removing the L{_LazyNamedEnumItem} from the class if isinstance(p, _LazyNamedEnumItem)):
'''Yield the keys of all or only the I{registered} items.
@kwarg all: Use C{True} to yield {all} item keys or C{False} for only the currently I{registered} ones. ''' yield k
'''Remove I{an, any} curretly I{registed} item.
@return: The removed item. ''' return self._zapitem(*_Dict.pop(self))
'''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. ''' raise ValueError except (AttributeError, ValueError, TypeError) as x: # PYCHOK no cover raise _NameError(_DOT_(_item_, _name_), item, txt=str(x)) raise _NameError(self._DOT_(n), item, txt=_exists_) raise _TypesError(self._DOT_(n), item, *self._item_Classes)
'''Remove a I{registered} item.
@arg name_or_item: Name (C{str}) or the item (any C{type}).
@return: The unregistered item.
@raise NameError: No item with that B{C{name}}.
@raise ValueError: No such item. ''' else: except KeyError: # PYCHOK no cover raise _NameError(item=self._DOT_(name), txt=_doesn_t_exist_)
'''Like C{repr(dict)} but with C{name} and C{floats} formatting by C{fstr}. '''
'''Like C{str(dict)} but with C{floats} formatting by C{fstr}. '''
'''Yield the value of all or only the I{registered} items.
@kwarg all: Use C{True} to yield {all} item values or C{False} for only the currently registered ones. ''' for _, v in self.items(all=all): yield v
# remove _LazyNamedEnumItem property value if still present
'''(INTERNAL) Lazily instantiated L{_NamedEnumItem}. '''
'''(INTERNAL) L{_LazyNamedEnumItem} property-like factory.
@see: Luciano Ramalho, "Fluent Python", page 636, O'Reilly, 2016, "Coding a Property Factory", especially Example 19-24. ''' # assert isinstance(inst, _NamedEnum) # instantiate an _NamedEnumItem, it self-registers # assert inst[name] is item # MUST be registered # store the item in the instance' __dict__ # remove the property from the registry class, such that # (a) the property no longer overrides the instance' item # in inst.__dict__ and (b) _NamedEnum.items(all=True) only # sees un-instantiated ones to be instantiated # assert isinstance(item, _NamedEnumItem)
'''(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, used by C{Conic}, C{Ellipsoid}, C{Transform}. ''' prec=prec, ints=True)
'''Get the I{registered} name (C{str}). '''
'''Set the name, unless already registered.
@arg name: New name (C{str}). ''' raise _NameError(str(name), self, txt=_registered_) # XXX _TypeError
'''(INTERNAL) Add this item as B{C{enum.name}}.
@note: Don't register if name is empty or doesn't start with a letter. '''
'''Remove this instance from its C{_NamedEnum} registry.
@raise AssertionError: Mismatch of this and registered item.
@raise NameError: This item is unregistered. ''' t = _SPACE_(repr(item), _vs_, repr(self)) # PYCHOK no cover raise _AssertionError(t)
'''(INTERNAL) Base for named C{tuple}s with both index I{and} attribute name access to the items.
@note: This class is similar to Python's C{namedtuple}, but statically defined, lighter and limited. ''' '''Tuple specifying the C{name} of each C{Named-Tuple} item.
@note: Specify at least 2 item names. ''' '''Tuple defining the C{units} of the value of each C{Named-Tuple} item.
@note: The C{len(_Units_)} must match C{len(_Names_)}. '''
'''New L{_NamedTuple} initialized with B{C{positional}} arguments.
@arg args: Tuple items (C{any}), all positional arguments. @kwarg name_only: Only C{B{name}='name'} is used, all other keyword arguments are I{silently} ignored.
@raise LenError: Unequal number of positional arguments and number of item C{_Names_} or C{_Units_}.
@raise TypeError: The C{_Names_} or C{_Units_} attribute is not a C{tuple} of at least 2 items.
@raise ValueError: Item name is not a C{str} or valid C{identifier} or starts with C{underscore}. '''
raise LenError(self.__class__, args=len(args), _Names_=n)
'''Delete an attribute by B{C{name}}.
@note: Items can not be deleted. ''' raise _TypeError(_del_, _DOT_(self.classname, name), txt=_immutable_) else: tuple.__delattr__(self, name)
'''Get the value of an attribute or item by B{C{name}}. ''' raise _IndexError(_DOT_(self.classname, Fmt.ANGLE(_name_)), name)
'''Get the value of an item by B{C{name}}. '''
'''Default C{repr(self)}. '''
'''Set attribute or item B{C{name}} to B{C{value}}. ''' raise _TypeError(_DOT_(self.classname, name), value, txt=_immutable_) else:
'''Default C{repr(self)}. '''
'''Yield the items, each as a C{(name, value)} pair (C{2-tuple}).
@see: Method C{.units}. '''
'''Get the iteration number (C{int}) or C{None} if not available/applicable. '''
'''(INTERNAL) Extend this C{Named-Tuple} with C{items} to an other B{C{xTuple}}. ''' (len(self._Names_) + len(items)) == len(xTuple._Names_) and self._Names_ == xTuple._Names_[:len(self)]): c = NN(self.classname, repr(self._Names_)) # PYCHOK no cover x = NN(xTuple.__name__, repr(xTuple._Names_)) # PYCHOK no cover raise TypeError(_SPACE_(c, _vs_, x))
'''Return this C{Named-Tuple} items as C{name=value} string(s).
@kwarg prec: The C{float} precision, number of decimal digits (0..9). Trailing zero decimals are stripped for B{C{prec}} values of 1 and above, but kept for negative B{C{prec}} values. @kwarg sep: Optional separator to join (C{str}).
@return: Tuple items (C{str}). '''
'''Return this C{Named-Tuple} items as string(s).
@kwarg prec: The C{float} precision, number of decimal digits (0..9). Trailing zero decimals are stripped for B{C{prec}} values of 1 and above, but kept for negative B{C{prec}} values. @kwarg sep: Optional separator to join (C{str}).
@return: Tuple items (C{str}). '''
'''Return a copy of this C{Named-Tuple} with each item value wrapped as an instance of its L{units} class.
@kwarg Error: Error to raise for L{units} issues (C{UnitError}).
@return: A duplicate of this C{Named-Tuple} (C{C{Named-Tuple}}).
@raise Error: Invalid C{Named-Tuple} item or L{units} class. '''
'''Yield the items, each as a C{(name, value}) pair (C{2-tuple}) with the value wrapped as an instance of its L{units} class.
@kwarg Error: Error to raise for L{units} issues (C{UnitError}).
@raise Error: Invalid C{Named-Tuple} item or L{units} class.
@see: Method C{.items}. ''' or (isclass(U) and isinstance(v, U) and hasattr(v, _name_) and v.name == n)): # PYCHOK indent
'''(INTERNAL) One-time check of C{_Names_} and C{_Units_} for each C{_NamedUnit} I{sub-class separately}. ''' raise _TypeError(_DOT_(self.classname, _Names_), ns) t = Fmt.SQUARE(_Names_=i) # PYCHOK no cover raise _ValueError(_DOT_(self.classname, t), n)
raise _TypeError(_DOT_(self.classname, _Units_), us) raise LenError(self.__class__, _Units_=len(us), _Names_=len(ns)) t = Fmt.SQUARE(_Units_=i) # PYCHOK no cover raise _TypeError(_DOT_(self.classname, t), u)
'''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. ''' not n.startswith(_UNDER_)): n = NN(n, _AT_, f, _COLON_, str(s)) except (AttributeError, ValueError): # PYCHOK no cover pass return dflt
'''(INTERNAL) Assemble the name for an invokation. ''' n = _SPACE_(n, repr(self_name))
'''Return the instance' class name optionally prefixed with the module name.
@arg inst: The object (any C{type}). @kwarg prefixed: Include the module name (C{bool}), see function C{classnaming}.
@return: The B{C{inst}}'s C{[module.]class} name (C{str}). '''
'''Get/set the default class naming for C{[module.]class} names.
@kwarg prefixed: Include the module name (C{bool}).
@return: Previous class naming setting (C{bool}). '''
'''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}). ''' except AttributeError: # PYCHOK no cover n = '__name__' # _DUNDER_(NN, _name_, NN)
'''Get the name of an instance.
@arg inst: The object (any C{type}).
@return: The instance' name (C{str}) or C{""}. '''
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 notImplemented(inst, *args, **kwds): # PYCHOK no cover '''Raise a C{NotImplementedError} for a missing method or property.
@arg inst: Instance (C{any}). @arg args: Method or property positional arguments (any C{type}s). @arg kwds: Method or property keyword arguments (any C{type}s). ''' n = kwds.pop(callername.__name__, NN) or callername(up=2) t = _notError(inst, n, args, kwds) raise _NotImplementedError(t, txt=notImplemented.__name__.replace(_I_, ' i'))
def notOverloaded(inst, *args, **kwds): # PYCHOK no cover '''Raise an C{AssertionError} for a method or property not overloaded.
@arg inst: Instance (C{any}). @arg args: Method or property positional arguments (any C{type}s). @arg kwds: Method or property keyword arguments (any C{type}s). ''' n = kwds.pop(callername.__name__, NN) or callername(up=2) t = _notError(inst, n, args, kwds) raise _AssertionError(t, txt=notOverloaded.__name__.replace(_O_, ' o'))
def _Pass(arg, **unused): # PYCHOK no cover '''(INTERNAL) I{Pass-thru} class for C{_NamedTuple._Units_}. ''' return arg
_NamedBase, # _NamedDict, _NamedEnum, _NamedEnumItem, _NamedTuple)
# **) MIT License # # Copyright (C) 2016-2021 -- 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 |