aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/zope.interface/py2/zope/interface/advice.py
diff options
context:
space:
mode:
authorshmel1k <shmel1k@ydb.tech>2023-11-26 18:16:14 +0300
committershmel1k <shmel1k@ydb.tech>2023-11-26 18:43:30 +0300
commitb8cf9e88f4c5c64d9406af533d8948deb050d695 (patch)
tree218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/zope.interface/py2/zope/interface/advice.py
parent523f645a83a0ec97a0332dbc3863bb354c92a328 (diff)
downloadydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz
add kikimr_configure
Diffstat (limited to 'contrib/python/zope.interface/py2/zope/interface/advice.py')
-rw-r--r--contrib/python/zope.interface/py2/zope/interface/advice.py213
1 files changed, 213 insertions, 0 deletions
diff --git a/contrib/python/zope.interface/py2/zope/interface/advice.py b/contrib/python/zope.interface/py2/zope/interface/advice.py
new file mode 100644
index 0000000000..86d0f11aa4
--- /dev/null
+++ b/contrib/python/zope.interface/py2/zope/interface/advice.py
@@ -0,0 +1,213 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Class advice.
+
+This module was adapted from 'protocols.advice', part of the Python
+Enterprise Application Kit (PEAK). Please notify the PEAK authors
+(pje@telecommunity.com and tsarna@sarna.org) if bugs are found or
+Zope-specific changes are required, so that the PEAK version of this module
+can be kept in sync.
+
+PEAK is a Python application framework that interoperates with (but does
+not require) Zope 3 and Twisted. It provides tools for manipulating UML
+models, object-relational persistence, aspect-oriented programming, and more.
+Visit the PEAK home page at http://peak.telecommunity.com for more information.
+"""
+
+from types import FunctionType
+try:
+ from types import ClassType
+except ImportError:
+ __python3 = True
+else:
+ __python3 = False
+
+__all__ = [
+ 'addClassAdvisor',
+ 'determineMetaclass',
+ 'getFrameInfo',
+ 'isClassAdvisor',
+ 'minimalBases',
+]
+
+import sys
+
+def getFrameInfo(frame):
+ """Return (kind,module,locals,globals) for a frame
+
+ 'kind' is one of "exec", "module", "class", "function call", or "unknown".
+ """
+
+ f_locals = frame.f_locals
+ f_globals = frame.f_globals
+
+ sameNamespace = f_locals is f_globals
+ hasModule = '__module__' in f_locals
+ hasName = '__name__' in f_globals
+
+ sameName = hasModule and hasName
+ sameName = sameName and f_globals['__name__']==f_locals['__module__']
+
+ module = hasName and sys.modules.get(f_globals['__name__']) or None
+
+ namespaceIsModule = module and module.__dict__ is f_globals
+
+ if not namespaceIsModule:
+ # some kind of funky exec
+ kind = "exec"
+ elif sameNamespace and not hasModule:
+ kind = "module"
+ elif sameName and not sameNamespace:
+ kind = "class"
+ elif not sameNamespace:
+ kind = "function call"
+ else: # pragma: no cover
+ # How can you have f_locals is f_globals, and have '__module__' set?
+ # This is probably module-level code, but with a '__module__' variable.
+ kind = "unknown"
+ return kind, module, f_locals, f_globals
+
+
+def addClassAdvisor(callback, depth=2):
+ """Set up 'callback' to be passed the containing class upon creation
+
+ This function is designed to be called by an "advising" function executed
+ in a class suite. The "advising" function supplies a callback that it
+ wishes to have executed when the containing class is created. The
+ callback will be given one argument: the newly created containing class.
+ The return value of the callback will be used in place of the class, so
+ the callback should return the input if it does not wish to replace the
+ class.
+
+ The optional 'depth' argument to this function determines the number of
+ frames between this function and the targeted class suite. 'depth'
+ defaults to 2, since this skips this function's frame and one calling
+ function frame. If you use this function from a function called directly
+ in the class suite, the default will be correct, otherwise you will need
+ to determine the correct depth yourself.
+
+ This function works by installing a special class factory function in
+ place of the '__metaclass__' of the containing class. Therefore, only
+ callbacks *after* the last '__metaclass__' assignment in the containing
+ class will be executed. Be sure that classes using "advising" functions
+ declare any '__metaclass__' *first*, to ensure all callbacks are run."""
+ # This entire approach is invalid under Py3K. Don't even try to fix
+ # the coverage for this block there. :(
+ if __python3: # pragma: no cover
+ raise TypeError('Class advice impossible in Python3')
+
+ frame = sys._getframe(depth)
+ kind, module, caller_locals, caller_globals = getFrameInfo(frame)
+
+ # This causes a problem when zope interfaces are used from doctest.
+ # In these cases, kind == "exec".
+ #
+ #if kind != "class":
+ # raise SyntaxError(
+ # "Advice must be in the body of a class statement"
+ # )
+
+ previousMetaclass = caller_locals.get('__metaclass__')
+ if __python3: # pragma: no cover
+ defaultMetaclass = caller_globals.get('__metaclass__', type)
+ else:
+ defaultMetaclass = caller_globals.get('__metaclass__', ClassType)
+
+
+ def advise(name, bases, cdict):
+
+ if '__metaclass__' in cdict:
+ del cdict['__metaclass__']
+
+ if previousMetaclass is None:
+ if bases:
+ # find best metaclass or use global __metaclass__ if no bases
+ meta = determineMetaclass(bases)
+ else:
+ meta = defaultMetaclass
+
+ elif isClassAdvisor(previousMetaclass):
+ # special case: we can't compute the "true" metaclass here,
+ # so we need to invoke the previous metaclass and let it
+ # figure it out for us (and apply its own advice in the process)
+ meta = previousMetaclass
+
+ else:
+ meta = determineMetaclass(bases, previousMetaclass)
+
+ newClass = meta(name,bases,cdict)
+
+ # this lets the callback replace the class completely, if it wants to
+ return callback(newClass)
+
+ # introspection data only, not used by inner function
+ advise.previousMetaclass = previousMetaclass
+ advise.callback = callback
+
+ # install the advisor
+ caller_locals['__metaclass__'] = advise
+
+
+def isClassAdvisor(ob):
+ """True if 'ob' is a class advisor function"""
+ return isinstance(ob,FunctionType) and hasattr(ob,'previousMetaclass')
+
+
+def determineMetaclass(bases, explicit_mc=None):
+ """Determine metaclass from 1+ bases and optional explicit __metaclass__"""
+
+ meta = [getattr(b,'__class__',type(b)) for b in bases]
+
+ if explicit_mc is not None:
+ # The explicit metaclass needs to be verified for compatibility
+ # as well, and allowed to resolve the incompatible bases, if any
+ meta.append(explicit_mc)
+
+ if len(meta)==1:
+ # easy case
+ return meta[0]
+
+ candidates = minimalBases(meta) # minimal set of metaclasses
+
+ if not candidates: # pragma: no cover
+ # they're all "classic" classes
+ assert(not __python3) # This should not happen under Python 3
+ return ClassType
+
+ elif len(candidates)>1:
+ # We could auto-combine, but for now we won't...
+ raise TypeError("Incompatible metatypes",bases)
+
+ # Just one, return it
+ return candidates[0]
+
+
+def minimalBases(classes):
+ """Reduce a list of base classes to its ordered minimum equivalent"""
+
+ if not __python3: # pragma: no cover
+ classes = [c for c in classes if c is not ClassType]
+ candidates = []
+
+ for m in classes:
+ for n in classes:
+ if issubclass(n,m) and m is not n:
+ break
+ else:
+ # m has no subclasses in 'classes'
+ if m in candidates:
+ candidates.remove(m) # ensure that we're later in the list
+ candidates.append(m)
+
+ return candidates