[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [ooni-probe/master] Move peculiar unused file to wtf directory.
commit 2cf46cd3a267a6829ff8ad562be5a7ecc2dc89ca
Author: Arturo Filastò <arturo@xxxxxxxxxxx>
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
+
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits