Skip to content

Commit aaa1f0f

Browse files
aj-fuentesKangOl
andcommitted
[IMP] util: improve documentation
The docstrings are directly rendered in Odoo online documentation. closes #66 Signed-off-by: Christophe Simonis (chs) <[email protected]> Co-authored-by: Christophe Simonis <[email protected]>
1 parent fec56e3 commit aaa1f0f

File tree

8 files changed

+984
-130
lines changed

8 files changed

+984
-130
lines changed

src/util/domains.py

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@
4747

4848
_logger = logging.getLogger(__name__)
4949
DomainField = collections.namedtuple("DomainField", "table domain_column model_select")
50+
"""
51+
Domain field
52+
53+
:meta private: exclude from online docs
54+
"""
5055

5156

5257
class _Skip(Exception):
@@ -178,6 +183,7 @@ def _valid_path_to(cr, path, from_, to):
178183
def _replace_path(cr, old, new, src_model, dst_model, path_str):
179184
"""
180185
Replace `old` by `new` in the fields path `path_str` assuming the path starts from `src_model`.
186+
181187
The replace only takes place if `old` points at `dst_model`.
182188
"""
183189
dot_old = old.split(".")
@@ -284,20 +290,57 @@ def clean_term(term):
284290

285291
def adapt_domains(cr, model, old, new, adapter=None, skip_inherit=(), force_adapt=False):
286292
"""
287-
Replace {old} by {new} in all domains for model {model} using an adapter callback.
288-
289-
{adapter} is to adapt leafs. It is a function that takes three arguments and
290-
returns a domain that substitutes the original leaf:
291-
(leaf: Tuple[str,str,Any], in_or: bool, negated: bool) -> List[Union[str,Tuple[str,str,Any]]]
292-
293-
The parameter {in_or} signals that the leaf is part of an or ("|") domain, otherwise
294-
it is part of an and ("&") domain. The other parameter signals if the leaf is
295-
{negated} ("!").
296-
297-
Note that the {adapter} is called only on leafs that use the {old} field of {model}.
298-
299-
{force_adapt} will run the adapter on all leaves having the removed field in the path. Useful
300-
when deleting a field (in which case {new} is ignored).
293+
Replace `old` by `new` in all domains of `model` and all its inheriting models using an `adapter` callback.
294+
295+
`adapter` is a callback function to adapt leaves. Adapter functions must take three
296+
arguments and return a `domain <reference/orm/domains>`_ that substitutes the original
297+
leaf. The arguments are:
298+
299+
- `leaf`: a domain leaf which is a `tuple` of the form `(left, op, right)`
300+
- `in_or`: a boolean, when `True` it means the leaf is part of an OR (`"|"`) domain,
301+
otherwise it is part of an AND (`"&"`) domain
302+
- `negated`: a boolean, when `True` it means that the leaf is negated (`"!"`)
303+
304+
.. example::
305+
.. code-block:: python
306+
307+
def adapter(leaf, in_or, negated):
308+
left, op, right = leaf
309+
ok, ko = (1, 2) if not negated else (2, 1)
310+
if op == "="
311+
return [(left, "=", ok)]
312+
elif op == "!=":
313+
return [(left, "=", ko)]
314+
return [leaf]
315+
316+
`adapter` is called only on leafs that use the `old` field of `model` as **last** part
317+
of the `left` part of leaves, unless `force_adapt` is `True`. The domains returned by
318+
an adapter do not need to have the `old` field replaced by `new` in the `left` part of
319+
the input leaf. The replace will be done anyway to the whole domain returned by the
320+
adapter. The purpose of the `adapter` is to modify the operator and the `right` part
321+
of the input leaf.
322+
323+
.. example::
324+
When replacing `"field1"` by `"field2"`, the following happens:
325+
326+
- `("foo.bar.baz.field1", "=", 1)` gets adapted *only* if the record pointed to by
327+
`foo.bar.baz` is of the requested `model`.
328+
- `("foo.field1.baz", "=", 1)` is *not* adapted *even* if `foo` points to `model`,
329+
unless `force_adapt` is `True`, because `field1` is not the last part of `left`
330+
in this leaf.
331+
332+
.. note::
333+
This function will replace domains in all *standard* domain fields. Including
334+
filters, dashboards, and standard fields known to represent a domain.
335+
336+
:param str model: name of the model for which to adapt the domains
337+
:param str old: name of the field to be adapted
338+
:param str new: name of the field that should replace `old`
339+
:param function adapter: adapter for leaves
340+
:param list(str) skip_inherit: list of inheriting model names to don't adapt (skip)
341+
:param bool force_adapt: when `True, run the `adapter` on all leaves having `new` in
342+
`left` part of the leaf (path), useful when deleting a
343+
field (in which case `new` is ignored).
301344
"""
302345
_validate_model(model)
303346
target_model = model

src/util/fields.py

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
# -*- coding: utf-8 -*-
2+
"""
3+
Utility functions for modifying model fields.
4+
5+
Field operations are best done in `pre-` script of the involved modules. In some cases a
6+
preliminary operation could be done in pre and finished in post. A common example is to
7+
remove a field in pre- keeping its column, later used in post when the column is finally
8+
dropped.
9+
"""
10+
211
import base64
312
import json
413
import logging
@@ -73,10 +82,13 @@ def make_index_name(table_name, column_name):
7382
def ensure_m2o_func_field_data(cr, src_table, column, dst_table):
7483
"""
7584
Fix broken m2o relations.
85+
7686
If any `column` not present in `dst_table`, remove column from `src_table` in
7787
order to force recomputation of the function field
7888
7989
WARN: only call this method on m2o function/related fields!!
90+
91+
:meta private: exclude from online docs
8092
"""
8193
if not column_exists(cr, src_table, column):
8294
return
@@ -92,6 +104,20 @@ def ensure_m2o_func_field_data(cr, src_table, column, dst_table):
92104

93105

94106
def remove_field(cr, model, fieldname, cascade=False, drop_column=True, skip_inherit=()):
107+
"""
108+
Remove a field and its references from the database.
109+
110+
This function also removes the field from inheriting models, unless exceptions are
111+
specified in `skip_inherit`. When the field is stored we can choose to not drop the
112+
column.
113+
114+
:param str model: model name of the field to remove
115+
:param str fieldname: name of the field to remove
116+
:param bool cascade: whether the field column(s) are removed in `CASCADE` mode
117+
:param bool drop_column: whether the field's column is dropped
118+
:param list(str) or str skip_inherit: list of inheriting models to skip the removal
119+
of the field, use `"*"` to skip all
120+
"""
95121
_validate_model(model)
96122

97123
ENVIRON["__renamed_fields"][model][fieldname] = None
@@ -339,11 +365,15 @@ def adapter(leaf, is_or, negated):
339365

340366
def remove_field_metadata(cr, model, fieldname, skip_inherit=()):
341367
"""
368+
Remove metadata of a field.
369+
342370
Due to a bug of the ORM [1], mixins doesn't create/register xmlids for fields created in children models
343371
Thus, when a field is no more defined in a child model, their xmlids should be removed explicitly to
344372
avoid the fields to be considered as missing and being removed at the end of the upgrade.
345373
346374
[1] https://github.com/odoo/odoo/issues/49354
375+
376+
:meta private: exclude from online docs
347377
"""
348378
_validate_model(model)
349379

@@ -360,6 +390,20 @@ def remove_field_metadata(cr, model, fieldname, skip_inherit=()):
360390

361391

362392
def move_field_to_module(cr, model, fieldname, old_module, new_module, skip_inherit=()):
393+
"""
394+
Move a field from one module to another.
395+
396+
This functions updates all references to a specific field, switching from the source
397+
module to the destination module. It avoid data removal after the registry is fully
398+
loaded. The field in inheriting models are also moved unless skipped.
399+
400+
:param str model: name of the owner model of the field to move
401+
:param str fieldname: name of the field to move
402+
:param str old_module: source module name from which the field is moved
403+
:param str new_module: target module name into which the field is moved
404+
:param list(str) or str skip_inherit: list of inheriting models for which the field is
405+
not to be moved, use `"*"` to skip all
406+
"""
363407
_validate_model(model)
364408
name = IMD_FIELD_PATTERN % (model.replace(".", "_"), fieldname)
365409
try:
@@ -385,6 +429,25 @@ def move_field_to_module(cr, model, fieldname, old_module, new_module, skip_inhe
385429

386430

387431
def rename_field(cr, model, old, new, update_references=True, domain_adapter=None, skip_inherit=()):
432+
"""
433+
Rename a field and its references from `old` to `new` on the given `model` and all inheriting models, unless exceptions are specified in `skip_inherit`.
434+
435+
This functions also updates references, indirect or direct ones, including filters,
436+
server actions, related fields, emails, dashboards, domains, and many more. See
437+
:func:`update_field_usage`
438+
439+
For the update of domains a special adapter function can be used. The default adapter
440+
just replaces `old` by `new` in each domain leaf. Refer to :func:`adapt_domains` for
441+
information about domain adapters.
442+
443+
:param str model: model name of the field to rename
444+
:param str old: current name of the field to rename
445+
:param str new: new name of the field to rename
446+
:param bool update_references: whether to update all references
447+
:param function domain_adapter: adapter to use for domains, see :func:`adapt_domains`
448+
:param list(str) or str skip_inherit: models to skip when renaming the field in
449+
inheriting models, use `"*"` to skip all
450+
"""
388451
_validate_model(model)
389452

390453
rf = ENVIRON["__renamed_fields"][model]
@@ -565,10 +628,16 @@ def convert_field_to_property(
565628
cr, model, field, type, target_model=None, default_value=None, default_value_ref=None, company_field="company_id"
566629
):
567630
"""
568-
Notes:
631+
Convert a field to a property field.
632+
633+
Notes
634+
-----
569635
`target_model` is only use when `type` is "many2one".
570636
The `company_field` can be an sql expression.
571637
You may use `t` to refer the model's table.
638+
639+
:meta private: exclude from online docs
640+
572641
"""
573642
_validate_model(model)
574643
if target_model:
@@ -763,6 +832,19 @@ def convert_field_to_untranslatable(cr, model, field, type="varchar"):
763832

764833

765834
def change_field_selection_values(cr, model, field, mapping, skip_inherit=()):
835+
"""
836+
Replace references of values of a selection field.
837+
838+
This function replaces all references to selection values according to a mapping.
839+
Domains are also updated.
840+
841+
:param str model: model name of the selection field to update
842+
:param str field: name of the selection field to update
843+
:param dict mapping: selection values to update, key values are replaced by
844+
their corresponding values in the mapping
845+
:param list(str) or str skip_inherit: list of inheriting models to skip in the update
846+
of the selection values, use `"*"` to skip all
847+
"""
766848
_validate_model(model)
767849
if not mapping:
768850
return
@@ -837,7 +919,9 @@ def register_unanonymization_query(cr, model, field, query, query_type="sql", se
837919

838920
def update_field_usage(cr, model, old, new, domain_adapter=None, skip_inherit=()):
839921
"""
840-
Replace all references to field `old` to `new` in:
922+
Replace all references to the field `old` by `new` in different places.
923+
924+
Search in:
841925
- ir_filters
842926
- ir_exports_line
843927
- ir_act_server
@@ -846,6 +930,17 @@ def update_field_usage(cr, model, old, new, domain_adapter=None, skip_inherit=()
846930
- domains (using `domain_adapter`)
847931
- related fields
848932
933+
This function can be used to replace the usage of a field by another. Domains are
934+
updated using the `domain_adapter`. By default the domain adapter just replaces `old`
935+
by `new` in domain leaves. See :func:`adapt_domains` for more information about domain
936+
adapters.
937+
938+
:param str model: model name of the field
939+
:param str old: source name of the field to replace
940+
:param str new: target name of the field to set
941+
:param function domain_adapter: adapter to use for domains, see :func:`adapt_domains`
942+
:param list(str) or str skip_inherit: models to skip when renaming the field in
943+
inheriting models, use `"*"` to skip all
849944
"""
850945
return _update_field_usage_multi(cr, [model], old, new, domain_adapter=domain_adapter, skip_inherit=skip_inherit)
851946

@@ -1140,6 +1235,8 @@ def adapt_related(cr, model, old, new, skip_inherit=()):
11401235

11411236
def update_server_actions_fields(cr, src_model, dst_model=None, fields_mapping=None):
11421237
"""
1238+
Update server action fields.
1239+
11431240
When some fields of `src_model` have ben copied to `dst_model` and/or have
11441241
been copied to fields with another name, some references have to be moved.
11451242
@@ -1149,6 +1246,8 @@ def update_server_actions_fields(cr, src_model, dst_model=None, fields_mapping=N
11491246
is given, the `src_model` is used as `dst_model`.
11501247
Then, if `dst_model` is set, `ir_act_server` referred by modified `ir_server_object_lines`
11511248
are also updated. A chatter message informs the customer about this modification.
1249+
1250+
:meta private: exclude from online docs
11521251
"""
11531252
if dst_model is None and fields_mapping is None:
11541253
raise SleepyDeveloperError(

0 commit comments

Comments
 (0)