1############################################################################## 2# 3# Copyright (c) 2003 Zope Foundation and Contributors. 4# All Rights Reserved. 5# 6# This software is subject to the provisions of the Zope Public License, 7# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. 8# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED 9# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 10# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 11# FOR A PARTICULAR PURPOSE. 12# 13############################################################################## 14""" Utilities for the 'nested directive' section in the narrative docs. 15""" 16 17from zope.interface import Attribute 18from zope.interface import Interface 19from zope.interface import implementer 20from zope.schema import BytesLine 21from zope.schema import Id 22from zope.schema import Int 23from zope.schema import Text 24from zope.schema import TextLine 25from zope.configuration.config import GroupingContextDecorator 26from zope.configuration.config import IConfigurationContext 27from zope.configuration.fields import Bool 28from zope.configuration._compat import u 29 30 31schema_registry = {} 32 33class ISchemaInfo(Interface): 34 """Parameter schema for the schema directive 35 """ 36 37 name = TextLine( 38 title=u("The schema name"), 39 description=u("This is a descriptive name for the schema."), 40 ) 41 42 id = Id(title=u("The unique id for the schema")) 43 44class ISchema(Interface): 45 """Interface that distinguishes the schema directive 46 """ 47 48 fields = Attribute("Dictionary of field definitions") 49 50 51@implementer(IConfigurationContext, ISchema) 52class Schema(GroupingContextDecorator): 53 """Handle schema directives 54 """ 55 56 57 def __init__(self, context, name, id): 58 self.context, self.name, self.id = context, name, id 59 self.fields = {} 60 61 def after(self): 62 schema = Interface.__class__( 63 self.name, 64 (Interface, ), 65 self.fields 66 ) 67 schema.__doc__ = self.info.text.strip() 68 self.action( 69 discriminator=('schema', self.id), 70 callable=schema_registry.__setitem__, 71 args=(self.id, schema), 72 ) 73 74 75class IFieldInfo(Interface): 76 77 name = BytesLine( 78 title=u("The field name"), 79 ) 80 81 title = TextLine( 82 title=u("Title"), 83 description=u("A short summary or label"), 84 default=u(""), 85 required=False, 86 ) 87 88 required = Bool( 89 title=u("Required"), 90 description=u("Determines whether a value is required."), 91 default=True) 92 93 readonly = Bool( 94 title=u("Read Only"), 95 description=u("Can the value be modified?"), 96 required=False, 97 default=False) 98 99class ITextInfo(IFieldInfo): 100 101 min_length = Int( 102 title=u("Minimum length"), 103 description=u("Value after whitespace processing cannot have less than " 104 "min_length characters. If min_length is None, there is " 105 "no minimum."), 106 required=False, 107 min=0, # needs to be a positive number 108 default=0) 109 110 max_length = Int( 111 title=u("Maximum length"), 112 description=u("Value after whitespace processing cannot have greater " 113 "or equal than max_length characters. If max_length is " 114 "None, there is no maximum."), 115 required=False, 116 min=0, # needs to be a positive number 117 default=None) 118 119def field(context, constructor, name, **kw): 120 121 # Compute the field 122 field = constructor(description=context.info.text.strip(), **kw) 123 124 # Save it in the schema's field dictionary 125 schema = context.context 126 if name in schema.fields: 127 raise ValueError("Duplicate field", name) 128 schema.fields[name] = field 129 130 131def textField(context, **kw): 132 field(context, Text, **kw) 133 134class IIntInfo(IFieldInfo): 135 136 min = Int( 137 title=u("Start of the range"), 138 required=False, 139 default=None 140 ) 141 142 max = Int( 143 title=u("End of the range (excluding the value itself)"), 144 required=False, 145 default=None 146 ) 147 148def intField(context, **kw): 149 field(context, Int, **kw) 150