diff --git a/README.md b/README.md
index 5bead0dba6..956011c884 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,7 @@
- Python dependencies listed in the file `requirements.txt`.
- Make
- A local copy of the [odoo/odoo repository](https://github.com/odoo/odoo) (optional)
+- A local copy of the [odoo/upgrade-util repository](https://github.com/odoo/upgrade-util) (optional)
### Instructions
@@ -18,8 +19,9 @@
3. See [this guide](https://www.odoo.com/documentation/latest/contributing/documentation.html)
for more detailed instructions.
-Optional: place your local copy of the `odoo/odoo` repository in the parent directory or in the root
-directory of the documentation to build the latter with the documented Python docstrings.
+Optional: place your local copy of the `odoo/odoo` and `odoo/upgrade-util` repositories in
+the parent directory or in the root directory of the documentation to build the latter
+with the documented Python docstrings.
## Contribute to the documentation
diff --git a/conf.py b/conf.py
index e5a6c682e7..ab3e2b0710 100644
--- a/conf.py
+++ b/conf.py
@@ -133,6 +133,24 @@
)
odoo_dir_in_path = True
+if odoo_dir_in_path:
+ upgrade_util_dir = next(filter(Path.exists, [Path('upgrade-util'), Path('../upgrade-util')]), None)
+ if not upgrade_util_dir:
+ _logger.warning(
+ "Could not find Upgrade Utils sources directory in `upgrade_util`.\n"
+ "The developer documentation will be built but autodoc directives will be skipped.\n"
+ "In order to fully build the 'Developer' documentation, clone the repository with "
+ "`git clone https://github.com/odoo/upgrade-util` or create a symbolic link."
+ )
+ odoo_dir_in_path = False
+ else:
+ _logger.info(
+ "Found Upgrade Util sources in %(directory)s",
+ {'directory': upgrade_util_dir.resolve()},
+ )
+ from odoo import upgrade
+ upgrade.__path__.append(str((upgrade_util_dir / 'src').resolve()))
+
# Mapping between odoo models related to master data and the declaration of the
# data. This is used to point users to available xml_ids when giving values for
# a field with the autodoc_field extension.
@@ -250,6 +268,9 @@
sphinx_tabs_disable_tab_closing = True
sphinx_tabs_disable_css_loading = True
+# Autodoc ordering
+autodoc_member_order = 'bysource'
+
#=== Options for HTML output ===#
html_theme = 'odoo_theme'
diff --git a/content/developer/howtos/upgrade_custom_db.rst b/content/developer/howtos/upgrade_custom_db.rst
index 276c2a588d..47db26402f 100644
--- a/content/developer/howtos/upgrade_custom_db.rst
+++ b/content/developer/howtos/upgrade_custom_db.rst
@@ -187,10 +187,10 @@ To make sure the custom code is working flawlessly in the new version, follow th
Migrate the data
----------------
-During the upgrade of the custom modules, you might have to use
-:doc:`upgrade scripts <../reference/upgrade_scripts>` to reflect changes from the source code
-to their corresponding data. Together with the upgrade scripts, you can also make use of the
-:doc:`../reference/upgrade_utils` and its helper functions.
+During the upgrade of the custom modules, you might have to use :doc:`upgrade scripts
+<../reference/upgrades/upgrade_scripts>` to reflect changes from the source code to their
+corresponding data. Together with the upgrade scripts, you can also make use of the
+:doc:`../reference/upgrades/upgrade_utils` and its helper functions.
- Any technical data that was renamed during the upgrade of the custom code (models, fields,
external identifiers) should be renamed using upgrade scripts to avoid data loss during the
@@ -220,7 +220,7 @@ to their corresponding data. Together with the upgrade scripts, you can also mak
"""
)
- Check the documentation for more information on :doc:`../reference/upgrade_scripts`.
+ Check the documentation for more information on :doc:`../reference/upgrades/upgrade_scripts`.
Upgrade scripts can also be used to:
diff --git a/content/developer/reference.rst b/content/developer/reference.rst
index a8b0c34b4d..af531f28ca 100644
--- a/content/developer/reference.rst
+++ b/content/developer/reference.rst
@@ -15,7 +15,6 @@ Reference
reference/user_interface
reference/standard_modules
reference/cli
- reference/upgrade_scripts
- reference/upgrade_utils
+ reference/upgrades
reference/external_api
reference/extract_api
diff --git a/content/developer/reference/upgrade_utils.rst b/content/developer/reference/upgrade_utils.rst
deleted file mode 100644
index 7c5da204fa..0000000000
--- a/content/developer/reference/upgrade_utils.rst
+++ /dev/null
@@ -1,279 +0,0 @@
-=============
-Upgrade utils
-=============
-
-`Upgrade utils `_ is a library that contains helper functions
-to facilitate the writing of upgrade scripts. This library, used by Odoo for the upgrade scripts of
-standard modules, provides reliability and helps speed up the upgrade process:
-
-- The helper functions help make sure the data is consistent in the database.
-- It takes care of indirect references of the updated records.
-- Allows calling functions and avoid writing code, saving time and reducing development risks.
-- Helpers allow to focus on what is important for the upgrade and not think of details.
-
-Installation
-============
-
-Clone the `Upgrade utils repository `_ locally and start
-``odoo`` with the ``src`` directory prepended to the ``--upgrade-path`` option.
-
-.. code-block:: console
-
- $ ./odoo-bin --upgrade-path=/path/to/upgrade-util/src,/path/to/other/upgrade/script/directory [...]
-
-On platforms where you do not manage Odoo yourself, you can install this library via `pip`:
-
-.. code-block:: console
-
- $ python3 -m pip install git+https://github.com/odoo/upgrade-util@master
-
-On `Odoo.sh `_ it is recommended to add it to the :file:`requirements.txt` of
-the custom repository. For this, add the following line inside the file::
-
- odoo_upgrade @ git+https://github.com/odoo/upgrade-util@master
-
-Using Upgrade utils
-===================
-
-Once installed, the following packages are available for the upgrade scripts:
-
-- :mod:`odoo.upgrade.util`: the helper itself.
-- :mod:`odoo.upgrade.testing`: base TestCase classes.
-
-To use it in upgrade scripts, simply import it:
-
-.. code-block:: python
-
- from odoo.upgrade import util
-
-
- def migrate(cr, version):
- # Rest of the script
-
-Now, the helper functions are available to be called through ``util``.
-
-Util functions
-==============
-
-Upgrade utils provides many useful functions to ease the upgrade process. Here, we describe some
-of the most useful ones. Refer to the `util folder
-`_ for the comprehensive declaration of
-helper functions.
-
-.. note::
-
- All util functions receive :attr:`cr` as a parameter. This refers to the database cursor. Pass
- the one received as a parameter in :meth:`migrate`.
-
-Fields
-------
-
-.. `[source] `_
-.. method:: remove_field(cr, model, fieldname, cascade=False, drop_column=True, skip_inherit=())
-
- Remove a field and its references from the database.
-
- :param str model: model name of the field to remove
- :param str fieldname: name of the field to remove
- :param bool cascade: whether the field's column and inheritance are removed in ``CASCADE``
- :param bool drop_column: whether the field's column is dropped
- :param list(str) or str skip_inherit: list of models whose field's inheritance is skipped.
- Use ``"*"`` to skip all inheritances
-
-.. `[source] `_
-.. method:: rename_field(cr, model, old, new, update_references=True, domain_adapter=None, skip_inherit=())
-
- Rename a field and its references from ``old`` to ``new``.
-
- :param str model: model name of the field to rename
- :param str old: current name od the field to rename
- :param str new: new name od the field to rename
- :param bool update_references: whether all references of field ``old`` to ``new`` are replaced
- in: ``ir_filters``, ``ir_exports_line``, ``ir_act_server``, ``mail_alias``,
- ``ir_ui_view_custom (dashboard)``, ``domains (using "domain_adapter")``, ``related fields``
- :param function domain_adapter: function that takes three arguments and returns a domain that
- substitutes the original leaf: ``(leaf: Tuple[str,str,Any], in_or: bool, negated: bool)`` ->
- ``List[Union[str,Tuple[str,str,Any]]]``
- :param list(str) or str skip_inherit: list of models whose field's inheritance is skipped.
- Use ``"*"`` to skip all inheritances
-
-.. `[source] `_
-.. method:: move_field_to_module(cr, model, fieldname, old_module, new_module, skip_inherit=())
-
- Move a field's reference in ``ir_model_data`` table from ``old_module`` to ``new_module``.
-
- :param str model: model name of the field to move
- :param str fieldname: name of the field to move
- :param str old_module: current module name of the field to move
- :param str new_module: new module name of the field to move
- :param list(str) or str skip_inherit: list of models whose field's inheritance is skipped.
- Use ``"*"`` to skip all inheritances
-
-Models
-------
-
-.. `[source] `_
-.. method:: remove_model(cr, model, drop_table=True, ignore_m2m=())
-
- Remove a model and its references from the database.
-
- :param str model: name of the model to remove
- :param bool drop_table: whether the model's table is dropped
- :param list(str) or str ignore_m2m: list of m2m tables ignored to remove. Use ``"*"`` to ignore
- all m2m tables
-
-.. `[source] `_
-.. method:: rename_model(cr, old, new, rename_table=True)
-
- Rename a model and its references from ``old`` to ``new``.
-
- :param str old: current name of the model to rename
- :param str new: new name of the model to rename
- :param bool rename_table: whether the model's table is renamed
-
-.. `[source] `_
-.. method:: merge_model(cr, source, target, drop_table=True, fields_mapping=None, ignore_m2m=())
-
- Merge the references from ``source`` model into ``target`` model and removes ``source`` model and
- its references. By default, only the fields with the same name in both models are mapped.
-
- .. warning::
- This function does not move the records from ``source`` model to ``target`` model.
-
- :param str source: name of the source model of the merge
- :param str target: name of the destination model of the merge
- :param bool drop_table: whether the source model's table is dropped
- :param dict fields_mapping: Dictionary ``{"source_model_field_1": "target_model_field_1", ...}``
- mapping fields with different names on both models
- :param list(str) or str ignore_m2m: list of m2m tables ignored to remove from source model.
-
-Modules
--------
-
-.. `[source] `_
-.. method:: remove_module(cr, module)
-
- Uninstall and remove a module and its references from the database.
-
- :param str module: name of the module to remove
-
-.. `[source] `_
-.. method:: rename_module(cr, old, new)
-
- Rename a module and its references from ``old`` to ``new``.
-
- :param str old: current name of the module to rename
- :param str new: new name of the module to rename
-
-.. `[source] `_
-.. method:: merge_module(cr, old, into, update_dependers=True)
-
- Move all references of module ``old`` into module ``into``.
-
- :param str old: name of the source module of the merge
- :param str into: ame of the destination module of the merge
- :param bool update_dependers: whether the dependencies of modules that depends on ``old`` are
- updated
-
-ORM
----
-
-.. `[source] `_
-.. method:: env(cr)
-
- Create a new environment from the cursor.
-
- .. warning::
- This function does NOT empty the cache maintained on the cursor for superuser with an empty
- environment. A call to `invalidate_cache` will most probably be necessary every time you
- directly modify something in database.
-
- :return: The new environment
- :rtype: :class:`~odoo.api.Environment`
-
-.. `[source] `_
-.. method:: recompute_fields(cr, model, fields, ids=None, logger=_logger, chunk_size=256, strategy="auto")
-
- Recompute field values. Possible strategies to process the recomputation:
-
- - ``flush``: Flush the recomputation when it's finished
- - ``commit``: Commit the recomputation when it's finished
- - ``auto``: The function chooses the best alternative based on the number of records to recompute
- and the fields traceability
-
- :param str model: model name of the field(s) to recompute
- :param list(str) fields: list of field names to recompute
- :param list(int) ids: list of record IDs to recompute
- :param logger: Logger used to print the progress of the function
- :type logger: :class:`logging.Logger`
- :param int chunk_size: size of the chunk used to split the records for better processing
- :param str strategy: strategy used to process the recomputation
-
-Records
--------
-
-.. `[source] `_
-.. method:: ref(cr, xmlid)
-
- Return the id corresponding to the given :term:`xml_id `.
-
- :param str xml_id: Record xml_id, under the format ````
- :return: Found record id, if any
- :rtype: int or `None`
-
-.. `[source] `_
-.. method:: remove_record(cr, name)
-
- Remove a record and its references corresponding to the given
- :term:`xml_id `.
-
- :param str name: record xml_id, under the format ````
-
-.. `[source] `_
-.. method:: rename_xmlid(cr, old, new, noupdate=None, on_collision="fail")
-
- Rename the :term:`external Identifier` of a record. Possible actions to take if the external
- Identifier already exists on the database:
-
- - ``fail``: raise ``MigrationError`` and prevent renaming
- - ``merge``: renames the external Identifier and removes the old one
-
- :param str old: current xml_id of the record, under the format ````
- :param str new: new xml_id of the record, under the format ````
- :param bool noupdate: value to set on the ir_model_data record ``noupdate`` field
- :param str on_collision: action to take if the xml_id already exists
-
-.. `[source] `_
-.. method:: ensure_xmlid_match_record(cr, xmlid, model, values)
-
- Match a record with an xmlid by creating or updating the external identifier.
-
- This function is useful when migrating in-database records into a custom module, to create the
- record's xmlid before the module is updated and avoid duplication.
-
- :param str xmlid: record xml_id, under the format ````
- :param str model: model name of the record
- :param dict values: Dictionary ``{"fieldname_1": "value_1", ...}`` mapping fields and values to
- search for the record to update. For example:
-
- .. code-block:: python
-
- values = {"id": 123}
- values = {"name": "INV/2024/0001", company_id: 1}
-
- :return: the :term:`xml_id ` of the record.
- :rtype: str
-
-.. `[source] `_
-.. method:: update_record_from_xml(cr, xmlid, reset_write_metadata=True, force_create=True, from_module=None, reset_translations=())
-
- Update a record based on its definition in the :doc:`/developer/reference/backend/data`.
-
- Useful to update ``noupdate`` records, in order to reset them for the upgraded version.
-
- :param str xmlid: record xml_id, under the format ````
- :param bool reset_write_metadata: whether the metadata before the record update is kept
- :param bool force_create: whether the record is created if it does not exist
- :param str from_module: name of the module from which to update the record. Useful when the
- record is rewritten in another module.
- :param set of str reset_translations: set of field names whose translations get reset
diff --git a/content/developer/reference/upgrades.rst b/content/developer/reference/upgrades.rst
new file mode 100644
index 0000000000..bda807dccb
--- /dev/null
+++ b/content/developer/reference/upgrades.rst
@@ -0,0 +1,11 @@
+:nosearch:
+
+========
+Upgrades
+========
+
+.. toctree::
+ :titlesonly:
+
+ upgrades/upgrade_scripts
+ upgrades/upgrade_utils
diff --git a/content/developer/reference/upgrade_scripts.rst b/content/developer/reference/upgrades/upgrade_scripts.rst
similarity index 92%
rename from content/developer/reference/upgrade_scripts.rst
rename to content/developer/reference/upgrades/upgrade_scripts.rst
index 3dc6c32512..fc3df4042f 100644
--- a/content/developer/reference/upgrade_scripts.rst
+++ b/content/developer/reference/upgrades/upgrade_scripts.rst
@@ -26,6 +26,11 @@ module (including Odoo's major version and the module's minor version) and `{pre
the file that needs to be executed. The file's name will determine the :ref:`phase
` and order in which it is executed for that module and version.
+.. note::
+ From Odoo 13 the top-level directory for the upgrade scripts can also be named `upgrades`. This
+ naming is preferred since it has the correct meaning: *migrate* can be confused with *moving out
+ of Odoo*. Thus :file:`$module/upgrades/$version/` is also valid.
+
.. note::
Upgrade scripts are only executed when the module is being updated. Therefore, the
module's minor version set in the `$version` directory needs to be higher than the module's
diff --git a/content/developer/reference/upgrades/upgrade_utils.rst b/content/developer/reference/upgrades/upgrade_utils.rst
new file mode 100644
index 0000000000..b133abae90
--- /dev/null
+++ b/content/developer/reference/upgrades/upgrade_utils.rst
@@ -0,0 +1,113 @@
+=============
+Upgrade utils
+=============
+
+`Upgrade utils `_ is a library that contains helper functions
+to facilitate the writing of upgrade scripts. This library, used by Odoo for the upgrade scripts of
+standard modules, provides reliability and helps speed up the upgrade process:
+
+- The helper functions help make sure the data is consistent in the database.
+- It takes care of indirect references of the updated records.
+- Allows calling functions and avoid writing code, saving time and reducing development risks.
+- Helpers allow to focus on what is important for the upgrade and not think of details.
+
+Installation
+============
+
+Clone the `Upgrade utils repository `_ locally and start
+``odoo`` with the ``src`` directory prepended to the ``--upgrade-path`` option.
+
+.. code-block:: console
+
+ $ ./odoo-bin --upgrade-path=/path/to/upgrade-util/src,/path/to/other/upgrade/script/directory [...]
+
+On platforms where you do not manage Odoo yourself, you can install this library via `pip`:
+
+.. code-block:: console
+
+ $ python3 -m pip install git+https://github.com/odoo/upgrade-util@master
+
+On `Odoo.sh `_ it is recommended to add it to the :file:`requirements.txt` of
+the custom repository. For this, add the following line inside the file::
+
+ odoo_upgrade @ git+https://github.com/odoo/upgrade-util@master
+
+Using upgrade utils
+===================
+
+Once installed, the following packages are available for the upgrade scripts:
+
+- :mod:`odoo.upgrade.util`: the helper itself.
+- :mod:`odoo.upgrade.testing`: base TestCase classes.
+
+To use it in upgrade scripts, simply import it:
+
+.. code-block:: python
+
+ from odoo.upgrade import util
+
+
+ def migrate(cr, version):
+ # Rest of the script
+
+Now, the helper functions are available to be called through ``util``.
+
+Util functions
+==============
+
+Upgrade utils provides many useful functions to ease the upgrade process. Here, we describe some
+of the most useful ones. Refer to the `util folder
+`_ for the comprehensive declaration of
+helper functions.
+
+.. note::
+
+ The :attr:`cr` parameter in util functions always refers to the database cursor. Pass the one
+ received as a parameter in :meth:`migrate`. Not all functions need this parameter.
+
+.. currentmodule:: odoo.upgrade.util
+
+Modules
+-------
+
+.. automodule:: odoo.upgrade.util.modules
+ :members:
+
+Models
+------
+
+.. automodule:: odoo.upgrade.util.models
+ :members:
+
+Fields
+------
+
+.. automodule:: odoo.upgrade.util.fields
+ :members:
+
+Records
+-------
+
+.. automodule:: odoo.upgrade.util.records
+ :members:
+
+ORM
+---
+
+.. automodule:: odoo.upgrade.util.orm
+ :members:
+
+.. automodule:: odoo.upgrade.util.domains
+ :members:
+
+SQL
+---
+
+.. automodule:: odoo.upgrade.util.pg
+ :members:
+
+Misc
+----
+
+.. automodule:: odoo.upgrade.util.misc
+ :members:
diff --git a/extensions/github_link/__init__.py b/extensions/github_link/__init__.py
index b77c627bb7..3993d538b8 100644
--- a/extensions/github_link/__init__.py
+++ b/extensions/github_link/__init__.py
@@ -24,6 +24,7 @@
import os.path
import werkzeug
+import contextlib
def setup(app):
@@ -36,6 +37,7 @@ def linkcode_resolve(domain, info):
# TODO: js?
if domain != 'py':
return None
+
if not (app.config.github_user and app.config.github_project):
return None
@@ -53,10 +55,8 @@ def linkcode_resolve(domain, info):
return None
# get original from decorated methods
- try:
- obj = getattr(obj, '_orig')
- except AttributeError:
- pass
+ with contextlib.suppress(AttributeError):
+ obj = obj._orig
try:
obj_source_path = inspect.getsourcefile(obj)
@@ -65,14 +65,21 @@ def linkcode_resolve(domain, info):
# obj doesn't have a module, or something
return None
- import odoo
# FIXME: make finding project root project-independent
- project_root = os.path.join(os.path.dirname(odoo.__file__), '..')
+ if module.startswith('odoo.upgrade.util'):
+ from odoo.upgrade import util
+ project = 'upgrade-util'
+ project_root = os.path.join(os.path.dirname(util.__file__), '../..')
+ else:
+ import odoo
+ project = 'odoo'
+ project_root = os.path.join(os.path.dirname(odoo.__file__), '..')
return make_github_link(
app,
- os.path.relpath(obj_source_path, project_root),
- line,
- odoo_repository=True)
+ project=project,
+ path=os.path.relpath(obj_source_path, project_root),
+ line=line,
+ )
app.config.linkcode_resolve = linkcode_resolve
return {
@@ -80,22 +87,12 @@ def linkcode_resolve(domain, info):
'parallel_write_safe': True
}
-def make_github_link(app, path, line=None, mode="blob", odoo_repository=False):
- config = app.config
-
- user = config.github_user
- project = config.github_project
- if odoo_repository:
- user = 'odoo'
- project = 'odoo'
-
- urlpath = "/{user}/{project}/{mode}/{branch}/{path}".format(
- user=user,
- project=project,
- branch=config.version or 'master',
- path=path,
- mode=mode,
- )
+def make_github_link(app, project, path, line=None, mode="blob"):
+ branch = app.config.version or 'master'
+ if project == 'upgrade-util':
+ branch = 'master'
+
+ urlpath = f"/{app.config.github_user}/{project}/{mode}/{branch}/{path}"
return werkzeug.urls.url_unparse((
'https',
'github.com',
@@ -116,4 +113,4 @@ def add_doc_link(app, pagename, templatename, context, doctree):
source_suffix = app.config.source_suffix
source_suffix = next(iter(source_suffix))
context['github_link'] = lambda mode='edit': make_github_link(
- app, f'content/{pagename}{source_suffix}', mode=mode)
+ app, project=app.config.github_project, path=f'content/{pagename}{source_suffix}', mode=mode)