Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

advice.py 3.8KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. ##############################################################################
  2. #
  3. # Copyright (c) 2003 Zope Foundation and Contributors.
  4. # All Rights Reserved.
  5. #
  6. # This software is subject to the provisions of the Zope Public License,
  7. # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
  8. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  9. # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  10. # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  11. # FOR A PARTICULAR PURPOSE.
  12. #
  13. ##############################################################################
  14. """Class advice.
  15. This module was adapted from 'protocols.advice', part of the Python
  16. Enterprise Application Kit (PEAK). Please notify the PEAK authors
  17. (pje@telecommunity.com and tsarna@sarna.org) if bugs are found or
  18. Zope-specific changes are required, so that the PEAK version of this module
  19. can be kept in sync.
  20. PEAK is a Python application framework that interoperates with (but does
  21. not require) Zope 3 and Twisted. It provides tools for manipulating UML
  22. models, object-relational persistence, aspect-oriented programming, and more.
  23. Visit the PEAK home page at http://peak.telecommunity.com for more information.
  24. """
  25. from types import FunctionType
  26. __all__ = [
  27. 'determineMetaclass',
  28. 'getFrameInfo',
  29. 'isClassAdvisor',
  30. 'minimalBases',
  31. ]
  32. import sys
  33. def getFrameInfo(frame):
  34. """Return (kind,module,locals,globals) for a frame
  35. 'kind' is one of "exec", "module", "class", "function call", or "unknown".
  36. """
  37. f_locals = frame.f_locals
  38. f_globals = frame.f_globals
  39. sameNamespace = f_locals is f_globals
  40. hasModule = '__module__' in f_locals
  41. hasName = '__name__' in f_globals
  42. sameName = hasModule and hasName
  43. sameName = sameName and f_globals['__name__']==f_locals['__module__']
  44. module = hasName and sys.modules.get(f_globals['__name__']) or None
  45. namespaceIsModule = module and module.__dict__ is f_globals
  46. if not namespaceIsModule:
  47. # some kind of funky exec
  48. kind = "exec"
  49. elif sameNamespace and not hasModule:
  50. kind = "module"
  51. elif sameName and not sameNamespace:
  52. kind = "class"
  53. elif not sameNamespace:
  54. kind = "function call"
  55. else: # pragma: no cover
  56. # How can you have f_locals is f_globals, and have '__module__' set?
  57. # This is probably module-level code, but with a '__module__' variable.
  58. kind = "unknown"
  59. return kind, module, f_locals, f_globals
  60. def isClassAdvisor(ob):
  61. """True if 'ob' is a class advisor function"""
  62. return isinstance(ob,FunctionType) and hasattr(ob,'previousMetaclass')
  63. def determineMetaclass(bases, explicit_mc=None):
  64. """Determine metaclass from 1+ bases and optional explicit __metaclass__"""
  65. meta = [getattr(b,'__class__',type(b)) for b in bases]
  66. if explicit_mc is not None:
  67. # The explicit metaclass needs to be verified for compatibility
  68. # as well, and allowed to resolve the incompatible bases, if any
  69. meta.append(explicit_mc)
  70. if len(meta)==1:
  71. # easy case
  72. return meta[0]
  73. candidates = minimalBases(meta) # minimal set of metaclasses
  74. if len(candidates)>1:
  75. # We could auto-combine, but for now we won't...
  76. raise TypeError("Incompatible metatypes", bases)
  77. # Just one, return it
  78. return candidates[0]
  79. def minimalBases(classes):
  80. """Reduce a list of base classes to its ordered minimum equivalent"""
  81. candidates = []
  82. for m in classes:
  83. for n in classes:
  84. if issubclass(n,m) and m is not n:
  85. break
  86. else:
  87. # m has no subclasses in 'classes'
  88. if m in candidates:
  89. candidates.remove(m) # ensure that we're later in the list
  90. candidates.append(m)
  91. return candidates