[IMP] Sphinx will automatically cross-reference return types it understands, for...
[odoo/odoo.git] / doc / source / addons.rst
1 Developing OpenERP Web Addons
2 =============================
3
4 Structure
5 ---------
6
7 .. literalinclude:: addon-structure.txt
8
9 ``__openerp__.py``
10   The addon's descriptor, contains the following information:
11
12   ``name: str``
13     The addon name, in plain, readable english
14   ``version: str``
15     The addon version, following `Semantic Versioning`_ rules
16   ``depends: [str]``
17     A list of addons this addon needs to work correctly. ``base`` is
18     an implied dependency if the list is empty.
19   ``css: [str]``
20     An ordered list of CSS files this addon provides and needs. The
21     file paths are relative to the addon's root. Because the Web
22     Client *may* perform concatenations and other various
23     optimizations on CSS files, the order is important.
24   ``js: [str]``
25     An ordered list of Javascript files this addon provides and needs
26     (including dependencies files). As with CSS files, the order is
27     important as the Web Client *may* perform contatenations and
28     minimizations of files.
29   ``active: bool``
30     Whether this addon should be enabled by default any time it is
31     found, or whether it will be enabled through other means (on a
32     by-need or by-installation basis for instance).
33
34 ``controllers/``
35   All of the Python controllers and JSON-RPC endpoints.
36
37 ``static/``
38   The static files directory, may be served via a separate web server.
39
40   The third-party dependencies should be bundled in it (each in their
41   own directory).
42
43 ``static/openerp/``
44   Sub-tree for all the addon's own static files.
45
46 ``static/openerp/{css,js,img}``
47   Location for (respectively) the addon's static CSS files, its JS
48   files and its various image resources.
49
50 ``tests/``
51   The directories in which all tests for the addon are located.
52
53 .. _addons-testing:
54
55 Testing
56 -------
57
58 Python
59 ++++++
60
61 OpenERP Web uses unittest2_ for its testing needs. We selected
62 unittest2 rather than unittest_ for the following reasons:
63
64 * autodiscovery_ (similar to nose, via the ``unit2``
65   CLI utility) and `pluggable test discovery`_.
66
67 * `new and improved assertions`_ (with improvements in type-specific
68   inequality reportings) including `pluggable custom types equality
69   assertions`_
70
71 * neveral new APIs, most notably `assertRaises context manager`_,
72   `cleanup function registration`_, `test skipping`_ and `class- and
73   module-level setup and teardown`_
74
75 * finally, unittest2 is a backport of Python 3's unittest. We might as
76   well get used to it.
77
78 To run tests on addons (from the root directory of OpenERP Web) is as
79 simple as typing ``PYTHONPATH=. unit2 discover -s addons`` [#]_. To
80 test an addon which does not live in the ``addons`` directory, simply
81 replace ``addons`` by the directory in which your own addon lives.
82
83 .. note:: unittest2 is entirely compatible with nose_ (or the
84      other way around). If you want to use nose as your test
85      runner (due to its addons for instance) you can simply install it
86      and run ``nosetests addons`` instead of the ``unit2`` command,
87      the result should be exactly the same.
88
89 APIs
90 ----
91
92 Javascript
93 ++++++++++
94
95 .. js:class:: openerp.base.Widget(view, node)
96
97     :param openerp.base.Controller view: The view to which the widget belongs
98     :param Object node: the ``fields_view_get`` descriptor for the widget
99
100     .. js:attribute:: $element
101
102         The widget's root element as jQuery object
103
104 .. js:class:: openerp.base.DataSet(session, model)
105
106     :param openerp.base.Session session: the RPC session object
107     :param String model: the model managed by this dataset
108
109     The DataSet is the abstraction for a sequence of records stored in
110     database.
111
112     It provides interfaces for reading records based on search
113     criteria, and for selecting and fetching records based on
114     activated ids.
115
116     .. js:function:: fetch([offset][, limit])
117
118        :param Number offset: the index from which records should start
119                              being returned (section)
120        :param Number limit: the maximum number of records to return
121        :returns: the dataset instance it was called on
122
123        Asynchronously fetches the records selected by the DataSet's
124        domain and context, in the provided sort order if any.
125
126        Only fetches the fields selected by the DataSet.
127
128        On success, triggers :js:func:`on_fetch`
129
130     .. js:function:: on_fetch(records, event)
131
132         :param Array records: an array of
133                              :js:class:`openerp.base.DataRecord`
134                              matching the DataSet's selection
135         :param event: a data holder letting the event handler fetch
136                      meta-informations about the event.
137         :type event: OnFetchEvent
138
139         Fired after :js:func:`fetch` is done fetching the records
140         selected by the DataSet.
141
142     .. js:function:: active_ids
143
144         :returns: the dataset instance it was called on
145
146         Asynchronously fetches the active records for this DataSet.
147
148         On success, triggers :js:func:`on_active_ids`
149
150     .. js:function:: on_active_ids(records)
151
152         :param Array records: an array of
153                               :js:class:`openerp.base.DataRecord`
154                               matching the currently active ids
155
156         Fired after :js:func:`active_ids` fetched the records matching
157         the DataSet's active ids.
158
159     .. js:function:: active_id
160
161         :returns: the dataset instance in was called on
162
163         Asynchronously fetches the current active record.
164
165         On success, triggers :js:func:`on_active_id`
166
167     .. js:function:: on_active_id(record)
168
169         :param Object record: the record fetched by
170                               :js:func:`active_id`, or ``null``
171         :type record: openerp.base.DataRecord
172
173         Fired after :js:func:`active_id` fetched the record matching
174         the dataset's active id
175
176     .. js:function:: set(options)
177
178         :param Object options: the options to set on the dataset
179         :type options: DataSetOptions
180         :returns: the dataset instance it was called on
181
182         Configures the data set by setting various properties on it
183
184     .. js:function:: prev
185
186         :returns: the dataset instance it was called on
187
188         Activates the id preceding the current one in the active ids
189         sequence of the dataset.
190
191         If the current active id is at the start of the sequence,
192         wraps back to the last id of the sequence.
193
194     .. js:function:: next
195
196         :returns: the dataset instance it was called on
197
198         Activates the id following the current one in the active ids
199         sequence.
200
201         If the current active id is the last of the sequence, wraps
202         back to the beginning of the active ids sequence.
203
204     .. js:function:: select(ids)
205
206         :param Array ids: the identifiers to activate on the dataset
207         :returns: the dataset instance it was called on
208
209         Activates all the ids specified in the dataset, resets the
210         current active id to be the first id of the new sequence.
211
212         The internal order will be the same as the ids list provided.
213
214     .. js:function:: get_active_ids
215
216         :returns: the list of current active ids for the dataset
217
218     .. js:function:: activate(id)
219
220         :param Number id: the id to activate
221         :returns: the dataset instance it was called on
222
223         Activates the id provided in the dataset. If no ids are
224         selected, selects the id in the dataset.
225
226         If ids are already selected and the provided id is not in that
227         selection, raises an error.
228
229     .. js:function:: get_active_id
230
231         :returns: the dataset's current active id
232
233 .. js:class:: openerp.base.DataRecord(session, model, fields, values)
234
235 Ad-hoc objects and structural types
236 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
237
238 These objects are not associated with any specific class, they're
239 generally literal objects created on the spot. Names are merely
240 convenient ways to refer to them and their properties.
241
242 .. js:class:: OnFetchEvent
243
244     .. js:attribute:: context
245
246         The context used for the :js:func:`fetch` call (domain set on
247         the :js:class:`openerp.base.DataSet` when ``fetch`` was
248         called)
249
250     .. js:attribute:: domain
251
252         The domain used for the :js:func:`fetch` call
253
254     .. js:attribute:: limit
255
256         The limit with which the original :js:func:`fetch` call was
257         performed
258
259     .. js:attribute:: offset
260
261         The offset with which the original :js:func:`fetch` call was
262         performed
263
264     .. js:attribute:: sort
265
266        The sorting criteria active on the
267        :js:class:`openerp.base.DataSet` when :js:func:`fetch` was
268        called
269
270 .. js:class:: DataSetOptions
271
272     .. js:attribute:: context
273
274     .. js:attribute:: domain
275
276     .. js:attribute:: sort
277
278 Python
279 ++++++
280
281 .. autoclass:: openerpweb.openerpweb.OpenERPSession
282     :members:
283
284 .. autoclass:: openerpweb.openerpweb.OpenERPModel
285     :members:
286
287 * Addons lifecycle (loading, execution, events, ...)
288
289   * Python-side
290   * JS-side
291
292 * Handling static files
293 * Overridding a Python controller (object?)
294 * Overridding a Javascript controller (object?)
295 * Extending templates
296   .. how do you handle deploying static files via e.g. a separate lighttpd?
297 * Python public APIs
298 * QWeb templates description?
299 * OpenERP Web modules (from OpenERP modules)
300
301 .. [#] the ``-s`` parameter tells ``unit2`` to start trying to
302        find tests in the provided directory (here we're testing
303        addons). However a side-effect of that is to set the
304        ``PYTHONPATH`` there as well, so it will fail to find (and
305        import) ``openerpweb``.
306
307        The ``-t`` parameter lets us set the ``PYTHONPATH``
308        independently, but it doesn't accept multiple values and here
309        we really want to have both ``.`` and ``addons`` on the
310        ``PYTHONPATH``.
311
312        The solution is to set the ``PYTHONPATH`` to ``.`` on start,
313        and the ``start-directory`` to ``addons``. This results in a
314        correct ``PYTHONPATH`` within ``unit2``.
315
316 .. _unittest:
317     http://docs.python.org/library/unittest.html
318
319 .. _unittest2:
320     http://www.voidspace.org.uk/python/articles/unittest2.shtml
321
322 .. _autodiscovery:
323     http://www.voidspace.org.uk/python/articles/unittest2.shtml#test-discovery
324
325 .. _pluggable test discovery:
326     http://www.voidspace.org.uk/python/articles/unittest2.shtml#load-tests
327
328 .. _new and improved assertions:
329     http://www.voidspace.org.uk/python/articles/unittest2.shtml#new-assert-methods
330
331 .. _pluggable custom types equality assertions:
332     http://www.voidspace.org.uk/python/articles/unittest2.shtml#add-new-type-specific-functions
333
334 .. _assertRaises context manager:
335     http://www.voidspace.org.uk/python/articles/unittest2.shtml#assertraises
336
337 .. _cleanup function registration:
338     http://www.voidspace.org.uk/python/articles/unittest2.shtml#cleanup-functions-with-addcleanup
339
340 .. _test skipping:
341     http://www.voidspace.org.uk/python/articles/unittest2.shtml#test-skipping
342
343 .. _class- and module-level setup and teardown:
344     http://www.voidspace.org.uk/python/articles/unittest2.shtml#class-and-module-level-fixtures
345
346 .. _Semantic Versioning:
347     http://semver.org/
348
349 .. _nose:
350     http://somethingaboutorange.com/mrl/projects/nose/1.0.0/