Commit Graph
294 Commits
Author SHA1 Message Date
Xavier Morel c7826675a8 [FIX] base: restore deletion of dependencies on field removal
odoo/odoo#111651 improved and optimised triggers but dropped the
in-place cleanup of field dependencies. As a consequence, during
module uninstallation if a stored computed field is removed (because
it's part of a module being uninstalled), and one of its dependencies
is subsequently altered (e.g. it's itself removed, or written to) the
second update will break as the query trying to find out which
dependent records to update will error, either because of trying to
select / filter on a missing column, or because of trying to fetch
in a missing table.

The simplest examples of this issue are computed fields with a
dependency on `ir.model`:

- In `calendar`, `calendar.event.res_model` is a related on
  `res_model_id.model`, this prevents the removal of *any* `ir.model`
  record if it gets uninstalled.

  As a result the `calendar.attendee` and `calendar.event` tables
  don't get removed (just emptied of all their non-automatic fields),
  their records remain as well, and when the non-automatic fields get
  re-added during installation re-instating the NOT NULL constraints
  fails, breaking the uninstall/reinstall test.

- In `payment`, `payment.provider.module_state` is a related on
  `module_id.state`, this breaks *during* uninstallation, as after
  `module_uninstall` first calls `_module_data_uninstall` which
  removes the field, then it *updates the modules being uninstalled*
  (sets their state), which tries to find out which
  `payment.provider`'s `module_state` is should update, which breaks
  because the `module_id` column has been removed.

  This second one was worked around in odoo/odoo#118900, by marking
  modules as uninstalled before actually gutting them, but as it turns
  out the "actual" fix is needed anyway. So revert the workaround, and
  actually fix the issue.

closes odoo/odoo#119130

X-original-commit: 48a420efcf7c7b46416bab006003553cc9d23846
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
2023-04-20 09:33:48 +02:00
Christophe Simonis 924487a72d [FIX] core: correctly handle major-less upgrade scripts during major version change
closes odoo/odoo#117948

X-original-commit: c38b5baaeac28a7952601878a5b5efadf7f52984
Signed-off-by: Christophe Simonis <chs@odoo.com>
2023-04-06 17:21:00 +02:00
Rémy Voet (ryv) 45115cb9c2 [IMP] core: add a representation of a TriggerTree
The TriggerTree class does not have a specific __repr__().  It thus
falls back on dict's __repr__(), which does not show the root of the
tree.  This makes debugging hard and confusing.

closes odoo/odoo#113521

Signed-off-by: Raphael Collet <rco@odoo.com>
2023-03-08 22:29:51 +01:00
Xavier-Do e9b170da38 [IMP] tests: refactor unittest classes
Odoo Test environments requires to modify many parts of the unittest
TestCase, Suite and Result.

The main initial reason is to **avoid to postpone result at the end of
the test suite**, because even if it is convenient to have all errors
visible after the tests in some case, odoo logs adds information during
the execution that can be useful to debug when a test fail, to have
context for an error. (see **OdooTestResult**)

We are also fixing the stack trace comming from a unittest and since
there is no proper way to hook inside the TestPartExecutor, a dirty hack
injects anoter result on the outcome to manage the error and complete
the stack trace. This was also a way to avoid to postpone subtest logs
at the end of the test case (see _ErrorCatcher)

`_feedErrorsToResult` was used to test the test suite behavior since
there are many customization and this is quite fragile, especially if
unittest changes behavior in other python version.

**Python 3.11** introduced python/cpython#664448d8 That, in a way, goes
in the same direction of the changed introduced with _ErrorCatcher:
immediately feed errors to resut instead of postponing it. But this also
removes `_feedErrorsToResult` that was used to test this behaviors, as
well as other ones.

Since odoo should remain multi-version, this amount of changes on the
initial behavior become to complicate to keep cross-version and the
(already in our mind for a while) solution to **vendor unittest** will
help to simplify most of our test code base.

This commit modified the vendored unittest files to simplify them as
much as possible to suite our needs.

Since the runner is still the unittest one, we need to inherit from
unittest.Testcase in order to have the right type.

This also means that we still have access to all TestCase methods
without overriding them all. This is convenient for assertion methods as
an example but the initial idea is to vendor our own version of TestCase
to avoid having trouble to adapte our miscommunications to future python
versions. A trade-off must be done to chose what should remain in our
code base. The idea is to keep logic closely linked to our changes in
our code base, mainly around the run method, but also addClassCleanup
wich need to be vendored for python 3.7, but assertions methods are
independent. Any logic can be moved fom unittest to our
vendored version in the future if needed.

X-original-commit: 9a5d1ea54be49e4cc8208c33e76a6bbd2414d5d0
Part-of: odoo/odoo#113850
2023-02-28 23:49:33 +01:00
Chong Wang (cwg)andRaphael Collet 7ded1a7acc [FIX] core: avoid losing translations during module upgrade
Consider field F in module X with parameter translate=False, and F is
overridden in module Y with parameter translate=True.  During the
upgrade of module X, module Y hasn't been loaded yet, and the ORM
considers the field to be `translate=False`.  Therefore it converts its
database column from type jsonb to varchar, and accidentally drops
non-en_US values:

    {"en_US": "English value", "fr_FR": "French value"} (jsonb)
        -> 'English value' (varchar)

As a result, translations are lost after upgrade.

This commit fixes the bug by checking whether the field is translated in
database and patches the field accordingly when loading the registry.
This avoids the ORM considering the field as non-translated while
upgrading modules.

In order to "force" translated fields to become non-translated ones, at
the end of the loading process the patch above is discarded, and fields
are checked again.  We then adapt the schema of models that have such
fields.  This extra step handles the uninstallation of modules like
module Y in the example above.

The patching of the fields has one potential issue.  While upgrading
module X, field F is patched with translate=True.  If module Y actually
overrides F with translate=xml_translate or so, this may cause the
behavior of the upgrade to be slightly incorrect.  Because of the
complexity, we have chosen to not support this case.

closes odoo/odoo#112223

X-original-commit: 1e6e482a9763baa5fae70d9b6676d16a46458f4a
Signed-off-by: Raphael Collet <rco@odoo.com>
Signed-off-by: Wang Chong (cwg) <cwg@odoo.com>
Co-authored-by: Raphael Collet <rco@odoo.com>
2023-02-08 16:50:03 +01:00
Raphael Collet 206525658b [IMP] core: add a class for trigger trees
The class is a simple extension of dict, and adds an explicit attribute
for the content of the root node of a tree.  It makes the code much more
readable with very small performance overhead.

closes odoo/odoo#111946

X-original-commit: 8a01d74e5f7d035cfd05bc02596f075270e0fcf8
Signed-off-by: Raphael Collet <rco@odoo.com>
2023-02-04 22:39:45 +01:00
Raphael Collet 65261cd7f0 [FIX] core: make trigger trees faster
This patch optimizes the way field trigger trees are computed.  Overall,
the resulting trigger trees are mostly identical, but they can now be
determined one by one, which enables an on-demand approach and partial
cache.

Before this patch, getting the first trigger tree proceeded as follows:
 - resolve the dependencies of all fields;
 - compute the transitive closure of the dependencies of all fields;
 - store the transitive closure above as field triggers for all fields
   in a cache.

After this patch, getting the first trigger tree proceeded as follows:
 - resolve the dependencies of all fields;
 - cache them as direct triggers for all fields;
 - compute one trigger tree as the transitive closure of the field's
   triggers, and cache it.

This optimization is quite effective during the installation of modules,
and is even more effective when the number of fields is large.  For
instance, a complete installation with all community modules is now 25%
faster.  For a complete installation with all enterprise modules, the
installation time is even 30% less!  A medium installation is about 16%
less time.

The optimization also speeds up the first request on a new Odoo worker,
since the minimum time for computing a handful of trigger trees is much
smaller than before.  We have measured times for a first request going
from 1.6 seconds to 1 second for posting a message.

We have observed slight differences in trigger trees, but they occur in
places where the tree has redundant branches, in particular with fields
having recursive dependencies.  It therefore makes no difference in what
is being triggered or invalidated.

X-original-commit: 68f786d494c3c73a085cd919b348c019f77794e7
Part-of: odoo/odoo#111946
2023-02-04 22:39:45 +01:00
Raphael Collet 161e5fad3b [REF] core: make APIs on registry for computation triggers
Those APIs are aimed at hiding the implementation of trigger trees,
dependent fields and fields modifying relations.  Explicit APIs simplify
the profiling of executions and comparison of implementations for
building trigger trees.

X-original-commit: d12b9270375634e738f5288d0c523ac0eec2fa18
Part-of: odoo/odoo#111946
2023-02-04 22:39:45 +01:00
Xavier Morel 6e700157d0 [REM] core: odoo.modules.module.loaded flag
Seems unnecessary, most of the information already lives in
`sys.modules`. We can just check that.

There are a few changes in behaviour, but they seem minor:

- if post_load fails, subsequent attempts to load the module will
  "succeed"
- since we didn't remove/reload the module, a failure because of an
  incorrect post_load wasn't fixable, however it was possible to
  update the manifest

Still seems like a wonky state to be in, and one we should ignore.

Also remove the logging of the error: since we're re-raising as-is,
the parent logs it with a traceback, so this is unnecessary and
redundant.

closes odoo/odoo#103933

Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
2023-02-03 05:08:40 +01:00
Denis Ledoux b4a7996e96 [IMP] base, *: change the API of init hooks to pass env
This is mostly a cleaning/refactoring change.

The current API for init hooks (pre, post, uninstall) is to pass
`cr, registry`.
But the first thing which was done by most
post init and uninstall hooks was to create an env using
the cr passed
e.g.
`env = api.Environment(cr, SUPERUSER_ID, {})`
and the `registry` argument was unused in all these hooks,
completely.

By changing the API of hooks to pass `env` instead
of `cr, registry`, we gain in average two lines in every
hooks:
- the line creating the env `env = api.Environment(cr, SUPERUSER_ID, {})`
- the line importing `api` and `SUPERUSER_ID`

Therefore removing ~250 lines of repeated code lines accross odoo/odoo and
odoo/enterprise.
In addition to these lines removed,
it also ease the API of init hooks for Odoo developers,
who are used to that `env` and not so much how to create an `env`
from a cursor.

Part-of: odoo/odoo#108254
2023-02-01 10:25:01 +01:00
Denis Ledoux 5bf1207c8c [IMP] base, *: re-use env during registry loading
The goal of this revision is to re-use the environment among the
different steps of the registry loading,
instead of creating a new environment for each step.

1. Simply To avoid to repeat the line
   `env = api.Environment(cr, SUPERUSER_ID, {})`
   multiple times in the code
2. This also allows to share the context among the different
   steps. This is not yet used in this revision, but it could
   be, for instance to avoid the current repetition to add the keys
   `install_module`, in `convert_csv_import` and `xml_import._tag_record`

Part-of: odoo/odoo#108254
2023-02-01 10:25:01 +01:00
Christophe Simonis 04487da7c5 [FIX] core: merge scripts found in --upgrade-path
Don't limit on the first directory found in the upgrade-path.

It follow the same behavior regarding scripts found in the `maintenance`
directory and the ones in the local `upgrades` directory of modules.

opw-2868713

closes odoo/odoo#111087

X-original-commit: d2e6c9d5010ab8092eff37775e92b486f89d28fc
Signed-off-by: Christophe Simonis <chs@odoo.com>
2023-01-26 19:55:55 +01:00
Victor Feyens 13ccd9cee4 [IMP] test_lint: detect useless manifest content
Keep the manifests as light as possible, to easily see custom behavior/content.
Complete the work of previous commits cleaning the manifests content:

* 42bad1a6d2
* ef7005f524

and make sure this kind of cleanup commit is not necessary in the future
because it is now automatically verified by a dedicated test.

closes odoo/odoo#107735

Related: odoo/enterprise#34903
Signed-off-by: Julien Castiaux <juc@odoo.com>
2022-12-16 16:17:41 +01:00
Raphael Collet f0ca3f32d2 [FIX] core: ignore imported modules when loading registry
The existing code was generating misleading errors for imported Odoo
modules that could not be loaded.  Although there was a specific hack
for module 'studio_customization', imported modules were not handled
properly.  This patch adds the right condition in the SQL query in the
module that introduces imported modules.

closes odoo/odoo#106098

X-original-commit: e1cfc1f74000e55473f7a26f0df5a13c4d5094c0
Signed-off-by: Vincent Schippefilt (vsc) <vsc@odoo.com>
Signed-off-by: Raphael Collet <rco@odoo.com>
2022-11-21 21:18:53 +01:00
Rémy Voet (ryv) 0787f150b1 [FIX] core: make index naming without conflicts
There are two issues with the index naming convention used by the ORM:

Problem 1: it is possible to have naming conflict for indexes.  For
instance, the name 'slide_channel_tag_group_sequence_index' is used for
both fields slide.channel.tag.group.sequence and
slide.channel.tag.group_sequence.  Only the first index will be created.

Solution 1: we separate the model and field names with a double
underscore instead of a single one, which is the same strategy as with
LEFT JOIN aliases.  This is correct because model names don't contain
such double underscores or underscores as prefix or suffix (it is not
forbiden but model name should follow the 'dot notation'.)

Problem 2: index names can be longer than 63 chars, but PostgreSQL
silently truncates it.  This doesn't actually break anything (PostgreSQL
also truncates values when we check the existence of indexes) but it can
lead to using the same name twice.  There is hopefully not any example
in our code.

Solution 2: if the name is too large, we truncate it and pad it with a
hash of the complete name to match 63 characters, which is also the
strategy used for LEFT JOIN aliases.

task-2984730

closes odoo/odoo#100736

Related: odoo/upgrade#3957
Signed-off-by: Raphael Collet <rco@odoo.com>
2022-11-07 15:57:28 +01:00
Hoang Tran 5c907fe1e3 [IMP] core: make sure addon dir exist before loading
Loading an non-existing addon directory affect all other modules to be
not loaded. This commit makes sure the path exist before proceed to
explore all the modules under that directory.

closes odoo/odoo#104704

X-original-commit: d77d9f8a9ff945f5f61924eda835c877eb4f281c
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
2022-11-02 12:37:21 +01:00
xmo-odoo 110770b7c1 [REM] core: openerp.addons alias and legacy ad_path
Part-of: odoo/odoo#98138
2022-10-26 19:03:47 +02:00
Xavier Morel e2b3463b5a [IMP] core: formally deprecate __openerp__.py manifests.
`__manifest__.py` was introduced in Odoo 10 and quickly migrated
to (c758e9043a fixed the last holdouts).

Deprecate old manifests. People who need the compatibility can just
add a symlink (or duplicate the file if they're working on FAT or an
old os where core.symlinks can't be set to `true`).

closes odoo/odoo#103952

Signed-off-by: Raphael Collet <rco@odoo.com>
2022-10-25 17:16:09 +02:00
Laurent Desausoi 7593c073d2 [IMP] core: use inert SQL based neutralization
Before this commit the neutralize system introduced in v16 was using ORM
methods in order to change appropriate records. Although flexible, this approach
could lead to call some methods with side effects while neutralizing
(eg: overloads of write).

This patch converts the neutralize system to a safer "inert" SQL based approach
by migrating the generic method _neutralize to SQL files exposed in the
data folder.

Task id: 2961687

closes odoo/odoo#102792

X-original-commit: e5dbded9bb363351feff7ca8a56c7f8a6860f492
Related: odoo/enterprise#32580
Signed-off-by: Fabien Meghazi <fme@odoo.com>
2022-10-09 22:04:00 +02:00
Tom De CaluwéandRaphael Collet 3a4a7b161b [FIX] core: recompute fields triggered by indirectly modified relational fields
The cache currectly fails to correctly invalidate relational fields that depend
on a non-relational field. Two passes of invalidation are done, to reflect
dependencies on both the old and the new written values. In the first pass
only relational fields are considered, as explained in the comments:

> It is best explained with a simple example: consider two sales orders SO1 and
SO2. The computed total amount on sales orders indirectly depends on the
many2one field 'order_id' linking lines to their sales order.  Now consider the
following code:
>
> line = so1.line_ids[0]      # pick a line from SO1
> line.order_id = so2         # move the line to SO2
>
> In this situation, the total amount must be recomputed on *both* sales order:
the line's order before the modification, and the line's order after the
modification.

The written values can be seen as the roots of a dependency forest (a
collection of dependency trees). Before this commit all non-relational roots
and their corresponding trees were filtered out during the first pass. However,
this approach is wrong, as relational fields can also depend on non-relational
fields. Instead, the complete dependency forest has to be traversed, skipping
invalidation for non-relational fields during the first pass.

The test that was previously included accidentally succeeded because of a
separate and unrelated bug in the orm domain parser: in certain one2many or
many2many leafs the domain parser would not take into consideration the domain
included in the definition of the field. As a result, the test still passed
by accident, because the records that no longer matched the domain after the
write were still invalidated during the second pass.

The problem can clearly be demonstrated, however, when the dependency is
generated by a compute function.

closes odoo/odoo#101038

X-original-commit: d4a5827b42d80f0f830455dcd2056701eb09aed1
Signed-off-by: Rémy Voet <ryv@odoo.com>
Signed-off-by: Raphael Collet <rco@odoo.com>
Co-authored-by: Raphael Collet <rco@odoo.com>
2022-09-24 19:12:26 +02:00
Raphael Collet 0bec85dcab [FIX] core: remove confused log message about existing index
When a module extends model 'base', the database schemas of all models are
checked, including indexes.  And a log message appears for "unexpected index
mail_message_subtype_id_index on table mail_message_subtype".  The index indeed
exists, but not for the table mentioned in the message.  The ORM actually makes
a confusion between:
 - the index mail_message_subtype_id_index for subtype_id on table mail_message
 - the index mail_message_subtype_id_index for id on table mail_message_subtype

The fix consists in logging the message about the unexpected index only if the
index is on the expected table.

closes odoo/odoo#100297

X-original-commit: fe8d0024897208e876f097564d50e6795df2c1d3
Signed-off-by: Raphael Collet <rco@odoo.com>
2022-09-19 10:29:56 +02:00
ef00294e71 [IMP] core: store translated fields as JSONB columns
Translated fields no longer use the model ir.translation.  Instead they store
all their values as JSON, and store them into JSONB columns in the model's
table.  The field's column value is either NULL or a JSON dict mapping language
codes to text (the field's value in the corresponding language), and must
contain an entry for key 'en_US' (as it is used as a fallback for all other
languages).  Empty text is allowed in translation values, but not NULL.

Here are examples for a field with translate=True:

    NULL
    {"en_US": "Foo"}
    {"en_US": "Foo", "fr_FR": "Bar", "nl_NL": "Baz"}
    {"en_US": "Foo", "fr_FR": "", "nl_NL": "Baz"}

Like before, writing False to the field makes it NULL, i.e., False in all
languages.  However, writing "" to the field makes its value empty in the
current language, but does not discard the values in the other languages.

Here are examples for a field with translate=xml_translate:

    NULL
    {"en_US": "<div>Foo<p>Bar</p></div>", "fr_FR": "<div>Fou<p>Barre</p></div>"}

Change for callable(translate) fields: one can now write any value in any
language on such a field.  The new value will be adapted in all languages, based
on the mapping of terms between languages in the old values.  Basically the
structure of the value must remain the same in all languages, like before.

Reading a translated field is now both simpler and faster than the former
implementation.  We fetch the value of the field in the current language by
coalescing its value with the 'en_US' value of the field:

    SELECT id, COALESCE(name->>'fr_FR', name->>'en_US') AS name ...

The raw cache of the field contains either None or a dict which is conceptually
a subset of the JSON value in database (except for missing languages).  For the
sake of simplicity, most cache operations deal with the dict and return the text
value in the current language.

Trigram indexes have been adapted to the new storing strategy, and should enable
to search in any language.  Before this change, only the source value of the
field ('en_US') could be indexed.

Computed stored translated fields are not supported by the framework, because of
the complexity of the computation itself: the field would need to be computed in
all active languages.  We chose to not provide any hook to compute a field in
all languages at once, and the framework always invokes a compute method once to
recompute it.

Code translations are no longer stored into the database.  They become static,
and are extracted from the PO files when needed.  The worker simply uses a cache
with extracted code translations for performance.  This is reasonable, since
fr_FR code translations for all modules takes around 2MB of memory, and the
cache can be shared among all registries in the worker.  Changing code
translations requires to update the corresponding PO file and reloading the
worker(s).

Performance summary:
 (+) reading 'model' translated fields is faster
 (+) reading 'model_terms' translated fields is much faster (no need to inject
     translations into the source value)
 (+) searching translated fields with operator 'ilike' is much faster when the
     field is indexed with 'trigram'
 (+) updating translated fields requires less ORM flushing
 (-) importing translations from PO files is 2x slower

Some extra fixes:
 - make field 'name' of ir.actions.actions translated; because of the PG
   inheritance, this is necessary to make the column definition consistent in
   all models that inherit from ir.actions.actions.
 - add some backend API for the web/website client for editing translations
 - move methods get_field_string() to model ir.model.fields
 - move _load_module_terms to model ir.module.module
 - adapt tests in test_impex, test_new_api
 - because env.lang is injected into SQL queries, its returned value is
   now guaranteed to correspond to a valid active language or None
 - remove wizard to insert missing translations (no longer makes sense)

task-id: 2081307

Co-authored-by: Fabien Pinckaers <fp@openerp.com>
Co-authored-by: Raphael Collet <rco@odoo.com>
2022-09-15 22:37:50 +02:00
Xavier-Do b58967d8d1 [IMP] loading: pregenerate assets bundles after install
During tests on runbot, the main reason tours are slow to start is
because the first loading of "/web" need to generate assets bundles.
Generation can take up to 5 seconds time the number of tour.

Before this, the first requests to /web takes around 7 seconds on
runbot and the next ones less than 1 second.

After this commit, the first request to /web takes around 1.5 seconds

Note that the main difficulty is to choose when to generate the assets.
(With optimisations from following commits) the generation time is
arround 30 seconds (21 css + 12 js) the first time, for all modules.
If the attachements exists the generation time is arround 3 seconds
(2.5 js + 0.5 css) mainly because of globs to find usefull files.

In practice for runbot the ideal would be to generate them at
the end of the install so that it is shared for all post_install builds.

Doint it at the end of an install is not wanted in all cases, saas
pregenerated templates and upgrade may avoid doing that.

Doing it in a special runbot step (subcommand) is not possible for niglty
execution (no split, in one go). This needs to be in the code.
It is also not practical for devs wanting to have the same behaviour on
a local machine.

A solution to make the test conditionnal at install is to base the
condion on an existing test_module. test_assetsbundle is a good
candidate here. On runbot, the at_install step (befor split) will
automatically generate assets with this solution.

Assets are also generated before post_install tests. This should be fast
if they already exists and ensure that assets are up to date after
modifying sources locally or after downloading a database on runbot.
It should be fast enough for small database and may be even faster
in the future for small diffs.

Part-of: odoo/odoo#99176
2022-09-12 13:48:59 +02:00
Rémy Voet (ryv) 4087bcdc5e [IMP] core: add unaccent to trigram indexes
We added trigram index for char fields since https://github.com/odoo/odoo/pull/83015.
But if `unaccent` is installed in the database (and isn't force to
`False` on field), these new trigram indexes are pointless and cost a
lot for nothing (almost nothing, it still can be used for equality
operator but in this case a btree will be far more efficient).

The simple way to fix it is to add `unaccent(<column>)` in the index
trigram definition, but unfortunately `unaccent` is not immutable and
may therefore not be indexed.  In order to make `unaccent` indexable, we
must declare it as immutable (see
https://stackoverflow.com/questions/11005036/does-postgresql-support-accent-insensitive-collations/11007216#11007216
for more information and how to do that).

With this patch, trigram indexes are created with `unaccent(<column>)`
if the function `unaccent` is available in the database, and for the
fields that are not declared with `unaccent=False`.  Moreover, we issue
a warning when `unaccent` is available but is not immutable, in which
case most trigram indexes will be useless.

odoo/upgrade#3736
task-2551518

closes odoo/odoo#95943

Signed-off-by: Rémy Voet <ryv@odoo.com>
2022-09-05 18:34:53 +02:00
Xavier Morel 9c0fa1efe3 [CHG] core: deprecate get_module_filetree
It's pretty much unused and fairly complicated.

Also deprecate `listdir` entirely since `get_module_filetree` is the
only extant user of the recursive listdir.

closes odoo/odoo#98034

Related: odoo/enterprise#30403
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
2022-08-23 07:36:24 +02:00
Xavier Morel 719e7d46e4 [CHG] core: mark a bunch of utilities as deprecated
Remove UnquoteEvalContext directly because it's unused and super specialised.

Part-of: odoo/odoo#98023
2022-08-22 16:48:27 +02:00
Raphael Collet 9c3b9a4926 [FIX] core: automatically flush upon invalidation for cache consistency
Because method _read() no longer updates existing values in memory,
those values in memory must be consistent with the database.

On the other hand, if pending updates are not performed on the database
before fetching values, it means that the corresponding database values
cannot be put in cache.  This implies that one cannot empty the cache
without flushing the corresponding fields.

In order to avoid mistakes, flush automatically before invalidating the
cache.  This makes the invalidation methods safe by default, and avoids
cargo-culting which would systematically associate invalidation to
flushing, which may eventually be less performant.

Part-of: odoo/odoo#66938
2022-07-05 11:35:00 +02:00
Raphael Collet 32bc28aa66 [IMP] core: better API for flush() and invalidate()
This provides a new API for those operations, in order to make the
distinction between the use cases more explicit.  The former API was
using obscure parameter combinations to correspond to various cases.

In the summary below, `fnames` is an iterable of field names.  If the
parameter is not given, it means "all fields" in the given context.
Note that method recompute() is now mostly private, as it should not be
used in business code.

    # process pending computations and updates
    records.env.flush_all()                # all fields of all models
    records.flush_model(fnames)            # the fields of all records of the model
    records.flush_recordset(fnames)        # the fields of the given records

    # process pending computations, became non-public methods
    records.env._recompute_all()           # all fields of all models
    records._recompute_model(fnames)       # the fields of all records of the model
    records._recompute_recordset(fnames)   # the fields of the given records

    # invalidate the cache of fields
    records.env.invalidate_all()           # all fields of all models
    records.invalidate_model(fnames)       # the fields of all records of the model
    records.invalidate_recordset(fnames)   # the fields of the given records

Part-of: odoo/odoo#87527
2022-05-25 18:00:46 +02:00
Christophe Monniez 65c8814a2f [FIX] various: replace deprecated currentThread method
CurrentThread is now really deprecated in Python 3.10 ... Time to
change.

Part-of: odoo/odoo#91927
2022-05-23 08:29:52 +02:00
Julien Castiaux c0647b5c52 [REF] core: HTTPocalypse (14) changes all addons
This commit is the 14th commit of a comprehensive refactor of our HTTP
framework. See odoo/odoo#78857 for complete historic, discussions and
rationnals.

* `request.uid = x` => `request.update_env(user=x)`.
* `request.context = x` => `request.update_env(context=x)`.
* `request.context = dict(request.context, x=y)`
   => `request.update_context(x=y)`.
* `request.cr = None` => `request.cr.close()`.
* `http.mono_db()` => `request.db`.
* `http.dispatch_rpc()` => `service.dispatch_rpc()`.
* `@service.model.check` => `service.model.retrying()`.
* `request.endpoint`
   => `env['ir.http']._match(request.httprequest.path)[0].endpoint`.
* `request.routing_iteration `=> `removed`.
* `request.jsonrequest` => `request.dispatcher.jsonrequest`.

Note that `request.params` is now set much later in the process. If you
are in a situation where you values from the query string or the
http body you can use `request.get_http_params()`.

Note that using the new `request.future_response`, it is possible to
add headers and cookies on the response object before the response
object is initialized. Please note that headers/cookies saved on
the future response will NOT be injected in case of error.

PR: odoo#78857
Task: 2571224
2022-02-24 13:30:51 +00:00
Victor Feyens 405c0dcc9c [IMP] core: warn on duplicate files in manifest data/demo
closes odoo/odoo#83775

Related: odoo/enterprise#23901
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
2022-02-04 07:18:51 +00:00
Victor Feyens 34022a35aa [IMP] core: do not log 'loading demo' for nothing
when there is no demo data available for the given module

closes odoo/odoo#83675

Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
2022-01-31 16:52:42 +00:00
Raphael Collet 75e6b645ac [IMP] core: install PG extension "pg_trgm" only if necessary
Task 2742526

closes odoo/odoo#83274

Signed-off-by: Raphael Collet <rco@odoo.com>
2022-01-28 14:10:02 +00:00
Raphael Collet a1904aa6f6 [IMP] core: field index names
The possible index names have been renamed "btree", "btree_not_null"
(instead of "not null") and "trigram" (instead of "gin").

Task 2742526

Part-of: odoo/odoo#83274
2022-01-28 14:10:01 +00:00
Xavier Morel 722f0f9b65 [IMP] core: deduplicate @locked and @synchronized, use in Registry
It's not entirely clear whether `@synchronized` is even useful, but
keep it for now. `locked` is just the default instance of
`@synchronised`.

- rewrite `@synchronized` using `decorator`, don't fold everything
  into a single call as there's a potential for parametric conflict
- remove the independent `locked` in `sql_db.py`
- convert `lru` to `locked`
- move `Registry` over to `locked` where applicable

closes odoo/odoo#82718

Signed-off-by: Raphael Collet <rco@odoo.com>
2022-01-26 08:48:43 +00:00
Ivan Yelizariev bd534c1861 [FIX] core: keep links in addons_path
resolving the links may block reading static files if real path
doesn't belong to addons_path.

The problem is introduced on refactoring of the `load_manifest` function
https://github.com/odoo/odoo/commit/2e29a9350306fd94fff19bc02821d7e7ab9c6f8b

closes odoo/odoo#82081

Signed-off-by: Raphael Collet <rco@odoo.com>
2022-01-24 12:02:39 +00:00
Fabien Pinckaers eedf37d6e2 [IMP] Better handling of indexes
Three supported types:
- btree (default for index=True)
- btree not null (when >90% of the data are null)
- gin trigram search (for char fields)

Review of indexes on all objects.

closes odoo/odoo#83015

Signed-off-by: Fabien Pinckaers <fp@odoo.com>
2022-01-19 16:52:23 +00:00
Xavier Morel 74241b3766 [FIX] test_lint: support fstrings in sql injection checker
Those were not accounted for, leading to fstrings passing through
unflagged.

Also update the SQL checker to be stricter but smarter:

The previous version would "fail open", unknown nodes would be allowed
through hence f-strings not being flagged when they started appearing
in arg0 position, should now fail-closed, anything that's not allowed
is forbidden.

This flags a few more cases, all of which seem acceptable upon review.

However the previous version would also only resolve arg0 (in case it
had a `NAME`, to see if that resolved to an acceptable form of
query-building). The new version performs resolution during
`_check_concatenation` and should thus allow e.g. format strings to be
separate variables (though not e.g. module-level constants, yet
anyway).

In resolution, replace the ad-hoc process by astroid's built-in
`lookup` which seems to provide the same information. Slightly more in
fact, as it yields every assignment in case of e.g. conditionals, but
making use of that would require a lot more changes in the checker so
leaving the behaviour as-is for now.

It's important to *not* use `ilookup` here, because ilookup is not
"iterable" but "inferring", and we don't want values, we want
expression ASTs for analysis.

NOTE: previous improvements as well as fixes to existing code were
only implemented in 14.0, hence this being merged in 14.0 not 13.0
despite 13.0 still being supported.

closes odoo/odoo#81721

X-original-commit: 376ccf0944dae1bc53ae9c5385977c4e6b23e083
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2021-12-27 09:36:42 +00:00
Julien Castiaux 2e29a93503 [REF] core: remove http.addons_manifest
The http.addons_manifest is a map {module: manifest_dict} that is
populated upon the first http request. This map is basically a module
manifest cache with an extra `addons_path` key, the path of the module
on the file-system. This cache is eagerly populated upon the first http
request, the map is empty in non-http contextes (e.g. cron) which have
been a source of bugs (e.g. 50c8eb1).

A manifest cache is necessary because reading and parsing python files
from the file-system is not that cheap but there is no reason that cache
is located in `odoo.http`. A thin cache layer now wraps
`load_information_from_description_file()`/`load_manifest()` and is
lazily populated.

The `http.addons_manifest` have been removed. The extra `addons_path`
key is now present in the "normal" manifest. The `read_manifest()` was
hardly used so it has been deprecated. The only way to retrieve a
manifest is now `load_information_from_description_file()` which was
renamed `load_manifest()` (no cache) and `get_manifest()` (cache).

Side note about performances, the cache is necessary. Addons manifest
are read-only and reading + parsing python files from the file system is
not a cheap operation. Running the e-commerce tour
`@website_sale.test_04_admin_website_sale_tour` without cache on
`load_manifest()` requires 68,29 secs to complete on my laptop,
exceeding the default 1-minute time frame allowed in tests. Using a
cache the time is down to 36,53 secs. The performance impact is huge.

Part-of: odoo/odoo#79977
2021-12-14 12:39:54 +00:00
Xavier Morel bdc9d9d369 [FIX] core; base: lots of docstrings
* add configuration for `flake8[flake8-rst-docstring]`
* enable docstring-related checks
* fix invalid docstrings in odoo's core & `base`
* fix a few more bits (mostly missing or incorrect `:param:` info
  fields) are out of scope for the lint but my editor catches

closes odoo/odoo#74604

Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
2021-12-09 14:36:58 +00:00
Raphael Collet 0011823932 [FIX] core: cr.transaction no longer depends on registry
The cursor features a "transaction" object to manage application-
specific data in relation with cursor operations.  In its initial
implementation, the transaction object was created by the registry.
This created a requirement: in order to be used in environments, a
cursor had to be created by registry.cursor().

We now remove that unnecessary technical requirement by making
environments create the transaction object on demand.

closes odoo/odoo#80644

X-original-commit: e902713648bca329e6821859462b2128aad62c09
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2021-12-01 08:44:48 +00:00
d04a5b5c8c [REF] core: compute fields before database insertion.
Until now, stored compute fields were computed after database insertion.
This meant that required fields should not be computed, for instance,
unless some hackish code was added to make it work.  Another trick was
to provide some default value, but this actually prevents the field for
being computed after insertion.

This commit provides a field parameter to specify that the field should
be precomputed: adding precompute=True on the field definition force the
method create() to compute its value before inserting the new record in
the database.  For the reason explained below, precomputing fields is
not always correct, and therefore the default remains to not precompute
a field.

Some stored fields must be computed after insertion, for instance:
* statistics fields computed with search/read_group/...
* fields referencing the current record (res.partner.commercial_partner_id)
* fields referencing another record that does not exist yet (think about
  records created by one2many fields)
* fields depending on the create_date/write_date/create_uid/write_uid

Those fields shouldn't be defined with precompute=True, which triggers
their computation post record creation.  This is why, by safety, we
consider the default behavior to be precompute=False.

closes odoo/odoo#80449

Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
Co-authored-by: Raphael Collet <rco@odoo.com>
Co-authored-by: Yannick Tivisse <yti@odoo.com>
2021-11-30 14:30:48 +00:00
Xavier-Do 9b1957fd81 [FIX] core: revert check on new models before setup
This reverts commit 9cc4d6956b71291958114196107b1889109e92a1.

How to reproduce the issue:
- Starts from a database with some modules installed (account).
- Install a module with data only (l10n_generic_coa)

The models are not setup and the data fails to install.

A proper fix would be to mark the registry as dirty when new models are
added and only setup models when needed.

Since the faulty commit was part of a bunch of optimization and the
impact of this particular one is quite small, reverting it is a quick
and easy fix waiting for a better one (maybe, one day).

closes odoo/odoo#79552

Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2021-11-09 14:46:21 +00:00
Adrian Torres ed6595ed15 [FIX] base: prevent messing up existing registry 2021-04-08 08:20:03 +02:00
Paolo (pgi) fe7ed6627d [FIX] base: invalid UNIQUE constraint just warn
When a submodule overrides an old UNIQUE constraint with a new one,
records in that module may respect the new one and not the old one.
As the old module is updated, it would fail giving an ERROR message,
and therefore blocking the Odoo.sh deployment pipeline.

i.e. website_sale (old): res_users_login_key -> ['login', 'website_id']
             base (new): res_users_login_key -> ['login']

With this patch, the error level is changed from ERROR to WARNING,
leaving Odoo.sh free to continue the build deployment, as the error
was not a blocking one.

closes odoo/odoo#79199

X-original-commit: 8ed3641f81502d3a7e9c9bb93771c6f5601a31a9
Signed-off-by: Olivier Dony (odo) <odo@openerp.com>
Signed-off-by: Paolo Gatti (pgi) <pgi@odoo.com>
2021-10-29 14:07:47 +00:00
Xavier-Do 9dceea1818 [IMP] core: skip (setup|init)_models for module without models
Some modules are only adding data/tests/routes/static content.

In this case, it is useless to check the database schema or setup models
in registry.

closes odoo/odoo#78898

Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2021-10-26 13:22:40 +00:00
Xavier-Do 0e2b2c9c8a [FIX] core: avoid useless setup_models at install
When installing a database with all modules in enterprise,
install take around 20 minutes and almost half of that is spent in the
`setup_model` method.

There is actually two calls to `setup_models` for each module.

One of them was introduced in b5c50fa824
and only looks useful when upgrading a module with migration scripts.

This first fix proposes to skip `setup_models` if the module state is
`to install`.

closes odoo/odoo#78808

Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
2021-10-22 15:04:43 +00:00
Raphael Collet bf0a6c9683 [FIX] registry: make invalidation flags thread-specific
The registry attributes 'registry_invalidated' and 'cache_invalidated'
are used to flag that the current request has modified the registry or
invalidated the ormcache, respectively.  This provides a simple yet
efficient way to signal registry changes or cache invalidations to other
workers.

However, those flags were not meant to be used with multi-threaded
workers.  For instance, a thread may signal registry changes that are
actually made by another thread.  It can also happen that a thread
changes the registry, which makes another thread crash (like a thread
modifying a dict while another one iterates over it), and the latter
will reset the registry to its original state because it misinterprets
the registry changes as its own changes.

The situation can even get worse, making threads crash in cascade and
eventually leaving the registry in an inconsistent state.  When this
happens, the worker is broken and has to be manually restarted.

The fix consists in making those flags thread-specific.  This does not
prevent thread crashing because of concurrent changes, but at least it
avoids leaving the worker in a broken state.

closes odoo/odoo#77273

X-original-commit: 28adbfa5a9df9b7754529d45188c0eedeffdf783
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2021-09-27 18:07:56 +00:00
Ivan Yelizariev 68b652b5b6 [FIX] core: regenerate user groups view after forcing demo data
Since
https://github.com/odoo/odoo/commit/8a3e1a0ccdad25ba5b4b99639bdaeb9073a27f1f,
`_update_user_groups_view` is called only once per module installation. However,
module installation is not the only scenario when data files are loaded and
hence we need to add the method call.

---

opw-2602541

closes odoo/odoo#76869

X-original-commit: a46d20c89c24a4e60faef09cf8ad7721bd29d6cc
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2021-09-22 08:15:47 +00:00
Adrian Torres c393a9882e [FIX] core: load all bases for ir.model before adding manual models
Commit cd12293386 introduced an
optimization in the way that models and their inheritances are loaded,
with this commit we defer the setting of each model class' bases
from the _build_model method to the _prepare_setup method.

This has the advantage of setting any given model class' `__bases__`
attribute only once, but it also means that when _add_manual_models is
called, the __bases__ for ir.model are not yet set (only the default
implementation exists), therefore any module overrides to ir.model do
not take effect when creating the custom models.

This meant that if one creates a custom model with chatter support (i.e.
custom ir.model behaviour implemented in mail) and one restarted the
server, the registry would not properly setup ir.model before creating
the custom model (yielding warnings about tracking and such not being
valid fields) and when creating a record of the custom model, the
registry would crash.

With this commit, ir.model's _prepare_setup is explicitly called before
_add_manual_models to ensure that all overrides to ir.model are taken
into account.

closes odoo/odoo#76325

X-original-commit: f3afb23cdf21f395855771a037c721e977dc93c8
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
Signed-off-by: Adrian Torres (adt) <adt@odoo.com>
2021-09-10 12:34:06 +00:00