[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