comparison tincan.py @ 19:5d9a1b82251a draft before-template-changes

Return the "deepest" subclass; this allows subclassing tincan.Page and making a standard base page class for a webapp.
author David Barts <n5jrn@me.com>
date Mon, 20 May 2019 17:42:18 -0700
parents e88ab99914cf
children ca2029ce95c7
comparison
equal deleted inserted replaced
18:e88ab99914cf 19:5d9a1b82251a
487 spec = importlib.util.spec_from_file_location(_mangle(self._name), pycpath) 487 spec = importlib.util.spec_from_file_location(_mangle(self._name), pycpath)
488 mod = importlib.util.module_from_spec(spec) 488 mod = importlib.util.module_from_spec(spec)
489 spec.loader.exec_module(mod) 489 spec.loader.exec_module(mod)
490 except Exception as e: 490 except Exception as e:
491 raise TinCanError("{0}: error importing: {1!s}".format(pycpath, e)) from e 491 raise TinCanError("{0}: error importing: {1!s}".format(pycpath, e)) from e
492 # Locate a suitable class 492 # Locate a suitable class. We look for the "deepest" class object
493 # we can find in the inheritance tree.
493 self._class = None 494 self._class = None
495 score = -1
496 ambig = False
494 for i in dir(mod): 497 for i in dir(mod):
495 v = getattr(mod, i) 498 v = getattr(mod, i)
496 if isclass(v) and issubclass(v, klass) and v is not klass: 499 if not isclass(v):
497 if self._class is not None: 500 continue
498 raise TinCanError("{0}: contains multiple {1} classes".format(pypath, klass.__name__)) 501 d = self._cldepth(klass, v)
502 if d > score:
499 self._class = v 503 self._class = v
504 score = d
505 ambig = False
506 elif d == score:
507 ambig = True
500 if self._class is None: 508 if self._class is None:
501 raise TinCanError("{0}: contains no {1} classes".format(pypath, klass.__name__)) 509 raise TinCanError("{0}: contains no {1} classes".format(pypath, klass.__name__))
510 if ambig:
511 raise TinCanError("{0}: contains ambiguous {1} classes".format(pypath, klass.__name__))
512
513 # This might fail for complex inheritance schemes from the classes of
514 # interest (so don't use them!).
515 def _cldepth(self, base, klass, count=0):
516 if klass is object:
517 # not found
518 return -1
519 elif klass is base:
520 # just found
521 return count
522 else:
523 # must recurse
524 for c in klass.__bases__:
525 result = self._cldepth(base, c, count=count+1)
526 if result > 0:
527 return result
528 return -1
502 529
503 def _redirect(self): 530 def _redirect(self):
504 try: 531 try:
505 rlist = self._splitpath(self._header.forward) 532 rlist = self._splitpath(self._header.forward)
506 forw = '/' + '/'.join(rlist) 533 forw = '/' + '/'.join(rlist)