From 12fee97003b493881bb11fdbb794d2f18e37d1eb Mon Sep 17 00:00:00 2001 From: Alvaro Fuentes Date: Mon, 15 Apr 2024 11:30:21 +0200 Subject: [PATCH 1/2] [IMP] upgrade-util: link code documentation Add direct code documentation from upgrade-util repo. Adapt `extensions/github_link`. Co-authored-by: Victor Feyens --- README.md | 6 ++-- conf.py | 21 +++++++++++++ extensions/github_link/__init__.py | 49 ++++++++++++++---------------- 3 files changed, 48 insertions(+), 28 deletions(-) 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/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) From d33b74dd98bbe59692b7fc64c0713f31d8d19261 Mon Sep 17 00:00:00 2001 From: Alvaro Fuentes Date: Mon, 15 Apr 2024 11:32:58 +0200 Subject: [PATCH 2/2] [IMP] doc: improve organization of upgrades docs * Add autodoc directives to generate documentation directly from upgrade-util repo. * Group all upgrades-related reference documentation into one group in the sidebar, instead of having two entries. * Mention `upgrades` vs `migrations` directory. It has been supported since a while but nothing was explicit in the documentation. --- .../developer/howtos/upgrade_custom_db.rst | 10 +- content/developer/reference.rst | 3 +- content/developer/reference/upgrade_utils.rst | 279 ------------------ content/developer/reference/upgrades.rst | 11 + .../{ => upgrades}/upgrade_scripts.rst | 5 + .../reference/upgrades/upgrade_utils.rst | 113 +++++++ 6 files changed, 135 insertions(+), 286 deletions(-) delete mode 100644 content/developer/reference/upgrade_utils.rst create mode 100644 content/developer/reference/upgrades.rst rename content/developer/reference/{ => upgrades}/upgrade_scripts.rst (92%) create mode 100644 content/developer/reference/upgrades/upgrade_utils.rst 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: