[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [ooni-probe/master] * Moved metaclass code to separate branch 'meta'.
commit 16d270968cd1d52a081b3c653312b1e4b029dd9f
Author: Isis Lovecruft <isis@xxxxxxxxxxxxxx>
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
-
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits