diff --git a/doc/_themes/odoodoc/layout.html b/doc/_themes/odoodoc/layout.html index 7685d8af25fcdf2b4131b79a6d1de889fb2e0c07..1a68d31814a093e700dab860812bef21d824c84d 100644 --- a/doc/_themes/odoodoc/layout.html +++ b/doc/_themes/odoodoc/layout.html @@ -32,7 +32,7 @@ <div class="sphinxsidebar"> <div class="sphinxsidebarwrapper"> {{ toctree(maxdepth=4, collapse=False, includehidden=True, - main_navbar=False, titles_only=False) }} + navbar='side', titles_only=False) }} {% if github_link %} <p><a href="{{ github_link(mode='edit') }}" class="github"> Edit on GitHub @@ -72,7 +72,8 @@ {% endif %} </div> <nav class="collapse navbar-collapse navbar-main" role="navigation"> - {{ toctree(titles_only=True, maxdepth=2, includehidden=True, collapse=False) }} + {{ toctree(titles_only=True, maxdepth=2, includehidden=True, + collapse=False, navbar='main') }} </nav> </div> </header> diff --git a/doc/_themes/odoodoc/sphinx_monkeypatch.py b/doc/_themes/odoodoc/sphinx_monkeypatch.py index 13c3a305988bb543c64f835493a9d4705d7ad71b..182fef89c8d0a3fb6a8171b766947389ba61c826 100644 --- a/doc/_themes/odoodoc/sphinx_monkeypatch.py +++ b/doc/_themes/odoodoc/sphinx_monkeypatch.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import sphinx.roles import sphinx.environment -from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.writers.html import HTMLTranslator from docutils.writers.html4css1 import HTMLTranslator as DocutilsTranslator @@ -9,27 +8,17 @@ def patch(): # navify toctree (oh god) @monkey(sphinx.environment.BuildEnvironment) def resolve_toctree(old_resolve, self, *args, **kwargs): - """ If main_navbar, bootstrapify TOC to yield a navbar + """ If navbar, bootstrapify TOC to yield a navbar """ - main_navbar = kwargs.pop('main_navbar', False) + navbar = kwargs.pop('navbar', None) toc = old_resolve(self, *args, **kwargs) if toc is None: return None - navbarify(toc[0], main_navbar=main_navbar) + navbarify(toc[0], navbar=navbar) return toc - @monkey(StandaloneHTMLBuilder) - def _get_local_toctree(old_local, self, *args, **kwargs): - """ _get_local_toctree generates a documentation toctree for the local - document (?), called from handle_page - """ - # so can call toctree(main_navbar=False) - d = {'main_navbar': True} - d.update(kwargs) - return old_local(self, *args, **d) - # monkeypatch visit_table to remove border and add .table HTMLTranslator.visit_table = visit_table # disable colspec crap @@ -37,11 +26,18 @@ def patch(): # copy data- attributes straight from source to dest HTMLTranslator.starttag = starttag_data -def navbarify(node, main_navbar=False): - # add classes to toplevel - if not main_navbar: - navify([node]) - else: +def navbarify(node, navbar=None): + """ + :param node: toctree node to navbarify + :param navbar: Whether this toctree is a 'main' navbar, a 'side' navbar or + not a navbar at all + """ + if navbar == 'side': + for n in node.traverse(): + if n.tagname == 'bullet_list': + n['classes'].append('nav') + elif navbar == 'main': + # add classes to just toplevel node['classes'].extend(['nav', 'navbar-nav', 'navbar-right']) for list_item in node.children: # bullet_list @@ -52,6 +48,10 @@ def navbarify(node, main_navbar=False): # list_item # compact_paragraph # reference + # no bullet_list.list_item -> don't dropdownify + if not list_item.children[1].children: + return + list_item['classes'].append('dropdown') # list_item.compact_paragraph.reference link = list_item.children[0].children[0] @@ -59,11 +59,6 @@ def navbarify(node, main_navbar=False): link.attributes['data-toggle'] = 'dropdown' # list_item.bullet_list list_item.children[1]['classes'].append('dropdown-menu') -def navify(nodes): - for node in nodes: - if node.tagname == 'bullet_list': - node['classes'].append('nav') - navify(node.children) def visit_table(self, node): """ diff --git a/doc/_themes/odoodoc/static/style.css b/doc/_themes/odoodoc/static/style.css index 19f5270109e0770e11d0b286d3495f5af7075bd1..7c0b8e82959cf4f269ce6e29bbc490f9ff71afe2 100644 --- a/doc/_themes/odoodoc/static/style.css +++ b/doc/_themes/odoodoc/static/style.css @@ -5902,8 +5902,10 @@ button.close { .panel-body:after, .modal-footer:before, .modal-footer:after, -.document-super:before, -.document-super:after, +.document-super:not(.stripe):before, +.document-super:not(.stripe):after, +.document-super.stripe:before, +.document-super.stripe:after, .document:before, .document:after { content: " "; @@ -5924,7 +5926,8 @@ button.close { .pager:after, .panel-body:after, .modal-footer:after, -.document-super:after, +.document-super:not(.stripe):after, +.document-super.stripe:after, .document:after { clear: both; } @@ -6181,35 +6184,53 @@ body { overflow: auto; position: relative; } -.document-super { +.document-super:not(.stripe) { margin-right: auto; margin-left: auto; padding-left: 15px; padding-right: 15px; } @media (min-width: 768px) { - .document-super { + .document-super:not(.stripe) { width: 750px; } } @media (min-width: 992px) { - .document-super { + .document-super:not(.stripe) { width: 970px; } } @media (min-width: 1200px) { - .document-super { + .document-super:not(.stripe) { width: 1170px; } } -.document-super > .navbar-header, -.document-super > .navbar-collapse { +.document-super:not(.stripe) > .navbar-header, +.document-super:not(.stripe) > .navbar-collapse { margin-right: -15px; margin-left: -15px; } @media (min-width: 768px) { - .document-super > .navbar-header, - .document-super > .navbar-collapse { + .document-super:not(.stripe) > .navbar-header, + .document-super:not(.stripe) > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} +.document-super.stripe { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +.document-super.stripe > .navbar-header, +.document-super.stripe > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .document-super.stripe > .navbar-header, + .document-super.stripe > .navbar-collapse { margin-right: 0; margin-left: 0; } @@ -6296,7 +6317,7 @@ body { -o-transition: all 0.3s ease-out; transition: all 0.3s ease-out; } -.docs-nav .navbar-nav > li > a:after { +.docs-nav .navbar-nav > li.dropdown > a:after { content: " "; display: inline-block; width: 0; @@ -6307,7 +6328,7 @@ body { border-right: 4px solid transparent; border-left: 4px solid transparent; } -.docs-nav .navbar-nav > li .dropdown-menu > li.current > a.current { +.docs-nav .navbar-nav > li.dropdown .dropdown-menu > li.current > a.current { background-color: #a24689; color: white; } @@ -6709,6 +6730,74 @@ td.field-body > ul { .descclassname { opacity: 0.5; } +.index-tree ul, +.index-tree li { + list-style: none; + padding: 0; + margin: 0; +} +.index-tree > ul > li { + margin-bottom: 0.5em; +} +.index-tree > ul > li > a { + font-family: Lato, Arial, sans-serif; + font-weight: 500; + line-height: 1.1; + color: inherit; + margin-top: 20px; + margin-bottom: 10px; + font-size: 24px; + text-align: center; +} +.index-tree > ul > li > a small, +.index-tree > ul > li > a .small { + font-weight: normal; + line-height: 1; + color: #777777; +} +.index-tree > ul > li > a small, +.index-tree > ul > li > a .small { + font-size: 65%; +} +.index-tree > ul > li > ul { + display: -webkit-flex; + display: flex; + -webkit-flex-wrap: wrap; + flex-wrap: wrap; +} +.index-tree > ul > li > ul > li { + width: 50%; +} +.index-tree > ul > li > ul > li a { + font-family: Lato, Arial, sans-serif; + font-weight: 500; + line-height: 1.1; + color: inherit; + margin-top: 10px; + margin-bottom: 10px; + font-size: 18px; + padding-left: 10%; + padding-right: 10%; +} +.index-tree > ul > li > ul > li a small, +.index-tree > ul > li > ul > li a .small { + font-weight: normal; + line-height: 1; + color: #777777; +} +.index-tree > ul > li > ul > li a small, +.index-tree > ul > li > ul > li a .small { + font-size: 75%; +} +.index-tree > ul > li a { + display: block; + color: #a24689 !important; + padding: 0.3em 0; + margin: 3px !important; +} +.index-tree > ul > li a:hover { + background-color: #eeeeee; +} .stripe .section { margin-bottom: 2em; } diff --git a/doc/_themes/odoodoc/static/style.less b/doc/_themes/odoodoc/static/style.less index 719fa6f10e3fe3ddf4beef0dfd84a1d2eb3aa5ed..ea53cd95e8526c2ae0736fe69d333228510296d4 100644 --- a/doc/_themes/odoodoc/static/style.less +++ b/doc/_themes/odoodoc/static/style.less @@ -25,9 +25,12 @@ body { position: relative; } -.document-super { +.document-super:not(.stripe) { .container(); } +.document-super.stripe { + .container-fluid(); +} .document { .make-row(); @@ -89,20 +92,22 @@ body { opacity: 0; .transition(all 0.3s ease-out); } - > a:after { - content: " "; - display: inline-block; - width: 0; - height: 0; - margin-left: 5px; - vertical-align: middle; - border-top: 4px solid @gray-light; - border-right: 4px solid transparent; - border-left: 4px solid transparent; - } - .dropdown-menu > li.current > a.current { - background-color: @brand-primary; - color: white; + &.dropdown { + > a:after { + content: " "; + display: inline-block; + width: 0; + height: 0; + margin-left: 5px; + vertical-align: middle; + border-top: 4px solid @gray-light; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + } + .dropdown-menu > li.current > a.current { + background-color: @brand-primary; + color: white; + } } } /* version switcher */ @@ -547,6 +552,44 @@ td.field-body { opacity: 0.5; } + +.index-tree { + ul, li { + list-style: none; + padding: 0; + margin: 0; + } + > ul > li { + margin-bottom: 0.5em; + > a { + .h3(); + text-align: center; + } + > ul { + display: -webkit-flex; + display: flex; + -webkit-flex-wrap: wrap; + flex-wrap: wrap; + > li { + width: 50%; + a { + .h4(); + padding-left: 10%; + padding-right: 10%; + } + } + } + a { + display: block; + color: @link-color !important; + padding: 0.3em 0; + margin: 3px !important; + &:hover { + background-color: @gray-lighter; + } + } + } +} // STRIPE-STYLE PAGES .stripe { .section { diff --git a/doc/modules/api_integration.rst b/doc/api_integration.rst similarity index 99% rename from doc/modules/api_integration.rst rename to doc/api_integration.rst index 21d0163ba4691a8a57465f0f87ce87fd6050f2a0..12c5b56737e8dff83369709e1c6d68a302273433 100644 --- a/doc/modules/api_integration.rst +++ b/doc/api_integration.rst @@ -1,7 +1,7 @@ :classes: stripe =========== -Odoo as API +Web Service =========== Odoo is mostly extended internally via modules, but much of its features and @@ -250,8 +250,8 @@ the login. Calling methods =============== -The second — and most generally useful — is ``xmlrpc/2/object`` which is used -to call methods of odoo models via the ``execute_kw`` RPC function. +The second endpoint is ``xmlrpc/2/object``, is used to call methods of odoo +models via the ``execute_kw`` RPC function. Each call to ``execute_kw`` takes the following parameters: diff --git a/doc/images/view-on-github.png b/doc/images/view-on-github.png deleted file mode 100644 index 65a8d42363de1b3414c175ca606491f74ca30b8d..0000000000000000000000000000000000000000 Binary files a/doc/images/view-on-github.png and /dev/null differ diff --git a/doc/index.rst b/doc/index.rst index 3c1696020d6a4cc65769484d319c45c722012653..56f58b6aa0d428aecdbef384698889251920a2df 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -4,38 +4,17 @@ odoo developer documentation Welcome to the Odoo developer documentation. -This documentation is incomplete and may contain errors, if you wish to -contribute, every page should have a :guilabel:`View on Github` link: - -.. image:: images/view-on-github.* - :align: center - -Through this link you can edit documents and submit changes for review using -`github's web interface -<https://help.github.com/articles/editing-files-in-your-repository/>`_. -Contributions are welcome and appreciated. - .. todo:: what's the documentation's license? -The documentation is currently organized in four sections: - -* :doc:`tutorials`, aimed at introducing the primary areas of developing Odoo - modules -* :doc:`reference`, which ought be the complete and canonical documentation - for Odoo subsystems -* :doc:`modules`, documenting useful specialized modules and integration - methods (and currently empty) - -.. hidden toctree w/o titlesonly otherwise the titlesonly "sticks" to - in-document toctrees and we can't have a toctree showing both "sibling" - pages and current document sections - +.. rst-class:: index-tree +.. titlesonly breaks level 3 (~in-document) toc of left navbar, so use + maxdepth instead .. toctree:: - :hidden: + :maxdepth: 2 tutorials reference - modules + api_integration .. ifconfig:: todo_include_todos diff --git a/doc/modules.rst b/doc/modules.rst deleted file mode 100644 index cb5ed8d6ca1590e0a11610235006fb7124c5ac36..0000000000000000000000000000000000000000 --- a/doc/modules.rst +++ /dev/null @@ -1,8 +0,0 @@ -============== -Module Objects -============== - -.. toctree:: - :titlesonly: - - modules/api_integration diff --git a/doc/reference/cmdline.rst b/doc/reference/cmdline.rst index 32c1ef487295c2e74a39668d0f535b6a39b79e0a..1ec7d96ae9d8013eef326dcd18d49276d4b60761 100644 --- a/doc/reference/cmdline.rst +++ b/doc/reference/cmdline.rst @@ -71,7 +71,7 @@ Scaffolding is available via the :command:`odoo.py scaffold` subcommand. .. option:: -t <template> a template directory, files are passed through jinja2_ then copied to - the :option:`destination` directory + the ``destination`` directory .. option:: name diff --git a/doc/reference/orm.rst b/doc/reference/orm.rst index 94aa18b48638b8212a65ff28c66e68a2932649dc..cfc465078b197afcc5e8b43844d24ac6914b19cc 100644 --- a/doc/reference/orm.rst +++ b/doc/reference/orm.rst @@ -421,10 +421,31 @@ added. is not written to the database, just used to know which value to send back to the client +Low-level SQL +------------- + +The :attr:`~openerp.api.Environment.cr` attribute on environments is the +cursor for the current database transaction and allows executing SQL directly, +either for queries which are difficult to express using the ORM (e.g. complex +joins) or for performance reasons:: + + self.env.cr.execute("some_sql", param1, param2, param3) + +Because models use the same cursor and the :class:`~openerp.api.Environment` +holds various caches, these caches must be invalidated when *altering* the +database in raw SQL, or further uses of models may become incoherent. It is +necessary to clear caches when using ``CREATE``, ``UPDATE`` or ``DELETE`` in +SQL, but not ``SELECT`` (which simply reads the database). + +Clearing caches can be performed using the +:meth:`~openerp.api.Environment.invalidate_all` method of the +:class:`~openerp.api.Environment` object. + + .. _reference/orm/oldapi: Old API compatibility ---------------------- +===================== Odoo is currently transitioning from an older (less regular) API, it can be necessary to manually bridge from one to the other manually: @@ -508,170 +529,6 @@ return lists of ids, there is also a decorator managing this: >>> old_style_model.some_method(cr, uid, [1, 2, 3], context=context) [1, 2, 3] -Porting from the old API ------------------------- - -* methods still written in the old API should be automatically bridged by the - ORM, no need to switch to the old API, just call them as if they were a new - API method. See :ref:`reference/orm/oldapi/bridging` for more details. -* ``search`` returns a recordset, no point in e.g. browsing its result -* ``fields.related`` and ``fields.function`` are replaced by using a normal - field type with either a ``related`` or a ``compute`` parameter -* ``depends`` on field compute methods **must be complete**, it must list - **all** the fields and sub-fields which the compute method uses. It is - better to have too many dependencies (will recompute the field in cases - where that is not needed) than not enough (will forget to recompute the - field and then values will be incorrect) -* **remove** all ``onchange`` methods on computed fields. Computed fields are - automatically re-computed when one of their dependencies is changed, and - that is used to auto-generate ``onchange`` by the client -* the decorators :func:`~openerp.api.model` and :func:`~openerp.api.multi` are - for bridging *when calling from the old API context*, for internal or pure - new-api (e.g. compute) they are useless -* remove :attr:`~openerp.models.Model._default`, replace by ``default=`` - parameter on corresponding fields -* if a field's ``string`` is the titlecased version of the field name:: - - name = fields.Char(string="Name") - - it is useless and should be removed -* ``multi`` does not do anything on new API fields use the same ``compute`` - methods on all relevant fields for the same result -* provide ``compute``, ``inverse`` and ``search`` methods by name (as a - string), this makes them overridable (removes the need for an intermediate - "trampoline" function) -* double check that all fields and methods have different names, there is no - warning in case of collision (because Python handles it before Odoo sees - anything) -* the normal new-api import is ``from openerp import fields, models``. If - compatibility decorators are necessary, use ``from openerp import api, - fields, models`` -* avoid the :func:`~openerp.api.one` decorator, it probably does not do what - you expect -* remove explicit definition of :attr:`~openerp.models.Model.create_uid`, - :attr:`~openerp.models.Model.create_date`, - :attr:`~openerp.models.Model.write_uid` and - :attr:`~openerp.models.Model.write_date` fields: they are now created as - regular "legitimate" fields, and can be read and written like any other - field out-of-the-box -* when straight conversion is impossible (semantics can not be bridged) or the - "old API" version is not desirable and could be improved for the new API, it - is possible to use completely different "old API" and "new API" - implementations for the same method name using :func:`~openerp.api.v7` and - :func:`~openerp.api.v8`. The method should first be defined using the - old-API style and decorated with :func:`~openerp.api.v7`, it should then be - re-defined using the exact same name but the new-API style and decorated - with :func:`~openerp.api.v8`. Calls from an old-API context will be - dispatched to the first implementation and calls from a new-API context will - be dispatched to the second implementation. One implementation can call (and - frequently does) call the other by switching context. - - .. danger:: using these decorators makes methods extremely difficult to - override and harder to understand and document -* uses of :attr:`~openerp.models.Model._columns` or - :attr:`~openerp.models.Model._all_columns` should be replaced by - :attr:`~openerp.models.Model._fields`, which provides access to instances of - new-style :class:`openerp.fields.Field` instances (rather than old-style - :class:`openerp.osv.fields._column`). - - Non-stored computed fields created using the new API style are *not* - available in :attr:`~openerp.models.Model._columns` and can only be - inspected through :attr:`~openerp.models.Model._fields` -* reassigning ``self`` in a method is probably unnecessary and may break - translation introspection -* :class:`~openerp.api.Environment` objects rely on some threadlocal state, - which has to be set up before using them. It is necessary to do so using the - :meth:`openerp.api.Environment.manage` context manager when trying to use - the new API in contexts where it hasn't been set up yet, such as new threads - or a Python interactive environment:: - - >>> from openerp import api, modules - >>> r = modules.registry.RegistryManager.get('test') - >>> cr = r.cursor() - >>> env = api.Environment(cr, 1, {}) - Traceback (most recent call last): - ... - AttributeError: environments - >>> with api.Environment.manage(): - ... env = api.Environment(cr, 1, {}) - ... print env['res.partner'].browse(1) - ... - res.partner(1,) - -.. _reference/orm/oldapi/bridging: - -Automatic bridging of old API methods -''''''''''''''''''''''''''''''''''''' - -When models are initialized, all methods are automatically scanned and bridged -if they look like models declared in the old API style. This bridging makes -them transparently callable from new-API-style methods. - -Methods are matched as "old-API style" if their second positional parameter -(after ``self``) is called either ``cr`` or ``cursor``. The system also -recognizes the third positional parameter being called ``uid`` or ``user`` and -the fourth being called ``id`` or ``ids``. It also recognizes the presence of -any parameter called ``context``. - -When calling such methods from a new API context, the system will -automatically fill matched parameters from the current -:class:`~openerp.api.Environment` (for :attr:`~openerp.api.Environment.cr`, -:attr:`~openerp.api.Environment.user` and -:attr:`~openerp.api.Environment.context`) or the current recordset (for ``id`` -and ``ids``). - -In the rare cases where it is necessary, the bridging can be customized by -decorating the old-style method: - -* disabling it entirely, by decorating a method with - :func:`~openerp.api.noguess` there will be no bridging and methods will be - called the exact same way from the new and old API styles -* defining the bridge explicitly, this is mostly for methods which are matched - incorrectly (because parameters are named in unexpected ways): - - :func:`~openerp.api.cr` - will automatically prepend the current cursor to explicitly provided - parameters, positionally - :func:`~openerp.api.cr_uid` - will automatically prepend the current cursor and user's id to explictly - provided parameters - :func:`~openerp.api.cr_uid_ids` - will automatically prepend the current cursor, user's id and recordset's - ids to explicitly provided parameters - :func:`~openerp.api.cr_uid_id` - will loop over the current recordset and call the method once for each - record, prepending the current cursor, user's id and record's id to - explicitly provided parameters. - - .. danger:: the result of this wrapper is *always a list* when calling - from a new-API context - - All of these methods have a ``_context``-suffixed version - (e.g. :func:`~openerp.api.cr_uid_context`) which also passes the current - context *by keyword*. -* dual implementations using :func:`~openerp.api.v7` and - :func:`~openerp.api.v8` will be ignored as they provide their own "bridging" - -Low-level SQL -------------- - -The :attr:`~openerp.api.Environment.cr` attribute on environments is the -cursor for the current database transaction and allows executing SQL directly, -either for queries which are difficult to express using the ORM (e.g. complex -joins) or for performance reasons:: - - self.env.cr.execute("some_sql", param1, param2, param3) - -Because models use the same cursor and the :class:`~openerp.api.Environment` -holds various caches, these caches must be invalidated when *altering* the -database in raw SQL, or further uses of models may become incoherent. It is -necessary to clear caches when using ``CREATE``, ``UPDATE`` or ``DELETE`` in -SQL, but not ``SELECT`` (which simply reads the database). - -Clearing caches can be performed using the -:meth:`~openerp.api.Environment.invalidate_all` method of the -:class:`~openerp.api.Environment` object. - .. _reference/orm/model: Model Reference @@ -1168,3 +1025,148 @@ Domain criteria can be combined using logical operators in *prefix* form: (name is 'ABC') AND (language is NOT english) AND (country is Belgium OR Germany) + +Porting from the old API +======================== + +* methods still written in the old API should be automatically bridged by the + ORM, no need to switch to the old API, just call them as if they were a new + API method. See :ref:`reference/orm/oldapi/bridging` for more details. +* :meth:`~openerp.models.Model.search` returns a recordset, no point in e.g. + browsing its result +* ``fields.related`` and ``fields.function`` are replaced by using a normal + field type with either a ``related=`` or a ``compute=`` parameter +* :func:`~openerp.api.depends` on ``compute=`` methods **must be complete**, + it must list **all** the fields and sub-fields which the compute method + uses. It is better to have too many dependencies (will recompute the field + in cases where that is not needed) than not enough (will forget to recompute + the field and then values will be incorrect) +* **remove** all ``onchange`` methods on computed fields. Computed fields are + automatically re-computed when one of their dependencies is changed, and + that is used to auto-generate ``onchange`` by the client +* the decorators :func:`~openerp.api.model` and :func:`~openerp.api.multi` are + for bridging *when calling from the old API context*, for internal or pure + new-api (e.g. compute) they are useless +* remove :attr:`~openerp.models.Model._default`, replace by ``default=`` + parameter on corresponding fields +* if a field's ``string=`` is the titlecased version of the field name:: + + name = fields.Char(string="Name") + + it is useless and should be removed +* the ``multi=`` parameter does not do anything on new API fields use the same + ``compute=`` methods on all relevant fields for the same result +* provide ``compute=``, ``inverse=`` and ``search=`` methods by name (as a + string), this makes them overridable (removes the need for an intermediate + "trampoline" function) +* double check that all fields and methods have different names, there is no + warning in case of collision (because Python handles it before Odoo sees + anything) +* the normal new-api import is ``from openerp import fields, models``. If + compatibility decorators are necessary, use ``from openerp import api, + fields, models`` +* avoid the :func:`~openerp.api.one` decorator, it probably does not do what + you expect +* remove explicit definition of :attr:`~openerp.models.Model.create_uid`, + :attr:`~openerp.models.Model.create_date`, + :attr:`~openerp.models.Model.write_uid` and + :attr:`~openerp.models.Model.write_date` fields: they are now created as + regular "legitimate" fields, and can be read and written like any other + field out-of-the-box +* when straight conversion is impossible (semantics can not be bridged) or the + "old API" version is not desirable and could be improved for the new API, it + is possible to use completely different "old API" and "new API" + implementations for the same method name using :func:`~openerp.api.v7` and + :func:`~openerp.api.v8`. The method should first be defined using the + old-API style and decorated with :func:`~openerp.api.v7`, it should then be + re-defined using the exact same name but the new-API style and decorated + with :func:`~openerp.api.v8`. Calls from an old-API context will be + dispatched to the first implementation and calls from a new-API context will + be dispatched to the second implementation. One implementation can call (and + frequently does) call the other by switching context. + + .. danger:: using these decorators makes methods extremely difficult to + override and harder to understand and document +* uses of :attr:`~openerp.models.Model._columns` or + :attr:`~openerp.models.Model._all_columns` should be replaced by + :attr:`~openerp.models.Model._fields`, which provides access to instances of + new-style :class:`openerp.fields.Field` instances (rather than old-style + :class:`openerp.osv.fields._column`). + + Non-stored computed fields created using the new API style are *not* + available in :attr:`~openerp.models.Model._columns` and can only be + inspected through :attr:`~openerp.models.Model._fields` +* reassigning ``self`` in a method is probably unnecessary and may break + translation introspection +* :class:`~openerp.api.Environment` objects rely on some threadlocal state, + which has to be set up before using them. It is necessary to do so using the + :meth:`openerp.api.Environment.manage` context manager when trying to use + the new API in contexts where it hasn't been set up yet, such as new threads + or a Python interactive environment:: + + >>> from openerp import api, modules + >>> r = modules.registry.RegistryManager.get('test') + >>> cr = r.cursor() + >>> env = api.Environment(cr, 1, {}) + Traceback (most recent call last): + ... + AttributeError: environments + >>> with api.Environment.manage(): + ... env = api.Environment(cr, 1, {}) + ... print env['res.partner'].browse(1) + ... + res.partner(1,) + +.. _reference/orm/oldapi/bridging: + +Automatic bridging of old API methods +------------------------------------- + +When models are initialized, all methods are automatically scanned and bridged +if they look like models declared in the old API style. This bridging makes +them transparently callable from new-API-style methods. + +Methods are matched as "old-API style" if their second positional parameter +(after ``self``) is called either ``cr`` or ``cursor``. The system also +recognizes the third positional parameter being called ``uid`` or ``user`` and +the fourth being called ``id`` or ``ids``. It also recognizes the presence of +any parameter called ``context``. + +When calling such methods from a new API context, the system will +automatically fill matched parameters from the current +:class:`~openerp.api.Environment` (for :attr:`~openerp.api.Environment.cr`, +:attr:`~openerp.api.Environment.user` and +:attr:`~openerp.api.Environment.context`) or the current recordset (for ``id`` +and ``ids``). + +In the rare cases where it is necessary, the bridging can be customized by +decorating the old-style method: + +* disabling it entirely, by decorating a method with + :func:`~openerp.api.noguess` there will be no bridging and methods will be + called the exact same way from the new and old API styles +* defining the bridge explicitly, this is mostly for methods which are matched + incorrectly (because parameters are named in unexpected ways): + + :func:`~openerp.api.cr` + will automatically prepend the current cursor to explicitly provided + parameters, positionally + :func:`~openerp.api.cr_uid` + will automatically prepend the current cursor and user's id to explictly + provided parameters + :func:`~openerp.api.cr_uid_ids` + will automatically prepend the current cursor, user's id and recordset's + ids to explicitly provided parameters + :func:`~openerp.api.cr_uid_id` + will loop over the current recordset and call the method once for each + record, prepending the current cursor, user's id and record's id to + explicitly provided parameters. + + .. danger:: the result of this wrapper is *always a list* when calling + from a new-API context + + All of these methods have a ``_context``-suffixed version + (e.g. :func:`~openerp.api.cr_uid_context`) which also passes the current + context *by keyword*. +* dual implementations using :func:`~openerp.api.v7` and + :func:`~openerp.api.v8` will be ignored as they provide their own "bridging"