[tor-commits] [ooni-probe/master] * Moved metaclass code to separate branch 'meta'.

isis at torproject.org isis at torproject.org
Thu Nov 8 08:33:25 UTC 2012


commit 16d270968cd1d52a081b3c653312b1e4b029dd9f
Author: Isis Lovecruft <isis at torproject.org>
Date:   Thu Nov 8 08:32:43 2012 +0000

    * Moved metaclass code to separate branch 'meta'.
---
 wtf/README        |    9 --
 wtf/assertions.py |  108 ------------------------
 wtf/meta.py       |  241 -----------------------------------------------------
 wtf/timer.py      |  107 -----------------------
 4 files changed, 0 insertions(+), 465 deletions(-)

diff --git a/wtf/README b/wtf/README
deleted file mode 100644
index 7696130..0000000
--- a/wtf/README
+++ /dev/null
@@ -1,9 +0,0 @@
-I have moved here all the pieces of code that are either not being used
-anywhere or that should probably not be part of OONIProbe.
-
-They are very neat pieces of code, though I have not tester their
-functionality, since there are no examples of how they should be called or
-used in the repo.
-
-I believe they should go on a separate branch or on another repo called
-something like "python class kung foo".
diff --git a/wtf/assertions.py b/wtf/assertions.py
deleted file mode 100644
index 60d3c50..0000000
--- a/wtf/assertions.py
+++ /dev/null
@@ -1,108 +0,0 @@
-#-*- coding: utf-8 -*-
-#
-# assertions.py
-# -------------
-# Collection of utilies for checks and assertions.
-#
-# :authors: Isis Lovecruft
-# :version: 0.1.0-alpha
-# :license: see included LICENSE file
-# :copyright: 2012 Isis Lovecruft, The Tor Project Inc.
-#
-
-def isNewStyleClass(obj):
-    """
-    Check if :param:`obj` is a new-style class, which is any class
-    derived by either
-
-        NewStyleClass = type('NewStyleClass')
-    or
-        class NewStyleClass(object):
-            pass
-
-    whereas old-style classes are (only in Python 2.x) derived by:
-
-        class OldStyleClass:
-            pass
-
-    There are recently implemented classes in many Python libraries,
-    including a few in Twisted, which are derived from old-style classes.
-    Thus, calling super() or attempting to retrieve the MRO of any
-    subclass of old-style classes can cause issues such as:
-
-      o Calling Subclass.mro() goes through the class hierarchy until it
-        reaches OldStyleClass, which has no mro(), and raises an
-        AttributeError.
-
-      o Calling super(Subclass, subcls) produces an ambiguous, rather than
-        algorithmic, class hierarchy, which (especially in Twisted's case)
-        breaks multiple inheritance.
-
-      o Expected Subclass instance attributes, in particular __bases__ and
-        __class__, can be missing, which in turn leads to problems with
-        a whole bunch of builtin methods and modules.
-
-    For more information, see:
-    http://www.python.org/download/releases/2.3/mro/
-    http://www.cafepy.com/article/python_attributes_and_methods/
-
-    :return:
-        True if :param:`obj` is a new-style class derived from object;
-        False if :param:`obj` is an old-style class (or derived from
-        one).
-    """
-    from types import ClassType
-    return not isinstance(type(object), ClassType)
-
-def isOldStyleClass(obj):
-    """
-    Check if :param:`obj` is an old-style class, which is any class
-    derived in Python 2.x with:
-
-        class OldStyleClass:
-            pass
-
-    There are recently implemented classes in many Python libraries,
-    including a few in Twisted, which are derived from old-style classes,
-    and thus their types, bases, and attributes are generally just messed
-    up.
-
-    :return:
-        True if :param:`obj` is a new-style class derived from object;
-        False if :param:`obj` is an old-style class (or derived from
-        one).
-    """
-    from types import ClassType
-    return not isinstance(type(object), ClassType)
-
-def isClass(obj):
-    """
-    Check if an object is *a* class (not a specific class), without trying
-    to call the obj.__class__ attribute, as that is not available in some
-    cases. This function will return True for both old- and new-style
-    classes, however, it will return False for class instances of either
-    style. An alternate way to do this (although it presumes that
-    :param:`obj` is a class instance) would be:
-
-       from types import TypeType
-       return isinstance(object.__class__, TypeType)
-
-    It turns out that objects with <type 'type'>, i.e. classes, don't
-    actually have the __class__ attribute...go figure. Instead, class
-    objects are only required to have the __doc__ and __module__
-    attributes.
-
-    :param obj:
-        Any object.
-    :return:
-        True if :param:`obj` is a class, False if otherwise (even if
-        :param:`obj` is an instance of a class).
-    """
-    from types import ClassType
-    return isinstance(object, (type, ClassType))
-
-def isNotClass(object):
-    """
-    See :func:`isClass`.
-    """
-    return True if not isClass(object) else False
diff --git a/wtf/meta.py b/wtf/meta.py
deleted file mode 100644
index 0b810f7..0000000
--- a/wtf/meta.py
+++ /dev/null
@@ -1,241 +0,0 @@
-#-*- coding: utf-8 -*-
-#
-# meta.py
-# -------
-# Meta classes for coercing subclasses which don't exist yet.
-#
-# :authors: Isis Lovecruft
-# :version: 0.1.0-alpha
-# :copyright: 2012 Isis Lovecruft
-# :license: see attached LICENSE file
-#
-
-class MetaDescriptor(type):
-    """
-    bug: "Attribute error: class <> has no attribute __bases__"
-
-    There are only objects. However, there *are* two kinds of objects:
-    type-objects and non-type-objects.
-
-    There are only two objects which do not have an attribute named
-    "__bases__":
-
-        1) Instances of the builtin object ``object`` itself (i.e. the
-           superclass of any top-level class in python), whose __class__ is
-           itself, and whose type is ``type(type)``:
-
-           >>> o = object()
-           >>> type(o)
-              <type 'type'>
-           >>> o.__class__
-              <type 'object'>
-
-           The o.__class__ part seems to imply that the __bases__ of
-           ``object`` should be itself.
-
-        2) Old Style Classes. Which are despicable demons, deserving to be
-           sent straight back to hell. No offense to the good Satanas. The
-           only thing these have by default is __doc__ and __module__. Also,
-           and this is importants too: Old Style Classes do not have an
-           attribute named __class__, because they do not derive from
-           anything.
-
-    Incidentally, the type of ``type(type)`` is itself, and the "__bases__" of
-    ``type(type)`` is...
-
-    >>> t = type(type)
-    >>> t.__name__
-    'type'
-    >>> type(t)
-       <type 'type'>
-    >>> t.__class__
-       <type 'type'>
-    >>> t.__bases__
-       (<type 'object'>,)
-
-    ``type(object)``. WTF. This is to say that the "__bases__" of ``object``
-    is the ``type`` of itself. This strange loop is where all black magic
-    enters into Python.
-
-    If we do "class Metaclass(type): pass", we can then call
-    ``super(Metaclass, mcls)``, and the resulting ``super`` object is actually
-    just ``type``:
-
-        o Its type is ``type(type)``.
-        o Its __bases__ ``type(object)``.
-
-    For example, ``super(Metaclass, mcls).__new__(mcls, *a, *kw)`` is the same
-    as saying ``type(mcls, "Metaclass", (type, ), {} )``, except that super
-    does some namespace munging with calling "self.__super" on its own type,
-    which is probably equivalent to the strange loops with type(type) and
-    type(object), but my brain is already flipping out (and I keep a string
-    cosmology textbook on my nightstand!).
-
-    However, we should not ever be able to call
-
-    >>> super(type, type(mcls)).__new__(type(mcls), 'type', (type(type),) {} )
-    TypeError: object.__new__(type) is not safe, use type.__new__()
-
-    Q: Why all this fuss?
-
-    A: We need to force future class-level attributes of subclasses of
-       NetTestCase to be accessible (also at the class-level, without
-       instatiations) by NetTestCase. I.e.:
-           1) class SubNetTestCase has class attribute optParameters, but no
-              class for doing anything with them, and they shouldn't have to.
-              They should just be able to define the options.
-           2) Therefore, NetTestCase needs to have data descriptors, which get
-              inherited.
-           3) We need to be able to do this without dangerous namespace
-              munging, because we cannot control the namespace of future
-              tests. Therefore, we cannot use hacks like "self.__super".
-
-       We need a Metaclass, which creates a Metafactory for classes which are
-       dynamic test descriptors. If this is confusing, leave it alone, there's
-       witches is these woods.
-
-    http://stackoverflow.com/a/10707719
-    http://docs.python.org/2/howto/descriptor.html
-    http://www.no-ack.org/2011/03/strange-behavior-with-properties-on.html
-    http://www.cafepy.com/article/python_types_and_objects/
-    http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python
-
-    """
-    ## DO NOT GIVE A METACLASS ATTRIBUTES HERE.
-    #descriptors = { }
-
-    from byteplay  import Code, opmap
-    from functools import partial
-
-    def __new__(im_so_meta_even_this_acronym, name, base, dict):
-
-        def hofstaeder_decorator(meta_decorator):
-            def meta_decorator_factory(*args, **kwargs):
-                def meta_decorator_wrapper(func):
-                    return meta_decorator(func, *args, **kwargs)
-                return meta_decorator_wrapper
-            return meta_decorator_factory
-
-        def _transmute(opcode, arg):
-            if ((opcode == opmap['LOAD_GLOBAL']) and
-                (arg == 'self')):
-                return opmap['LOAD_FAST'], arg
-            return opcode, arg
-
-        def selfless(child):
-            code = Code.from_code(child.func_code)
-            code.args = tuple(['self'] + list(code.args))
-            code.code = [_transmute(op, arg) for op, arg in code.code]
-            function.func_code = code.to_code()
-            return function
-
-        acronym = ( ( k,v ) for k,v in dict.items( )
-                    if not k.startswith('__') )
-        metanym, polymorph = ( (k for ( k,v ) in acronym),
-                               (v for ( k,v ) in acronym) )
-        morphonemes = (("get%s"%n, "set%s"%n, "del%s"%n) for n in metanym )
-
-        oracles = []
-        for getter, setter, deleter in morphonemes:
-            childnym = getter[3:]
-
-            @hofstaeder_decorator
-            def meta_decorator(func, *args, **kwargs):
-                def decorator_wrapper(first, last):
-                    return func(first, last)
-                return decorator_wrapper
-
-            @meta_decorator(getter, setter, deleter)
-            def decorated_property(first, last):
-                childnym = getter[3:]
-                class DataDescriptor(object):
-                    @selfless
-                    def __init__(childnym=None, polymorph):
-                        setattr(self, childnym, polymorph)
-
-                    @property
-                    @selfless
-                    def getter():
-                        return self.childnym
-                return DataDescriptor(first, last)
-
-            oracles.append(decorated_property(childnym, polymorph))
-
-        return super(
-            MetaDescriptor, im_so_meta_even_this_acronym).__new__(
-            im_so_meta_even_this_acronym,
-            metanym,
-            polymorph,
-            dict(oracles) )
-'''
-    @property
-    def x(self):        ## or getx
-        return self._x
-    @x.setter
-    def x(self, value): ## or setx
-        self._x = value
-    @x.deleter
-    def x(self):        ## or delx
-        del self._x
-    ## or 'x = property(getx, setx, delx, "documentation")'
-    ##     ^               ^     ^     ^
-    ## just need @property's name, initial value can be None
-
-Metaclass
-   Creates Metaclasses for each data descriptor in each SubNetTestCase
-        so, per SubNetTestCase, we get (usually two) descriptors:
-        optParameters and input
-
-'''
-
-def applyClassAttribute(obj, cls, get='optParameters'):
-    """
-    I get attributes from an outside instances' dictionary and attempt to
-    apply them to a class. I require that the attributes I am trying to set be
-    data descriptors which is just Python name munging trick that is mild and
-    harmless enough to have it's own builtin decorator helper:
-
-        class Foo(object):
-            def __init__(self, *a, **kw):
-                if 'thing' in kw:
-                    self._thing = thing
-            @property
-            def thing(self):
-                return self._thing
-            @property.setter
-            def thing(self, value):
-                self._thing = value
-            @property.delter
-            def thing(self):
-                return del(self)
-    """
-    from ooni.utils.assertions import isClass, isNotClass
-
-    try:
-        assert isNotClass(obj), "must be an instance"
-        assert isClass(cls), "not a class"
-                                        ## obj is probably an instance
-        C = obj.__class__               ## of a subclass of nettest.NetTestCase
-
-        assert issubclass(C, cls), "not a subclass of %s" % cls
-        assert C.__dict__.__contains__('optParameters'), \
-            "%s in %s.__dict__ not found" % (get, C)
-    except AssertionError, ae:
-        log.debug(ae)
-    else:
-        attributes = classify_class_attrs(C)
-        ## uncomment this to have class attributes spewn everywhere:
-        #log.debug("Found class attributes:\n%s" % pprint(attributes))
-        for attr in attributes:
-            if attr.name == str(get):
-                setattr(obj, str(get), attr.object)
-        if not hasattr(obj, str(get)):
-            log.debug("Unable to find class attribute %s" % get)
-        else:
-            log.debug("Applying %s.%s = %s to descriptor..."
-                      % (C.name, attr.name, attr.object))
-        ## This was an unfinished attempt at fixing a class' __bases__, I do
-        ## not know if it was heading in the right direction. It can be
-        ## removed it is still crufting up the space. --isis
-        if '__bases__' or '_parents' in C.__dict__:
-            pass
diff --git a/wtf/timer.py b/wtf/timer.py
deleted file mode 100644
index e03fd74..0000000
--- a/wtf/timer.py
+++ /dev/null
@@ -1,107 +0,0 @@
-#
-# timer.py
-# ----------
-# OONI utilities for adding timeouts to functions and to Deferreds.
-#
-# :author: Isis Lovecruft
-# :version: 0.1.0-pre-alpha
-# :license: see include LICENSE file
-# :copyright: copyright (c) 2012, Isis Lovecruft, The Tor Project Inc.
-# 
-
-class TimeoutError(Exception):
-    """Raised when a timer runs out."""
-    pass
-
-def timeout(seconds, e=None):
-    """
-    A decorator for blocking methods to cause them to timeout. Can be used
-    like this: 
-
-        @timeout(30)
-        def foo(arg1, kwarg="baz"):
-            for x in xrange(1000000000):
-                print "%s %s" % (arg1, kwarg)
-                print x
-
-    or like this:
-
-        ridiculous = timeout(30)(foo("bar"))
-
-    :param seconds:
-        Number of seconds to wait before raising :class:`TimeoutError`.
-    :param e:
-        Error message to pass to :class:`TimeoutError`. Default None.
-    :return:
-        The result of the original function, or else an instance of 
-        :class:`TimeoutError`.
-    """
-    from signal    import alarm, signal, SIGALRM
-    from functools import wraps
-
-    def decorator(func):
-        def _timeout(signum, frame):
-            raise TimeoutError, e
-        def wrapper(*args, **kwargs):
-            signal(SIGALRM, _timeout)
-            alarm(seconds)
-            try:
-                res = func(*args, **kwargs)
-            finally:
-                alarm(0)
-            return res
-        return wraps(func)(wrapper)
-    return decorator
-
-def deferred_timeout(seconds, e=None):
-    """
-    Decorator for adding a timeout to an instance of a
-    :class:`twisted.internet.defer.Deferred`. Can be used like this:
-
-        @deferred_timeout(30)
-        def foo(arg1, kwarg="baz"):
-            for x in xrange(1000000000):
-                print "%s %s" % (arg1, kwarg)
-                print x
-
-    or like this:
-
-        ridiculous = deferred_timeout(30)(foo("bar"))
-
-    :param seconds:
-        Number of seconds to wait before raising :class:`TimeoutError`.
-    :param e:
-        Error message to pass to :class:`TimeoutError`. Default None.
-    :return:
-        The result of the orginal :class:`twisted.internet.defer.Deferred`
-        or else a :class:`TimeoutError`.
-    """
-    from twisted.internet import defer, reactor
-
-    def wrapper(func):
-        @defer.inlineCallbacks
-        def _timeout(*args, **kwargs):
-            d_original = func(*args, **kwargs)
-            if not isinstance(d_original, defer.Deferred):
-                defer.returnValue(d_original) ## fail gracefully
-            d_timeout = defer.Deferred()
-            timeup = reactor.callLater(seconds, d_timeout.callback, None)
-            try:
-                original_result, timeout_result = \
-                    yield defer.DeferredList([d_original, d_timeout],
-                                             fireOnOneCallback=True,
-                                             fireOnOneErrback=True,
-                                             consumeErrors=True)
-            except defer.FirstError, dfe:
-                assert dfe.index == 0         ## error in original
-                timeup.cancel()
-                dfe.subFailure.raiseException()
-            else:
-                if d_timeout.called:          ## timeout
-                    d_original.cancel()
-                    raise TimeoutError, e
-            timeup.cancel()                   ## no timeout
-            defer.returnValue(d_original)
-        return _timeout
-    return wrapper
-



More information about the tor-commits mailing list