[Checkins] SVN: martian/branches/jw-philipp-using-ndir-directives/src/martian/ Replace the directive module with the new-style directive implementations.

Jan-Wijbrand Kolman janwijbrand at gmail.com
Sat May 3 08:17:23 EDT 2008


Log message for revision 86198:
  Replace the directive module with the new-style directive implementations.

Changed:
  U   martian/branches/jw-philipp-using-ndir-directives/src/martian/__init__.py
  D   martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.py
  A   martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.py
  D   martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.txt
  A   martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.txt
  D   martian/branches/jw-philipp-using-ndir-directives/src/martian/ndir.py
  D   martian/branches/jw-philipp-using-ndir-directives/src/martian/ndir.txt
  U   martian/branches/jw-philipp-using-ndir-directives/src/martian/tests/test_all.py

-=-
Modified: martian/branches/jw-philipp-using-ndir-directives/src/martian/__init__.py
===================================================================
--- martian/branches/jw-philipp-using-ndir-directives/src/martian/__init__.py	2008-05-03 12:04:39 UTC (rev 86197)
+++ martian/branches/jw-philipp-using-ndir-directives/src/martian/__init__.py	2008-05-03 12:17:23 UTC (rev 86198)
@@ -3,4 +3,8 @@
     grok_package, grok_module)
 from martian.components import GlobalGrokker, ClassGrokker, InstanceGrokker
 from martian.util import scan_for_classes
-from martian.ndir import baseclass
+from martian.directive import Directive, MarkerDirective, baseclass
+from martian.directive import ONCE, MULTIPLE, DICT
+from martian.directive import CLASS, CLASS_OR_MODULE, MODULE
+from martian.directive import (
+    validateText, validateInterface, validateInterfaceOrClass)

Deleted: martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.py
===================================================================
--- martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.py	2008-05-03 12:04:39 UTC (rev 86197)
+++ martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.py	2008-05-03 12:17:23 UTC (rev 86198)
@@ -1,202 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006-2007 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Grok directives.
-"""
-
-import sys
-import inspect
-
-from zope import interface
-from zope.interface.interfaces import IInterface
-
-from martian import util
-from martian.error import GrokImportError
-
-class IDirectiveContext(interface.Interface):
-    description = interface.Attribute("The correct place in which the "
-                                      "directive can be used.")
-
-    def matches(frame):
-        """returns whether the given frame is the correct place in
-        which the directive can be used.
-        """
-
-class ClassDirectiveContext(object):
-    interface.implements(IDirectiveContext)
-    
-    description = "class"
-
-    def matches(self, frame):
-        return util.frame_is_class(frame)
-
-    
-class ModuleDirectiveContext(object):
-    interface.implements(IDirectiveContext)
-    
-    description = "module"
-
-    def matches(self, frame):
-        return util.frame_is_module(frame)
-    
-
-class ClassOrModuleDirectiveContext(object):
-    interface.implements(IDirectiveContext)
-    
-    description = "class or module"
-
-    def matches(self, frame):
-        return util.frame_is_module(frame) or util.frame_is_class(frame)
-
-
-class Directive(object):
-    """
-    Directive sets a value into the context's locals as __<name>__
-    ('.' in the name are replaced with '_').
-    """
-
-    def __init__(self, name, directive_context):
-        self.name = name
-        self.local_name = '__%s__' % name.replace('.', '_')
-        self.directive_context = directive_context
-
-    def __call__(self, *args, **kw):
-        self.check_argument_signature(*args, **kw)
-        self.check_arguments(*args, **kw)
-
-        frame = sys._getframe(1)
-        self.check_directive_context(frame)
-
-        value = self.value_factory(*args, **kw)
-        return self.store(frame, value)
-
-    def check_arguments(self, *args, **kw):
-        raise NotImplementedError
-
-    # to get a correct error message, we construct a function that has
-    # the same signature as check_arguments(), but without "self".
-    def check_argument_signature(self, *arguments, **kw):
-        args, varargs, varkw, defaults = inspect.getargspec(
-            self.check_arguments)
-        argspec = inspect.formatargspec(args[1:], varargs, varkw, defaults)
-        exec("def signature_checker" + argspec + ": pass")
-        try:
-            signature_checker(*arguments, **kw)
-        except TypeError, e:
-            message = e.args[0]
-            message = message.replace("signature_checker()", self.name)
-            raise TypeError(message)
-
-    def check_directive_context(self, frame):
-        if not self.directive_context.matches(frame):
-            raise GrokImportError("%s can only be used on %s level."
-                                  % (self.name,
-                                     self.directive_context.description))
-
-    def value_factory(self, *args, **kw):
-        raise NotImplementedError
-
-    def store(self, frame, value):
-        raise NotImplementedError
-
-
-class OnceDirective(Directive):
-    def store(self, frame, value):
-        if self.local_name in frame.f_locals:
-            raise GrokImportError("%s can only be called once per %s."
-                                  % (self.name,
-                                     self.directive_context.description))
-        frame.f_locals[self.local_name] = value
-
-
-class MarkerDirective(OnceDirective):
-    """A directive without argument that places a marker.
-    """
-    def value_factory(self):
-        return True
-
-    def check_arguments(self):
-        pass
-
-class MultipleTimesDirective(Directive):
-    def store(self, frame, value):
-        values = frame.f_locals.get(self.local_name, [])
-        values.append(value)
-        frame.f_locals[self.local_name] = values
-
-
-class SingleValue(object):
-
-    # Even though the value_factory is called with (*args, **kw),
-    # we're safe since check_arguments would have bailed out with a
-    # TypeError if the number arguments we were called with was not
-    # what we expect here.
-    def value_factory(self, value):
-        return value
-
-class OptionalValueDirective(object):
-    def check_arguments(self, value=None):
-        pass
-
-    def value_factory(self, value=None):
-        if value is None:
-            return self.default_value()
-        return value
-
-    def default_value(self):
-        raise NotImplementedError
-
-class BaseTextDirective(object):
-    """
-    Base directive that only accepts unicode/ASCII values.
-    """
-
-    def check_arguments(self, value):
-        if util.not_unicode_or_ascii(value):
-            raise GrokImportError("You can only pass unicode or ASCII to "
-                                  "%s." % self.name)
-
-
-class SingleTextDirective(BaseTextDirective, SingleValue, OnceDirective):
-    """
-    Directive that accepts a single unicode/ASCII value, only once.
-    """
-
-
-class MultipleTextDirective(BaseTextDirective, SingleValue,
-                            MultipleTimesDirective):
-    """
-    Directive that accepts a single unicode/ASCII value, multiple times.
-    """
-
-
-class InterfaceOrClassDirective(SingleValue, OnceDirective):
-    """
-    Directive that only accepts classes or interface values.
-    """
-
-    def check_arguments(self, value):
-        if not (IInterface.providedBy(value) or util.isclass(value)):
-            raise GrokImportError("You can only pass classes or interfaces to "
-                                  "%s." % self.name)
-
-
-class InterfaceDirective(SingleValue, OnceDirective):
-    """
-    Directive that only accepts interface values.
-    """
-
-    def check_arguments(self, value):
-        if not (IInterface.providedBy(value)):
-            raise GrokImportError("You can only pass interfaces to "
-                                  "%s." % self.name)

Copied: martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.py (from rev 86197, martian/branches/jw-philipp-using-ndir-directives/src/martian/ndir.py)
===================================================================
--- martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.py	                        (rev 0)
+++ martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.py	2008-05-03 12:17:23 UTC (rev 86198)
@@ -0,0 +1,189 @@
+import sys
+import inspect
+
+from zope.interface.interfaces import IInterface
+
+from martian import util
+from martian.error import GrokImportError
+
+class StoreOnce(object):
+
+    def set(self, locals_, directive, value):
+        if directive.dotted_name() in locals_:
+            raise GrokImportError(
+                "The '%s' directive can only be called once per %s." %
+                (directive.name, directive.scope.description))
+        locals_[directive.dotted_name()] = value
+
+    def get(self, directive, component, default):
+        return getattr(component, directive.dotted_name(), default)
+
+    def setattr(self, context, directive, value):
+        setattr(context, directive.dotted_name(), value)
+
+ONCE = StoreOnce()
+
+class StoreOnceGetFromThisClassOnly(StoreOnce):
+
+    def get(self, directive, component, default):
+        return component.__dict__.get(directive.dotted_name(), default)
+
+class StoreMultipleTimes(StoreOnce):
+
+    def set(self, locals_, directive, value):
+        values = locals_.setdefault(directive.dotted_name(), [])
+        values.append(value)
+
+MULTIPLE = StoreMultipleTimes()
+
+class StoreDict(StoreOnce):
+
+    def set(self, locals_, directive, value):
+        values_dict = locals_.setdefault(directive.dotted_name(), {})
+        try:
+            key, value = value
+        except (TypeError, ValueError):
+            raise GrokImportError(
+                "The factory method for the '%s' directive should return a "
+                "key-value pair." % directive.name)
+        values_dict[key] = value
+
+DICT = StoreDict()
+
+_SENTINEL = object()
+_USE_DEFAULT = object()
+
+class ClassScope(object):
+    description = 'class'
+
+    def check(self, frame):
+        return (util.frame_is_class(frame) and
+                not is_fake_module(frame))
+
+CLASS = ClassScope()
+
+class ClassOrModuleScope(object):
+    description = 'class or module'
+
+    def check(self, frame):
+        return (util.frame_is_class(frame) or
+                util.frame_is_module(frame))
+
+CLASS_OR_MODULE = ClassOrModuleScope()
+
+class ModuleScope(object):
+    description = 'module'
+
+    def check(self, frame):
+        return util.frame_is_module(frame)
+
+MODULE = ModuleScope()
+
+class Directive(object):
+
+    default = None
+
+    def __init__(self, *args, **kw):
+        self.name = self.__class__.__name__
+
+        frame = sys._getframe(1)
+        if not self.scope.check(frame):
+            raise GrokImportError("The '%s' directive can only be used on "
+                                  "%s level." %
+                                  (self.name, self.scope.description))
+
+        self.check_factory_signature(*args, **kw)
+
+        validate = getattr(self, 'validate', None)
+        if validate is not None:
+            validate(*args, **kw)
+
+        value = self.factory(*args, **kw)
+
+        self.store.set(frame.f_locals, self, value)
+
+    # To get a correct error message, we construct a function that has
+    # the same signature as check_arguments(), but without "self".
+    def check_factory_signature(self, *arguments, **kw):
+        args, varargs, varkw, defaults = inspect.getargspec(
+            self.factory)
+        argspec = inspect.formatargspec(args[1:], varargs, varkw, defaults)
+        exec("def signature_checker" + argspec + ": pass")
+        try:
+            signature_checker(*arguments, **kw)
+        except TypeError, e:
+            message = e.args[0]
+            message = message.replace("signature_checker()", self.name)
+            raise TypeError(message)
+
+    def factory(self, value):
+        return value
+
+    def get_default(self, component):
+        return self.default
+
+    @classmethod
+    def dotted_name(cls):
+        return cls.__module__ + '.' + cls.__name__
+
+    @classmethod
+    def get(cls, component, module=None):
+        # Create an instance of the directive without calling __init__
+        self = cls.__new__(cls)
+
+        value = self.store.get(self, component, _USE_DEFAULT)
+        if value is _USE_DEFAULT and module is not None:
+            value = self.store.get(self, module, _USE_DEFAULT)
+        if value is _USE_DEFAULT:
+            value = self.get_default(component)
+
+        return value
+
+    @classmethod
+    def set(cls, component, value):
+        # Create an instance of the directive without calling __init__
+        self = cls.__new__(cls)
+        cls.store.setattr(component, self, value)
+
+class MultipleTimesDirective(Directive):
+    store = MULTIPLE
+    default = []
+
+
+class MarkerDirective(Directive):
+    store = ONCE
+    default = False
+
+    def factory(self):
+        return True
+
+
+class baseclass(MarkerDirective):
+    scope = CLASS
+    store = StoreOnceGetFromThisClassOnly()
+
+
+def validateText(directive, value):
+    if util.not_unicode_or_ascii(value):
+        raise GrokImportError("The '%s' directive can only be called with "
+                              "unicode or ASCII." % directive.name)
+
+def validateInterfaceOrClass(directive, value):
+    if not (IInterface.providedBy(value) or util.isclass(value)):
+        raise GrokImportError("The '%s' directive can only be called with "
+                              "a class or an interface." % directive.name)
+
+
+def validateInterface(directive, value):
+    if not (IInterface.providedBy(value)):
+        raise GrokImportError("The '%s' directive can only be called with "
+                              "an interface." % directive.name)
+
+
+# this here only for testing purposes, which is a bit unfortunate
+# but makes the tests a lot clearer for module-level directives
+# also unfortunate that fake_module needs to be defined directly
+# in the fake module being tested and not in the FakeModule base class;
+# the system cannot find it on the frame if it is in the base class.
+def is_fake_module(frame):
+    return frame.f_locals.has_key('fake_module')

Deleted: martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.txt
===================================================================
--- martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.txt	2008-05-03 12:04:39 UTC (rev 86197)
+++ martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.txt	2008-05-03 12:17:23 UTC (rev 86198)
@@ -1,226 +0,0 @@
-Directives
-==========
-
-A martian directive is a special function call that causes information
-to be set on module or class level. This information is set as a
-Python module is imported, so should do the minimum amount of work (as
-import side-effects are bad). The idea is that this information can
-then be picked up by a martian-based framework during grok time.
-
-Martian has an infrastructure to make it easy to define new
-directives.
-
-Directive contexts
-------------------
-
-If a directive is given ``ModuleDirectiveContext`` it can only work in
-real modules::
-
-  >>> from martian.directive import SingleTextDirective, ModuleDirectiveContext
-  >>> foo = SingleTextDirective('grok.foo', ModuleDirectiveContext())
-
-We cannot show a working example of the ``foo`` directive in this
-doctest as it is not a real module. It would look like this::
-  
-   foo('hello world')
-
-We have placed this code in a real module and will import it::
-
-  >>> from martian.tests.directive import modulecontext
-
-We expect modulecontext to contain a special attribute ``__grok_foo__``
-with the string ``'hello world'``::
-
-  >>> modulecontext.__grok_foo__
-  'hello world'
-
-This directive cannot be used in a class as it's not allowed by its context::
- 
-  >>> class Test(object):
-  ...   foo('hello world')
-  Traceback (most recent call last):
-   ...
-  GrokImportError: grok.foo can only be used on module level.
-
-Now let's define a directive that can only work in classes::
-
-  >>> from martian.directive import ClassDirectiveContext
-  >>> bar = SingleTextDirective('grok.bar', ClassDirectiveContext())
-
-It won't work in a module::
-
-  >>> from martian.tests.directive import classcontextbroken
-  Traceback (most recent call last):
-    ...
-  GrokImportError: grok.bar can only be used on class level.
-
-It will work in a class context::
-
-  >>> class Test(object):
-  ...   bar('hello world')
-  >>> Test.__grok_bar__
-  'hello world'
-
-Now let's define a directive that can be used both on module-level as
-well as on class-level::
-
-  >>> from martian.directive import ClassOrModuleDirectiveContext
-  >>> qux = SingleTextDirective('grok.qux', ClassOrModuleDirectiveContext())
-
-It can be used in a class::
-
-  >>> class Test(object):
-  ...   qux('hello world')
-  >>> Test.__grok_qux__
-  'hello world'
-
-It can also be used in a module::
-
-  >>> from martian.tests.directive import classormodulecontext
-  >>> classormodulecontext.__grok_qux__
-  'hello world'
-
-Calling a directive once or multiple times
-------------------------------------------
-
-Directives can either be called once in a particular context, or
-multiple times. Let's define a type of directive that can only be
-called once::
-  
-  >>> from martian.directive import OnceDirective, SingleValue, BaseTextDirective
-  >>> class MyDirective(BaseTextDirective, SingleValue, OnceDirective):
-  ...   pass
-  >>> hoi = MyDirective('hoi', ClassDirectiveContext())
-
-When we try to use it twice, we get an error::
-
-  >>> class Test(object):
-  ...   hoi('once')
-  ...   hoi('twice')
-  Traceback (most recent call last):
-    ...
-  GrokImportError: hoi can only be called once per class.
-
-This also works for module-level directives::
-
-  >>> from martian.tests.directive import onlyoncemodulecontext
-  Traceback (most recent call last):
-    ...
-  GrokImportError: hoi can only be called once per module.
-
-Now let's define a directive that can be called multiple times::
-
-  >>> from martian.directive import MultipleTimesDirective
-  >>> class MyDirective(BaseTextDirective, SingleValue, MultipleTimesDirective):
-  ...   pass
-  >>> dag = MyDirective('dag', ClassDirectiveContext())
-
-It will allow you to use it multiple times::
- 
-  >>> class Test(object):
-  ...   dag('once')
-  ...   dag('twice')
-
-The underlying annotation will have stored the multiple values::
-
-  >>> Test.__dag__
-  ['once', 'twice']
-
-Directive values
-----------------
-
-A ``BaseTextDirective`` directive accepts unicode or plain ascii values::
-
- >>> class Test(object):
- ...   hoi('hello')
- >>> class Test(object):
- ...   hoi(u'è')
-
-It won't accept values in another encoding::
-
- >>> class Test(object):
- ...   hoi(u'è'.encode('latin-1'))
- Traceback (most recent call last):
-   ...
- GrokImportError: You can only pass unicode or ASCII to hoi.
- >>> class Test(object):
- ...   hoi(u'è'.encode('UTF-8'))
- Traceback (most recent call last):
-   ...
- GrokImportError: You can only pass unicode or ASCII to hoi.
-
-A ``InterfaceOrClassDirective`` only accepts class or interface objects::
-
-  >>> from martian.directive import InterfaceOrClassDirective
-  >>> class MyDirective(InterfaceOrClassDirective, SingleValue, OnceDirective):
-  ...   pass
-  >>> hello = MyDirective('hello', ClassDirectiveContext())
-  >>> class SomeClass(object):
-  ...    pass
-  >>> class Test(object):
-  ...   hello(SomeClass)
-  >>> class SomeOldStyleClass:
-  ...   pass
-  >>> class Test(object):
-  ...   hello(SomeOldStyleClass)
-  >>> from zope.interface import Interface
-  >>> class ISomeInterface(Interface):
-  ...   pass
-  >>> class Test(object):
-  ...   hello(ISomeInterface)
-
-But not anything else::
-  
-  >>> class Test(object):
-  ...   hello(None)
-  Traceback (most recent call last):
-   ...
-  GrokImportError: You can only pass classes or interfaces to hello.
-  >>> class Test(object):
-  ...   hello('foo')
-  Traceback (most recent call last):
-   ...
-  GrokImportError: You can only pass classes or interfaces to hello.
-
-An ``InterfaceDirective`` accepts only interfaces::
-
-  >>> from martian.directive import InterfaceDirective
-  >>> class MyDirective(InterfaceDirective, SingleValue, OnceDirective):
-  ...   pass
-  >>> hello2 = MyDirective('hello2', ClassDirectiveContext())
-  >>> class Test(object):
-  ...   hello2(ISomeInterface)
-
-But not classes::
-
-  >>> class Test(object):
-  ...   hello2(SomeClass)
-  Traceback (most recent call last):
-    ...
-  GrokImportError: You can only pass interfaces to hello2.
-
-An ``OptionalValueDirective`` accepts a single value, but the value
-can be left out. If so, the value will be calculated by a function we
-pass it::
-
-  >>> from martian.directive import OptionalValueDirective
-  >>> class MyDirective(OptionalValueDirective, OnceDirective):
-  ...    def default_value(self):
-  ...       return 4 # the default if no value is given 
-  >>> hello3 = MyDirective('hello3', ClassDirectiveContext())
-
-Let's try the directive with a single value::
-
-  >>> class Test(object):
-  ...   hello3(1)
-  >>> Test.__hello3__
-  1
-
-We can also try the directive without a value::
-
-  >>> class Test(object):
-  ...   hello3()
-  >>> Test.__hello3__
-  4
-
-

Copied: martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.txt (from rev 86197, martian/branches/jw-philipp-using-ndir-directives/src/martian/ndir.txt)
===================================================================
--- martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.txt	                        (rev 0)
+++ martian/branches/jw-philipp-using-ndir-directives/src/martian/directive.txt	2008-05-03 12:17:23 UTC (rev 86198)
@@ -0,0 +1,486 @@
+Directives New Style
+====================
+
+When grokking a class, the grokking procedure can be informed by
+directives, on a class, or a module. If a directive is absent, the
+system falls back to a default. Here we introduce a general way to
+define these directives, and how to use them to retrieve information
+for a class for use during the grokking procedure.
+
+A simple directive
+------------------
+
+We define a simple directive that sets a description::
+
+  >>> from martian import Directive, CLASS, ONCE
+  >>> class description(Directive):
+  ...     scope = CLASS
+  ...     store = ONCE
+  ...     default = u''
+
+The name of the directive is ``description``. We specify that the
+directive can only be used in the scope of a class. We also specify it
+can only be used a single time. Finally we define the default in case
+the directive is absent (the empty string).
+
+Now we look at the directive in action::
+
+  >>> class Foo(object):
+  ...    description(u"This is a description")
+
+After setting it, we can use the ``get`` method on the directive to
+retrieve it from the class again::
+
+  >>> description.get(Foo)
+  u'This is a description'
+
+Directives in different namespaces get stored differently. We'll
+define a similar directive in another namespace::
+
+  >>> class description2(description):
+  ...     pass
+
+  >>> class Foo(object):
+  ...     description(u"Description1")
+  ...     description2(u"Description2")
+  >>> description.get(Foo)
+  u'Description1'
+  >>> description2.get(Foo)
+  u'Description2'
+
+If we check the value of a class without the directive, we see the
+default value for that directive, this case the empty unicode string::
+
+  >>> class Foo(object):
+  ...     pass
+  >>> description.get(Foo)
+  u''
+
+In certain cases we need to set a value on a component as if the directive was
+actually used::
+
+  >>> description.set(Foo, u'value as set')
+  >>> description.get(Foo)
+  u'value as set'
+
+Subclasses of the original class will inherit the properties set by the
+directive:
+
+  >>> class Foo(object):
+  ...     description('This is a foo.')
+  ...
+  >>> class Bar(Foo):
+  ...     pass
+  ...
+  >>> description.get(Bar)
+  'This is a foo.'
+
+When we use the directive outside of class scope, we get an error
+message::
+
+  >>> description('Description')
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'description' directive can only be used on class level.
+
+In particular, we cannot use it in a module::
+
+  >>> class testmodule(FakeModule):
+  ...   fake_module = True
+  ...   description("Description")
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'description' directive can only be used on class level.
+
+We cannot use the directive twice in the class scope. If we do so, we
+get an error message as well::
+
+  >>> class Foo(object):
+  ...   description(u"Description1")
+  ...   description(u"Description2")
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'description' directive can only be called once per class.
+
+We cannot call the directive with no argument either::
+
+  >>> class Foo(object):
+  ...   description()
+  Traceback (most recent call last):
+    ...
+  TypeError: description takes exactly 1 argument (0 given)
+
+Class and module scope
+----------------------
+
+We define a ``layer`` directive that can be used in class and module
+scope both::
+
+  >>> from martian import CLASS_OR_MODULE
+  >>> class layer(Directive):
+  ...     scope = CLASS_OR_MODULE
+  ...     store = ONCE
+
+By default, the ``default`` property is None which is why we can omit
+specifying it here.
+
+We can use this directive now on a class::
+
+  >>> class Foo(object):
+  ...   layer('Test')
+  >>> layer.get(Foo)
+  'Test'
+
+The defaulting to ``None`` works::
+
+  >>> class Foo(object):
+  ...   pass
+  >>> layer.get(Foo) is None
+  True
+
+We can also use it in a module::
+
+  >>> class testmodule(FakeModule):
+  ...    layer('Test2')
+  ...    class Foo(object):
+  ...       pass
+  >>> test_module = fake_import(testmodule)
+
+When we now try to access ``layer`` on ``Foo``, we find the
+module-level default which we just set. We pass the module as the
+second argument to the ``get`` method to have it fall back on this::
+
+  >>> layer.get(testmodule.Foo, testmodule)
+  'Test2'
+
+Let's look at a module where the directive is not used::
+
+  >>> class testmodule(FakeModule):
+  ...   class Foo(object):
+  ...      pass
+  >>> testmodule = fake_import(testmodule)
+
+In this case, the value cannot be found so the system falls back on
+the default, ``None``::
+
+  >>> layer.get(testmodule.Foo, testmodule) is None
+  True
+
+Using a directive multiple times
+--------------------------------
+
+A directive can be configured to allow it to be called multiple times
+in the same scope::
+
+  >>> from martian import MULTIPLE
+  >>> class multi(Directive):
+  ...     scope = CLASS
+  ...     store = MULTIPLE
+
+We can now use the directive multiple times without any errors::
+
+  >>> class Foo(object):
+  ...   multi(u"Once")
+  ...   multi(u"Twice")
+
+We can now retrieve the value and we'll get a list::
+
+  >>> multi.get(Foo)
+  [u'Once', u'Twice']
+
+Using a directive multiple times, as a dictionary
+-------------------------------------------------
+
+A directive can be configured to allow it to be called multiple times in the
+same scope. In this case the factory method should be overridden to return a
+key-value pair::
+
+  >>> from martian import DICT
+  >>> class multi(Directive):
+  ...     scope = CLASS
+  ...     store = DICT
+  ...     def factory(self, value):
+  ...         return value.lower(), value
+
+We can now use the directive multiple times without any errors::
+
+  >>> class Bar(object):
+  ...   multi(u"Once")
+  ...   multi(u"Twice")
+
+We can now retrieve the value and we'll get a to the items::
+
+  >>> d = multi.get(Bar)
+  >>> print sorted(d.items())
+  [(u'once', u'Once'), (u'twice', u'Twice')]
+
+When the factory method does not return a key-value pair, an error is raised::
+
+  >>> class wrongmulti(Directive):
+  ...     scope = CLASS
+  ...     store = DICT
+  ...     def factory(self, value):
+  ...         return None
+
+  >>> class Baz(object):
+  ...   wrongmulti(u"Once")
+  Traceback (most recent call last):
+  ...
+  GrokImportError: The factory method for the 'wrongmulti' directive should
+  return a key-value pair.
+
+  >>> class wrongmulti2(Directive):
+  ...     scope = CLASS
+  ...     store = DICT
+  ...     def factory(self, value):
+  ...         return value, value, value
+
+  >>> class Baz(object):
+  ...   wrongmulti2(u"Once")
+  Traceback (most recent call last):
+  ...
+  GrokImportError: The factory method for the 'wrongmulti2' directive should
+  return a key-value pair.
+
+Calculated defaults
+-------------------
+
+Often instead of just supplying the system with a default, we want to
+calculate the default in some way. We define the ``name`` directive,
+which if not present, will calculate its value from the name of class,
+lower-cased. Instead of passing a default value, we pass a function as the
+default argument::
+
+  >>> class name(Directive):
+  ...     scope = CLASS
+  ...     store = ONCE
+  ...     def get_default(self, component):
+  ...         return component.__name__.lower()
+
+  >>> class Foo(object):
+  ...   name('bar')
+  >>> name.get(Foo)
+  'bar'
+
+  >>> class Foo(object):
+  ...   pass
+  >>> name.get(Foo)
+  'foo'
+
+A marker directive
+------------------
+
+Another type of directive is a marker directive. This directive takes
+no arguments at all, but when used it marks the context::
+
+  >>> from martian import MarkerDirective
+  >>> class mark(MarkerDirective):
+  ...     scope = CLASS
+
+  >>> class Foo(object):
+  ...     mark()
+
+Class ``Foo`` is now marked::
+
+  >>> mark.get(Foo)
+  True
+
+When we have a class that isn't marked, we get the default value, ``False``::
+
+  >>> class Bar(object):
+  ...    pass
+  >>> mark.get(Bar)
+  False
+
+If we pass in an argument, we get an error::
+
+  >>> class Bar(object):
+  ...   mark("An argument")
+  Traceback (most recent call last):
+    ...
+  TypeError: mark takes no arguments (1 given)
+
+
+Validation
+----------
+
+A directive can be supplied with a validation method. The validation method
+checks whether the value passed in is allowed. It should raise
+``GrokImportError`` if the value cannot be validated, together with a
+description of why not.
+
+First we define our own validation function. A validation function
+takes two arguments:
+
+* the name of the directive we're validating for
+
+* the value we need to validate
+
+The name can be used to format the exception properly.
+
+We'll define a validation method that only expects integer numbers::
+
+  >>> from martian.error import GrokImportError
+  >>> class number(Directive):
+  ...     scope = CLASS
+  ...     store = ONCE
+  ...     def validate(self, value):
+  ...         if type(value) is not int:
+  ...             raise GrokImportError("The '%s' directive can only be called with an integer." %
+  ...                                   self.name)
+
+  >>> class Foo(object):
+  ...    number(3)
+
+  >>> class Foo(object):
+  ...    number("This shouldn't work")
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'number' directive can only be called with an integer.
+
+Some built-in validation functions
+----------------------------------
+
+Let's look at some built-in validation functions.
+
+The ``validateText`` function determines whether a string
+is unicode or plain ascii::
+
+  >>> from martian import validateText
+  >>> class title(Directive):
+  ...     scope = CLASS
+  ...     store = ONCE
+  ...     default = u''
+  ...     validate = validateText
+
+When we pass ascii text into the directive, there is no error::
+
+  >>> class Foo(object):
+  ...    title('Some ascii text')
+
+We can also pass in a unicode string without error::
+
+  >>> class Foo(object):
+  ...    title(u'Some unicode text')
+
+Let's now try it with something that's not text at all, such as a number.
+This fails::
+
+  >>> class Foo(object):
+  ...    title(123)
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'title' directive can only be called with unicode or ASCII.
+
+It's not allowed to call the direct with a non-ascii encoded string::
+
+  >>> class Foo(object):
+  ...   title(u'è'.encode('latin-1'))
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'title' directive can only be called with unicode or ASCII.
+
+ >>> class Foo(object):
+ ...   title(u'è'.encode('UTF-8'))
+ Traceback (most recent call last):
+   ...
+ GrokImportError: The 'title' directive can only be called with unicode or ASCII.
+
+The ``validateInterfaceOrClass`` function only accepts class or
+interface objects::
+
+  >>> from martian import validateInterfaceOrClass
+  >>> class klass(Directive):
+  ...     scope = CLASS
+  ...     store = ONCE
+  ...     validate = validateInterfaceOrClass
+
+It works with interfaces and classes::
+
+  >>> class Bar(object):
+  ...    pass
+  >>> class Foo(object):
+  ...    klass(Bar)
+
+  >>> from zope.interface import Interface
+  >>> class IBar(Interface):
+  ...    pass
+  >>> class Foo(object):
+  ...    klass(IBar)
+
+It won't work with other things::
+
+  >>> class Foo(object):
+  ...   klass(Bar())
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'klass' directive can only be called with a class or an interface.
+
+  >>> class Foo(object):
+  ...   klass(1)
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'klass' directive can only be called with a class or an interface.
+
+The ``validateInterface`` validator only accepts an interface::
+
+  >>> from martian import validateInterface
+  >>> class iface(Directive):
+  ...     scope = CLASS
+  ...     store = ONCE
+  ...     validate = validateInterface
+
+Let's try it::
+
+  >>> class Foo(object):
+  ...    iface(IBar)
+
+It won't work with classes or other things::
+
+  >>> class Foo(object):
+  ...   iface(Bar)
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'iface' directive can only be called with an interface.
+
+  >>> class Foo(object):
+  ...   iface(1)
+  Traceback (most recent call last):
+    ...
+  GrokImportError: The 'iface' directive can only be called with an interface.
+
+Declaring base classes
+----------------------
+
+There's a special directive called 'baseclass' which lets you declare that a
+certain class is the base class for a series of other components.  This
+property should not be inherited by those components.  Consider the following
+base class:
+
+  >>> from martian import baseclass
+  >>> class MyBase(object):
+  ...     baseclass()
+
+As you would expect, the directive will correctly identify this class as a
+baseclass:
+
+  >>> baseclass.get(MyBase)
+  True
+
+But, if we create a subclass of this base class, the subclass won't inherit
+that property, unlike with a regular directive:
+
+  >>> class SubClass(MyBase):
+  ...     pass
+  ...
+  >>> baseclass.get(SubClass)
+  False
+
+Naturally, the directive will also report a false answer if the class doesn't
+inherit from a base class at all and hasn't been marked with the directive:
+
+  >>> class NoBase(object):
+  ...     pass
+  ...
+  >>> baseclass.get(NoBase)
+  False

Deleted: martian/branches/jw-philipp-using-ndir-directives/src/martian/ndir.py
===================================================================
--- martian/branches/jw-philipp-using-ndir-directives/src/martian/ndir.py	2008-05-03 12:04:39 UTC (rev 86197)
+++ martian/branches/jw-philipp-using-ndir-directives/src/martian/ndir.py	2008-05-03 12:17:23 UTC (rev 86198)
@@ -1,189 +0,0 @@
-import sys
-import inspect
-
-from zope.interface.interfaces import IInterface
-
-from martian import util
-from martian.error import GrokImportError
-
-class StoreOnce(object):
-
-    def set(self, locals_, directive, value):
-        if directive.dotted_name() in locals_:
-            raise GrokImportError(
-                "The '%s' directive can only be called once per %s." %
-                (directive.name, directive.scope.description))
-        locals_[directive.dotted_name()] = value
-
-    def get(self, directive, component, default):
-        return getattr(component, directive.dotted_name(), default)
-
-    def setattr(self, context, directive, value):
-        setattr(context, directive.dotted_name(), value)
-
-ONCE = StoreOnce()
-
-class StoreOnceGetFromThisClassOnly(StoreOnce):
-
-    def get(self, directive, component, default):
-        return component.__dict__.get(directive.dotted_name(), default)
-
-class StoreMultipleTimes(StoreOnce):
-
-    def set(self, locals_, directive, value):
-        values = locals_.setdefault(directive.dotted_name(), [])
-        values.append(value)
-
-MULTIPLE = StoreMultipleTimes()
-
-class StoreDict(StoreOnce):
-
-    def set(self, locals_, directive, value):
-        values_dict = locals_.setdefault(directive.dotted_name(), {})
-        try:
-            key, value = value
-        except (TypeError, ValueError):
-            raise GrokImportError(
-                "The factory method for the '%s' directive should return a "
-                "key-value pair." % directive.name)
-        values_dict[key] = value
-
-DICT = StoreDict()
-
-_SENTINEL = object()
-_USE_DEFAULT = object()
-
-class ClassScope(object):
-    description = 'class'
-
-    def check(self, frame):
-        return (util.frame_is_class(frame) and
-                not is_fake_module(frame))
-
-CLASS = ClassScope()
-
-class ClassOrModuleScope(object):
-    description = 'class or module'
-
-    def check(self, frame):
-        return (util.frame_is_class(frame) or
-                util.frame_is_module(frame))
-
-CLASS_OR_MODULE = ClassOrModuleScope()
-
-class ModuleScope(object):
-    description = 'module'
-
-    def check(self, frame):
-        return util.frame_is_module(frame)
-
-MODULE = ModuleScope()
-
-class Directive(object):
-
-    default = None
-
-    def __init__(self, *args, **kw):
-        self.name = self.__class__.__name__
-
-        frame = sys._getframe(1)
-        if not self.scope.check(frame):
-            raise GrokImportError("The '%s' directive can only be used on "
-                                  "%s level." %
-                                  (self.name, self.scope.description))
-
-        self.check_factory_signature(*args, **kw)
-
-        validate = getattr(self, 'validate', None)
-        if validate is not None:
-            validate(*args, **kw)
-
-        value = self.factory(*args, **kw)
-
-        self.store.set(frame.f_locals, self, value)
-
-    # To get a correct error message, we construct a function that has
-    # the same signature as check_arguments(), but without "self".
-    def check_factory_signature(self, *arguments, **kw):
-        args, varargs, varkw, defaults = inspect.getargspec(
-            self.factory)
-        argspec = inspect.formatargspec(args[1:], varargs, varkw, defaults)
-        exec("def signature_checker" + argspec + ": pass")
-        try:
-            signature_checker(*arguments, **kw)
-        except TypeError, e:
-            message = e.args[0]
-            message = message.replace("signature_checker()", self.name)
-            raise TypeError(message)
-
-    def factory(self, value):
-        return value
-
-    def get_default(self, component):
-        return self.default
-
-    @classmethod
-    def dotted_name(cls):
-        return cls.__module__ + '.' + cls.__name__
-
-    @classmethod
-    def get(cls, component, module=None):
-        # Create an instance of the directive without calling __init__
-        self = cls.__new__(cls)
-
-        value = self.store.get(self, component, _USE_DEFAULT)
-        if value is _USE_DEFAULT and module is not None:
-            value = self.store.get(self, module, _USE_DEFAULT)
-        if value is _USE_DEFAULT:
-            value = self.get_default(component)
-
-        return value
-
-    @classmethod
-    def set(cls, component, value):
-        # Create an instance of the directive without calling __init__
-        self = cls.__new__(cls)
-        cls.store.setattr(component, self, value)
-
-class MultipleTimesDirective(Directive):
-    store = MULTIPLE
-    default = []
-
-
-class MarkerDirective(Directive):
-    store = ONCE
-    default = False
-
-    def factory(self):
-        return True
-
-
-class baseclass(MarkerDirective):
-    scope = CLASS
-    store = StoreOnceGetFromThisClassOnly()
-
-
-def validateText(directive, value):
-    if util.not_unicode_or_ascii(value):
-        raise GrokImportError("The '%s' directive can only be called with "
-                              "unicode or ASCII." % directive.name)
-
-def validateInterfaceOrClass(directive, value):
-    if not (IInterface.providedBy(value) or util.isclass(value)):
-        raise GrokImportError("The '%s' directive can only be called with "
-                              "a class or an interface." % directive.name)
-
-
-def validateInterface(directive, value):
-    if not (IInterface.providedBy(value)):
-        raise GrokImportError("The '%s' directive can only be called with "
-                              "an interface." % directive.name)
-
-
-# this here only for testing purposes, which is a bit unfortunate
-# but makes the tests a lot clearer for module-level directives
-# also unfortunate that fake_module needs to be defined directly
-# in the fake module being tested and not in the FakeModule base class;
-# the system cannot find it on the frame if it is in the base class.
-def is_fake_module(frame):
-    return frame.f_locals.has_key('fake_module')

Deleted: martian/branches/jw-philipp-using-ndir-directives/src/martian/ndir.txt
===================================================================
--- martian/branches/jw-philipp-using-ndir-directives/src/martian/ndir.txt	2008-05-03 12:04:39 UTC (rev 86197)
+++ martian/branches/jw-philipp-using-ndir-directives/src/martian/ndir.txt	2008-05-03 12:17:23 UTC (rev 86198)
@@ -1,486 +0,0 @@
-Directives New Style
-====================
-
-When grokking a class, the grokking procedure can be informed by
-directives, on a class, or a module. If a directive is absent, the
-system falls back to a default. Here we introduce a general way to
-define these directives, and how to use them to retrieve information
-for a class for use during the grokking procedure.
-
-A simple directive
-------------------
-
-We define a simple directive that sets a description::
-
-  >>> from martian.ndir import Directive, CLASS, ONCE
-  >>> class description(Directive):
-  ...     scope = CLASS
-  ...     store = ONCE
-  ...     default = u''
-
-The name of the directive is ``description``. We specify that the
-directive can only be used in the scope of a class. We also specify it
-can only be used a single time. Finally we define the default in case
-the directive is absent (the empty string).
-
-Now we look at the directive in action::
-
-  >>> class Foo(object):
-  ...    description(u"This is a description")
-
-After setting it, we can use the ``get`` method on the directive to
-retrieve it from the class again::
-
-  >>> description.get(Foo)
-  u'This is a description'
-
-Directives in different namespaces get stored differently. We'll
-define a similar directive in another namespace::
-
-  >>> class description2(description):
-  ...     pass
-
-  >>> class Foo(object):
-  ...     description(u"Description1")
-  ...     description2(u"Description2")
-  >>> description.get(Foo)
-  u'Description1'
-  >>> description2.get(Foo)
-  u'Description2'
-
-If we check the value of a class without the directive, we see the
-default value for that directive, this case the empty unicode string::
-
-  >>> class Foo(object):
-  ...     pass
-  >>> description.get(Foo)
-  u''
-
-In certain cases we need to set a value on a component as if the directive was
-actually used::
-
-  >>> description.set(Foo, u'value as set')
-  >>> description.get(Foo)
-  u'value as set'
-
-Subclasses of the original class will inherit the properties set by the
-directive:
-
-  >>> class Foo(object):
-  ...     description('This is a foo.')
-  ...
-  >>> class Bar(Foo):
-  ...     pass
-  ...
-  >>> description.get(Bar)
-  'This is a foo.'
-
-When we use the directive outside of class scope, we get an error
-message::
-
-  >>> description('Description')
-  Traceback (most recent call last):
-    ...
-  GrokImportError: The 'description' directive can only be used on class level.
-
-In particular, we cannot use it in a module::
-
-  >>> class testmodule(FakeModule):
-  ...   fake_module = True
-  ...   description("Description")
-  Traceback (most recent call last):
-    ...
-  GrokImportError: The 'description' directive can only be used on class level.
-
-We cannot use the directive twice in the class scope. If we do so, we
-get an error message as well::
-
-  >>> class Foo(object):
-  ...   description(u"Description1")
-  ...   description(u"Description2")
-  Traceback (most recent call last):
-    ...
-  GrokImportError: The 'description' directive can only be called once per class.
-
-We cannot call the directive with no argument either::
-
-  >>> class Foo(object):
-  ...   description()
-  Traceback (most recent call last):
-    ...
-  TypeError: description takes exactly 1 argument (0 given)
-
-Class and module scope
-----------------------
-
-We define a ``layer`` directive that can be used in class and module
-scope both::
-
-  >>> from martian.ndir import CLASS_OR_MODULE
-  >>> class layer(Directive):
-  ...     scope = CLASS_OR_MODULE
-  ...     store = ONCE
-
-By default, the ``default`` property is None which is why we can omit
-specifying it here.
-
-We can use this directive now on a class::
-
-  >>> class Foo(object):
-  ...   layer('Test')
-  >>> layer.get(Foo)
-  'Test'
-
-The defaulting to ``None`` works::
-
-  >>> class Foo(object):
-  ...   pass
-  >>> layer.get(Foo) is None
-  True
-
-We can also use it in a module::
-
-  >>> class testmodule(FakeModule):
-  ...    layer('Test2')
-  ...    class Foo(object):
-  ...       pass
-  >>> test_module = fake_import(testmodule)
-
-When we now try to access ``layer`` on ``Foo``, we find the
-module-level default which we just set. We pass the module as the
-second argument to the ``get`` method to have it fall back on this::
-
-  >>> layer.get(testmodule.Foo, testmodule)
-  'Test2'
-
-Let's look at a module where the directive is not used::
-
-  >>> class testmodule(FakeModule):
-  ...   class Foo(object):
-  ...      pass
-  >>> testmodule = fake_import(testmodule)
-
-In this case, the value cannot be found so the system falls back on
-the default, ``None``::
-
-  >>> layer.get(testmodule.Foo, testmodule) is None
-  True
-
-Using a directive multiple times
---------------------------------
-
-A directive can be configured to allow it to be called multiple times
-in the same scope::
-
-  >>> from martian.ndir import MULTIPLE
-  >>> class multi(Directive):
-  ...     scope = CLASS
-  ...     store = MULTIPLE
-
-We can now use the directive multiple times without any errors::
-
-  >>> class Foo(object):
-  ...   multi(u"Once")
-  ...   multi(u"Twice")
-
-We can now retrieve the value and we'll get a list::
-
-  >>> multi.get(Foo)
-  [u'Once', u'Twice']
-
-Using a directive multiple times, as a dictionary
--------------------------------------------------
-
-A directive can be configured to allow it to be called multiple times in the
-same scope. In this case the factory method should be overridden to return a
-key-value pair::
-
-  >>> from martian.ndir import DICT
-  >>> class multi(Directive):
-  ...     scope = CLASS
-  ...     store = DICT
-  ...     def factory(self, value):
-  ...         return value.lower(), value
-
-We can now use the directive multiple times without any errors::
-
-  >>> class Bar(object):
-  ...   multi(u"Once")
-  ...   multi(u"Twice")
-
-We can now retrieve the value and we'll get a to the items::
-
-  >>> d = multi.get(Bar)
-  >>> print sorted(d.items())
-  [(u'once', u'Once'), (u'twice', u'Twice')]
-
-When the factory method does not return a key-value pair, an error is raised::
-
-  >>> class wrongmulti(Directive):
-  ...     scope = CLASS
-  ...     store = DICT
-  ...     def factory(self, value):
-  ...         return None
-
-  >>> class Baz(object):
-  ...   wrongmulti(u"Once")
-  Traceback (most recent call last):
-  ...
-  GrokImportError: The factory method for the 'wrongmulti' directive should
-  return a key-value pair.
-
-  >>> class wrongmulti2(Directive):
-  ...     scope = CLASS
-  ...     store = DICT
-  ...     def factory(self, value):
-  ...         return value, value, value
-
-  >>> class Baz(object):
-  ...   wrongmulti2(u"Once")
-  Traceback (most recent call last):
-  ...
-  GrokImportError: The factory method for the 'wrongmulti2' directive should
-  return a key-value pair.
-
-Calculated defaults
--------------------
-
-Often instead of just supplying the system with a default, we want to
-calculate the default in some way. We define the ``name`` directive,
-which if not present, will calculate its value from the name of class,
-lower-cased. Instead of passing a default value, we pass a function as the
-default argument::
-
-  >>> class name(Directive):
-  ...     scope = CLASS
-  ...     store = ONCE
-  ...     def get_default(self, component):
-  ...         return component.__name__.lower()
-
-  >>> class Foo(object):
-  ...   name('bar')
-  >>> name.get(Foo)
-  'bar'
-
-  >>> class Foo(object):
-  ...   pass
-  >>> name.get(Foo)
-  'foo'
-
-A marker directive
-------------------
-
-Another type of directive is a marker directive. This directive takes
-no arguments at all, but when used it marks the context::
-
-  >>> from martian.ndir import MarkerDirective
-  >>> class mark(MarkerDirective):
-  ...     scope = CLASS
-
-  >>> class Foo(object):
-  ...     mark()
-
-Class ``Foo`` is now marked::
-
-  >>> mark.get(Foo)
-  True
-
-When we have a class that isn't marked, we get the default value, ``False``::
-
-  >>> class Bar(object):
-  ...    pass
-  >>> mark.get(Bar)
-  False
-
-If we pass in an argument, we get an error::
-
-  >>> class Bar(object):
-  ...   mark("An argument")
-  Traceback (most recent call last):
-    ...
-  TypeError: mark takes no arguments (1 given)
-
-
-Validation
-----------
-
-A directive can be supplied with a validation method. The validation method
-checks whether the value passed in is allowed. It should raise
-``GrokImportError`` if the value cannot be validated, together with a
-description of why not.
-
-First we define our own validation function. A validation function
-takes two arguments:
-
-* the name of the directive we're validating for
-
-* the value we need to validate
-
-The name can be used to format the exception properly.
-
-We'll define a validation method that only expects integer numbers::
-
-  >>> from martian.error import GrokImportError
-  >>> class number(Directive):
-  ...     scope = CLASS
-  ...     store = ONCE
-  ...     def validate(self, value):
-  ...         if type(value) is not int:
-  ...             raise GrokImportError("The '%s' directive can only be called with an integer." %
-  ...                                   self.name)
-
-  >>> class Foo(object):
-  ...    number(3)
-
-  >>> class Foo(object):
-  ...    number("This shouldn't work")
-  Traceback (most recent call last):
-    ...
-  GrokImportError: The 'number' directive can only be called with an integer.
-
-Some built-in validation functions
-----------------------------------
-
-Let's look at some built-in validation functions.
-
-The ``validateText`` function determines whether a string
-is unicode or plain ascii::
-
-  >>> from martian.ndir import validateText
-  >>> class title(Directive):
-  ...     scope = CLASS
-  ...     store = ONCE
-  ...     default = u''
-  ...     validate = validateText
-
-When we pass ascii text into the directive, there is no error::
-
-  >>> class Foo(object):
-  ...    title('Some ascii text')
-
-We can also pass in a unicode string without error::
-
-  >>> class Foo(object):
-  ...    title(u'Some unicode text')
-
-Let's now try it with something that's not text at all, such as a number.
-This fails::
-
-  >>> class Foo(object):
-  ...    title(123)
-  Traceback (most recent call last):
-    ...
-  GrokImportError: The 'title' directive can only be called with unicode or ASCII.
-
-It's not allowed to call the direct with a non-ascii encoded string::
-
-  >>> class Foo(object):
-  ...   title(u'è'.encode('latin-1'))
-  Traceback (most recent call last):
-    ...
-  GrokImportError: The 'title' directive can only be called with unicode or ASCII.
-
- >>> class Foo(object):
- ...   title(u'è'.encode('UTF-8'))
- Traceback (most recent call last):
-   ...
- GrokImportError: The 'title' directive can only be called with unicode or ASCII.
-
-The ``validateInterfaceOrClass`` function only accepts class or
-interface objects::
-
-  >>> from martian.ndir import validateInterfaceOrClass
-  >>> class klass(Directive):
-  ...     scope = CLASS
-  ...     store = ONCE
-  ...     validate = validateInterfaceOrClass
-
-It works with interfaces and classes::
-
-  >>> class Bar(object):
-  ...    pass
-  >>> class Foo(object):
-  ...    klass(Bar)
-
-  >>> from zope.interface import Interface
-  >>> class IBar(Interface):
-  ...    pass
-  >>> class Foo(object):
-  ...    klass(IBar)
-
-It won't work with other things::
-
-  >>> class Foo(object):
-  ...   klass(Bar())
-  Traceback (most recent call last):
-    ...
-  GrokImportError: The 'klass' directive can only be called with a class or an interface.
-
-  >>> class Foo(object):
-  ...   klass(1)
-  Traceback (most recent call last):
-    ...
-  GrokImportError: The 'klass' directive can only be called with a class or an interface.
-
-The ``validateInterface`` validator only accepts an interface::
-
-  >>> from martian.ndir import validateInterface
-  >>> class iface(Directive):
-  ...     scope = CLASS
-  ...     store = ONCE
-  ...     validate = validateInterface
-
-Let's try it::
-
-  >>> class Foo(object):
-  ...    iface(IBar)
-
-It won't work with classes or other things::
-
-  >>> class Foo(object):
-  ...   iface(Bar)
-  Traceback (most recent call last):
-    ...
-  GrokImportError: The 'iface' directive can only be called with an interface.
-
-  >>> class Foo(object):
-  ...   iface(1)
-  Traceback (most recent call last):
-    ...
-  GrokImportError: The 'iface' directive can only be called with an interface.
-
-Declaring base classes
-----------------------
-
-There's a special directive called 'baseclass' which lets you declare that a
-certain class is the base class for a series of other components.  This
-property should not be inherited by those components.  Consider the following
-base class:
-
-  >>> from martian.ndir import baseclass
-  >>> class MyBase(object):
-  ...     baseclass()
-
-As you would expect, the directive will correctly identify this class as a
-baseclass:
-
-  >>> baseclass.get(MyBase)
-  True
-
-But, if we create a subclass of this base class, the subclass won't inherit
-that property, unlike with a regular directive:
-
-  >>> class SubClass(MyBase):
-  ...     pass
-  ...
-  >>> baseclass.get(SubClass)
-  False
-
-Naturally, the directive will also report a false answer if the class doesn't
-inherit from a base class at all and hasn't been marked with the directive:
-
-  >>> class NoBase(object):
-  ...     pass
-  ...
-  >>> baseclass.get(NoBase)
-  False

Modified: martian/branches/jw-philipp-using-ndir-directives/src/martian/tests/test_all.py
===================================================================
--- martian/branches/jw-philipp-using-ndir-directives/src/martian/tests/test_all.py	2008-05-03 12:04:39 UTC (rev 86197)
+++ martian/branches/jw-philipp-using-ndir-directives/src/martian/tests/test_all.py	2008-05-03 12:17:23 UTC (rev 86198)
@@ -70,9 +70,6 @@
                              optionflags=optionflags),
         doctest.DocFileSuite('directive.txt',
                              package='martian',
-                             optionflags=optionflags),
-        doctest.DocFileSuite('ndir.txt',
-                             package='martian',
                              globs=globs,
                              optionflags=optionflags),
         ])



More information about the Checkins mailing list