/usr/share/pyshared/lazr/restful/docs/interface.txt is in python-lazr.restful 0.19.3-0ubuntu2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | LAZR Interface Helpers
**********************
==============
use_template()
==============
Sometime it is convenient to create an interface by copying another one,
without creating a typed relationship between the two. A good use-case
for that is for a UI form. The model and form schema are related but not
identical. For examples, the labels/descriptions should probably be
different since the model doc is intended to the developers, while the
UI ones are for the user. The model may have additional fields that are
not relevant for the UI model and/or vice versa. And there is no reason
to say that an object providing the UI schema *is a* model. (Like the
extension relationship would allow us to claim.) In the end, the
relationship between the two schemas is one of convenience: we want to
share the data validation constraint specified by the model. For these
cases, there is lazr.restful.interface.use_template.
Let's define a "model" schema:
>>> from zope.interface import Attribute, Interface
>>> from zope.schema import Int, Choice, Text
>>> class MyModel(Interface):
... """A very simple model."""
...
... age = Int(title=u"Number of years since birth")
... name = Text(title=u"Identifier")
>>> class Initiated(MyModel):
... illuminated = Choice(
... title=u"Has seen the fnords?", values=('yes', 'no', 'maybe'))
... fancy_value = Attribute(u"Some other fancy value.")
The use_template() helper takes as first parameter the interface to use
as a template and either a 'include' or 'exclude' parameter taking the
list of the fields to include/exclude.
So to create a form for UI with more appropriate labels you would use:
>>> from lazr.restful.interface import use_template
>>> class MyForm1(Interface):
... "Form schema for a MyModel."
... use_template(MyModel, include=['age', 'name'])
... age.title = u'Your age:'
... name.title = u'Your name:'
The MyForm1 interface now has an age and name fields that have a
distinct titles than their original:
>>> sorted(MyForm1.names())
['age', 'name']
>>> print MyForm1.get('age').title
Your age:
>>> print MyForm1.get('name').title
Your name:
The interface attribute points to the correct interface:
>>> MyForm1.get('age').interface is MyForm1
True
And the original field wasn't updated:
>>> print MyModel.get('age').title
Number of years since birth
>>> MyModel.get('name').interface is MyModel
True
Using the exclude form of the directive, you could get an equivalent to
MyForm1 using the following:
>>> class MyForm2(Interface):
... use_template(Initiated, exclude=['illuminated', 'fancy_value'])
>>> sorted(MyForm2.names())
['age', 'name']
It is an error to use both arguments:
>>> class MyForm3(Interface):
... use_template(MyModel, include=['age'], exclude=['name'])
Traceback (most recent call last):
...
ValueError: you cannot use 'include' and 'exclude' at the same time.
If neither include, nor exclude are used. The new interface is an exact
copy of the template:
>>> class MyForm4(Interface):
... use_template(Initiated)
>>> sorted(MyForm4.names())
['age', 'fancy_value', 'illuminated', 'name']
The order of the field in the new interface is based on the order of the
declaration in the use_template() directive.
>>> class MyForm5(Interface):
... use_template(Initiated, include=['name', 'illuminated', 'age'])
>>> from zope.schema import getFieldNamesInOrder
>>> getFieldNamesInOrder(MyForm5)
['name', 'illuminated', 'age']
The directive can only be used from within a class scope:
>>> use_template(MyModel)
Traceback (most recent call last):
...
TypeError: use_template() can only be used from within a class
definition.
================
copy_attribute()
================
use_template() uses the copy_attribute() function to copy attributes from
the original interface. It can also be used on its own to make a copy of
an interface attribute or schema field.
>>> from lazr.restful.interface import copy_attribute
>>> illuminated = copy_attribute(Initiated['illuminated'])
>>> illuminated
<...Choice...>
>>> illuminated.__name__
'illuminated'
>>> illuminated.title
u'Has seen the fnords?'
The interface attribute is cleared:
>>> print illuminated.interface
None
It also supports the Field ordering (the copied field will have an
higher order than its original.)
>>> Initiated['illuminated'].order < illuminated.order
True
The parameter to the function must provide IAttribute:
>>> copy_attribute(MyModel)
Traceback (most recent call last):
...
TypeError: <...MyModel...> doesn't provide IAttribute.
============
copy_field()
============
There is also a copy_field() field function that can be used to copy a
schema field and override some of the copy attributes at the same time.
>>> from lazr.restful.interface import copy_field
>>> age = copy_field(
... MyModel['age'], title=u'The age.', required=False,
... arbitrary=1)
>>> age.__class__.__name__
'Int'
>>> age.title
u'The age.'
>>> age.arbitrary
1
>>> age.required
False
>>> MyModel['age'].required
True
If the value for an overridden field is invalid, an exception will be
raised:
>>> copy_field(MyModel['age'], title='This should be unicode')
Traceback (most recent call last):
...
WrongType: ...
That function can only be called on an IField:
>>> copy_field(Initiated['fancy_value'])
Traceback (most recent call last):
...
TypeError: <...Attribute...> doesn't provide IField.
|