[tor-commits] [ooni-probe/master] Move peculiar unused file to wtf directory.

art at torproject.org art at torproject.org
Wed Nov 7 20:37:43 UTC 2012


commit 2cf46cd3a267a6829ff8ad562be5a7ecc2dc89ca
Author: Arturo Filastò <arturo at filasto.net>
Date:   Wed Nov 7 20:10:46 2012 +0100

    Move peculiar unused file to wtf directory.
---
 ooni/utils/assertions.py |  180 ----------------------------------
 ooni/utils/meta.py       |  241 ----------------------------------------------
 ooni/utils/timer.py      |  107 --------------------
 wtf/assertions.py        |  180 ++++++++++++++++++++++++++++++++++
 wtf/meta.py              |  241 ++++++++++++++++++++++++++++++++++++++++++++++
 wtf/timer.py             |  107 ++++++++++++++++++++
 6 files changed, 528 insertions(+), 528 deletions(-)

diff --git a/ooni/utils/assertions.py b/ooni/utils/assertions.py
deleted file mode 100644
index 875dcf5..0000000
--- a/ooni/utils/assertions.py
+++ /dev/null
@@ -1,180 +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.
-#
-
-class ValueChecker(object):
-    """
-    A class for general purpose value checks on commandline parameters
-    passed to subclasses of :class:`twisted.python.usage.Options`.
-    """
-    default_doc = "fix me"
-
-    def __init__(self, coerce_doc=None):
-        if not coerce_doc:
-            self.coerce_doc = default_doc
-        else:
-            self.coerce_doc = coerce_doc
-
-    @classmethod
-    def port_check(cls, port,
-                   range_min=1024, range_max=65535,
-                   coerce_doc=None):
-        """
-        Check that given ports are in the allowed range for an unprivileged
-        user.
-
-        :param port:
-            The port to check.
-        :param range_min:
-            The minimum allowable port number.
-        :param range_max:
-            The minimum allowable port number.
-        :param coerce_doc:
-            The documentation string to show in the optParameters menu, see
-            :class:`twisted.python.usage.Options`.
-        """
-        if not coerce_doc:
-            coerceDoc = cls.default_doc
-
-        assert isinstance(port, int)
-        if port not in range(range_min, range_max):
-            raise ValueError("Port out of range")
-            log.err()
-
-    @staticmethod
-    def uid_check(error_message):
-        """
-        Check that we're not root. If we are, setuid(1000) to normal user if
-        we're running on a posix-based system, and if we're on Windows just
-        tell the user that we can't be run as root with the specified options
-        and then exit.
-
-        :param error_message:
-            The string to log as an error message when the uid check fails.
-        """
-        uid, gid = os.getuid(), os.getgid()
-        if uid == 0 and gid == 0:
-            log.msg(error_message)
-        if os.name == 'posix':
-            log.msg("Dropping privileges to normal user...")
-            os.setgid(1000)
-            os.setuid(1000)
-        else:
-            sys.exit(0)
-
-    @staticmethod
-    def dir_check(d):
-        """Check that the given directory exists."""
-        if not os.path.isdir(d):
-            raise ValueError("%s doesn't exist, or has wrong permissions" % d)
-
-    @staticmethod
-    def file_check(f):
-        """Check that the given file exists."""
-        if not os.path.isfile(f):
-            raise ValueError("%s does not exist, or has wrong permissions" % f)
-
-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/ooni/utils/meta.py b/ooni/utils/meta.py
deleted file mode 100644
index 0b810f7..0000000
--- a/ooni/utils/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/ooni/utils/timer.py b/ooni/utils/timer.py
deleted file mode 100644
index e03fd74..0000000
--- a/ooni/utils/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
-
diff --git a/wtf/assertions.py b/wtf/assertions.py
new file mode 100644
index 0000000..875dcf5
--- /dev/null
+++ b/wtf/assertions.py
@@ -0,0 +1,180 @@
+#-*- 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.
+#
+
+class ValueChecker(object):
+    """
+    A class for general purpose value checks on commandline parameters
+    passed to subclasses of :class:`twisted.python.usage.Options`.
+    """
+    default_doc = "fix me"
+
+    def __init__(self, coerce_doc=None):
+        if not coerce_doc:
+            self.coerce_doc = default_doc
+        else:
+            self.coerce_doc = coerce_doc
+
+    @classmethod
+    def port_check(cls, port,
+                   range_min=1024, range_max=65535,
+                   coerce_doc=None):
+        """
+        Check that given ports are in the allowed range for an unprivileged
+        user.
+
+        :param port:
+            The port to check.
+        :param range_min:
+            The minimum allowable port number.
+        :param range_max:
+            The minimum allowable port number.
+        :param coerce_doc:
+            The documentation string to show in the optParameters menu, see
+            :class:`twisted.python.usage.Options`.
+        """
+        if not coerce_doc:
+            coerceDoc = cls.default_doc
+
+        assert isinstance(port, int)
+        if port not in range(range_min, range_max):
+            raise ValueError("Port out of range")
+            log.err()
+
+    @staticmethod
+    def uid_check(error_message):
+        """
+        Check that we're not root. If we are, setuid(1000) to normal user if
+        we're running on a posix-based system, and if we're on Windows just
+        tell the user that we can't be run as root with the specified options
+        and then exit.
+
+        :param error_message:
+            The string to log as an error message when the uid check fails.
+        """
+        uid, gid = os.getuid(), os.getgid()
+        if uid == 0 and gid == 0:
+            log.msg(error_message)
+        if os.name == 'posix':
+            log.msg("Dropping privileges to normal user...")
+            os.setgid(1000)
+            os.setuid(1000)
+        else:
+            sys.exit(0)
+
+    @staticmethod
+    def dir_check(d):
+        """Check that the given directory exists."""
+        if not os.path.isdir(d):
+            raise ValueError("%s doesn't exist, or has wrong permissions" % d)
+
+    @staticmethod
+    def file_check(f):
+        """Check that the given file exists."""
+        if not os.path.isfile(f):
+            raise ValueError("%s does not exist, or has wrong permissions" % f)
+
+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
new file mode 100644
index 0000000..0b810f7
--- /dev/null
+++ b/wtf/meta.py
@@ -0,0 +1,241 @@
+#-*- 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
new file mode 100644
index 0000000..e03fd74
--- /dev/null
+++ b/wtf/timer.py
@@ -0,0 +1,107 @@
+#
+# 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