mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-20 08:52:08 +02:00
18.0 vanilla
This commit is contained in:
parent
d72e748793
commit
0a7ae8db93
337 changed files with 399651 additions and 232598 deletions
|
|
@ -1,129 +1,74 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import fnmatch
|
||||
import logging
|
||||
import optparse
|
||||
import sys
|
||||
import time
|
||||
from contextlib import nullcontext
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
import odoo
|
||||
|
||||
from . import Command
|
||||
import odoo
|
||||
from odoo.modules.registry import Registry
|
||||
from odoo.tools.populate import populate_models
|
||||
from odoo.api import Environment
|
||||
|
||||
DEFAULT_FACTOR = '10000'
|
||||
DEFAULT_SEPARATOR = '_'
|
||||
DEFAULT_MODELS = 'res.partner,product.template,account.move,sale.order,crm.lead,stock.picking,project.task'
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Populate(Command):
|
||||
""" Inject fake data inside a database for testing """
|
||||
"""Populate database via duplication of existing data for testing/demo purposes"""
|
||||
|
||||
def run(self, cmdargs):
|
||||
parser = odoo.tools.config.parser
|
||||
parser.prog = f'{Path(sys.argv[0]).name} {self.name}'
|
||||
group = optparse.OptionGroup(parser, "Populate Configuration")
|
||||
group.add_option("--size", dest="population_size",
|
||||
help="Populate database with auto-generated data. Value should be the population size: small, medium or large",
|
||||
default='small')
|
||||
group.add_option("--factors", dest="factors",
|
||||
help="Comma separated list of factors for each model, or just a single factor."
|
||||
"(Ex: a factor of 3 means the given model will be copied 3 times, reaching 4x it's original size)"
|
||||
"The last factor is propagated to the remaining models without a factor.",
|
||||
default=DEFAULT_FACTOR)
|
||||
group.add_option("--models",
|
||||
dest='populate_models',
|
||||
help="Comma separated list of model or pattern (fnmatch)")
|
||||
group.add_option("--profile",
|
||||
dest='profiling_enabled', action="store_true",
|
||||
help="Specify if you want to profile records population.",
|
||||
default=False)
|
||||
group.add_option("--rollback",
|
||||
dest='populate_rollback', action="store_true",
|
||||
help="Specify if you want to rollback database population.",
|
||||
default=False)
|
||||
dest='models_to_populate',
|
||||
help="Comma separated list of models",
|
||||
default=DEFAULT_MODELS)
|
||||
group.add_option("--sep",
|
||||
dest='separator',
|
||||
help="Single character separator for char/text fields.",
|
||||
default=DEFAULT_SEPARATOR)
|
||||
parser.add_option_group(group)
|
||||
opt = odoo.tools.config.parse_config(cmdargs)
|
||||
populate_models = opt.populate_models and set(opt.populate_models.split(','))
|
||||
dbname = odoo.tools.config['db_name']
|
||||
registry = odoo.registry(dbname)
|
||||
with registry.cursor() as cr:
|
||||
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
|
||||
self.populate(
|
||||
env, opt.population_size, populate_models,
|
||||
profiling_enabled=opt.profiling_enabled,
|
||||
commit=not opt.populate_rollback)
|
||||
opt = odoo.tools.config.parse_config(cmdargs, setup_logging=True)
|
||||
|
||||
@classmethod
|
||||
def populate(cls, env, size, model_patterns=False, profiling_enabled=False, commit=True):
|
||||
registry = env.registry
|
||||
populated_models = None
|
||||
# deduplicate models if necessary, and keep the last corresponding
|
||||
# factor for each model
|
||||
opt_factors = [int(f) for f in opt.factors.split(',')]
|
||||
model_factors = {
|
||||
model_name: opt_factors[index] if index < len(opt_factors) else opt_factors[-1]
|
||||
for index, model_name in enumerate(opt.models_to_populate.split(','))
|
||||
}
|
||||
try:
|
||||
registry.populated_models = {} # todo master, initialize with already populated models
|
||||
ordered_models = cls._get_ordered_models(env, model_patterns)
|
||||
separator_code = ord(opt.separator)
|
||||
except TypeError:
|
||||
raise ValueError("Separator must be a single Unicode character.")
|
||||
|
||||
_logger.log(25, 'Populating database')
|
||||
for model in ordered_models:
|
||||
if profiling_enabled:
|
||||
profiling_context = odoo.tools.profiler.Profiler(
|
||||
description=f'{model} {size}',
|
||||
db=env.cr.dbname
|
||||
)
|
||||
else:
|
||||
profiling_context = nullcontext()
|
||||
|
||||
if commit:
|
||||
commit_context = nullcontext()
|
||||
else:
|
||||
commit_context = patch('odoo.sql_db.Cursor.commit')
|
||||
|
||||
_logger.info('Populating database for model %s', model._name)
|
||||
t0 = time.time()
|
||||
|
||||
with profiling_context, commit_context:
|
||||
registry.populated_models[model._name] = model._populate(size).ids
|
||||
|
||||
if not registry.populated_models[model._name]:
|
||||
# Do not create ir.profile records
|
||||
# for models without any population factories
|
||||
profiling_context.db = False
|
||||
|
||||
# force the flush to make sure population time still
|
||||
# considers flushing all values to database
|
||||
env.flush_all()
|
||||
|
||||
if commit:
|
||||
env.cr.commit()
|
||||
|
||||
model_time = time.time() - t0
|
||||
if model_time > 1:
|
||||
_logger.info('Populated database for model %s (total: %fs) (average: %fms per record)',
|
||||
model._name, model_time, model_time / len(registry.populated_models[model._name]) * 1000)
|
||||
except:
|
||||
_logger.exception('Something went wrong populating database')
|
||||
finally:
|
||||
if not commit:
|
||||
env.cr.rollback()
|
||||
populated_models = registry.populated_models
|
||||
del registry.populated_models
|
||||
|
||||
return populated_models
|
||||
dbname = odoo.tools.config['db_name']
|
||||
registry = Registry(dbname)
|
||||
with registry.cursor() as cr:
|
||||
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {'active_test': False})
|
||||
self.populate(env, model_factors, separator_code)
|
||||
|
||||
@classmethod
|
||||
def _get_ordered_models(cls, env, model_patterns=False):
|
||||
_logger.info('Computing model order')
|
||||
processed = set()
|
||||
ordered_models = []
|
||||
visited = set()
|
||||
def add_model(model):
|
||||
if model not in processed:
|
||||
if model in visited:
|
||||
raise ValueError('Cyclic dependency detected for %s' % model)
|
||||
visited.add(model)
|
||||
for dep in model._populate_dependencies:
|
||||
add_model(env[dep])
|
||||
ordered_models.append(model)
|
||||
processed.add(model)
|
||||
for model in env.values():
|
||||
if model_patterns and not any(fnmatch.fnmatch(model._name, match) for match in model_patterns):
|
||||
continue
|
||||
if model._transient or model._abstract:
|
||||
continue
|
||||
ir_model = env['ir.model'].search([('model', '=', model._name)])
|
||||
if not model_patterns and all(module.startswith('test_') for module in ir_model.modules.split(',')):
|
||||
continue
|
||||
add_model(model)
|
||||
|
||||
return ordered_models
|
||||
def populate(cls, env: Environment, modelname_factors: dict[str, int], separator_code: int):
|
||||
model_factors = {
|
||||
model: factor
|
||||
for model_name, factor in modelname_factors.items()
|
||||
if (model := env.get(model_name)) is not None and not (model._transient or model._abstract)
|
||||
}
|
||||
_logger.log(25, 'Populating models %s', list(model_factors))
|
||||
t0 = time.time()
|
||||
populate_models(model_factors, separator_code)
|
||||
env.flush_all()
|
||||
model_time = time.time() - t0
|
||||
_logger.info('Populated models %s (total: %fs)', list(model_factors), model_time)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue