mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-20 19:31:59 +02:00
18.0 vanilla
This commit is contained in:
parent
d72e748793
commit
0a7ae8db93
337 changed files with 399651 additions and 232598 deletions
|
|
@ -5,9 +5,6 @@ from . import db
|
|||
from . import model
|
||||
from . import server
|
||||
|
||||
# deprecated since 15.3
|
||||
from . import wsgi_server
|
||||
|
||||
#.apidoc title: RPC Services
|
||||
|
||||
""" Classes of this module implement the network protocols that the
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import logging
|
|||
import odoo.release
|
||||
import odoo.tools
|
||||
from odoo.exceptions import AccessDenied
|
||||
from odoo.modules.registry import Registry
|
||||
from odoo.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
|
@ -22,9 +23,10 @@ def exp_login(db, login, password):
|
|||
def exp_authenticate(db, login, password, user_agent_env):
|
||||
if not user_agent_env:
|
||||
user_agent_env = {}
|
||||
res_users = odoo.registry(db)['res.users']
|
||||
res_users = Registry(db)['res.users']
|
||||
try:
|
||||
return res_users.authenticate(db, login, password, {**user_agent_env, 'interactive': False})
|
||||
credential = {'login': login, 'password': password, 'type': 'password'}
|
||||
return res_users.authenticate(db, credential, {**user_agent_env, 'interactive': False})['uid']
|
||||
except AccessDenied:
|
||||
return False
|
||||
|
||||
|
|
|
|||
|
|
@ -6,36 +6,44 @@ import os
|
|||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import threading
|
||||
import traceback
|
||||
from xml.etree import ElementTree as ET
|
||||
import zipfile
|
||||
|
||||
from datetime import datetime
|
||||
from psycopg2 import sql
|
||||
from pytz import country_timezones
|
||||
from functools import wraps
|
||||
from contextlib import closing
|
||||
from decorator import decorator
|
||||
from datetime import datetime
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
import psycopg2
|
||||
from psycopg2.extensions import quote_ident
|
||||
from decorator import decorator
|
||||
from pytz import country_timezones
|
||||
|
||||
import odoo
|
||||
from odoo import SUPERUSER_ID
|
||||
from odoo.exceptions import AccessDenied
|
||||
import odoo.release
|
||||
import odoo.sql_db
|
||||
import odoo.tools
|
||||
from odoo.sql_db import db_connect
|
||||
from odoo import SUPERUSER_ID
|
||||
from odoo.exceptions import AccessDenied
|
||||
from odoo.release import version_info
|
||||
from odoo.tools import find_pg_tool, exec_pg_environ
|
||||
from odoo.sql_db import db_connect
|
||||
from odoo.tools import SQL
|
||||
from odoo.tools.misc import exec_pg_environ, find_pg_tool
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DatabaseExists(Warning):
|
||||
pass
|
||||
|
||||
|
||||
def database_identifier(cr, name: str) -> SQL:
|
||||
"""Quote a database identifier.
|
||||
|
||||
Use instead of `SQL.identifier` to accept all kinds of identifiers.
|
||||
"""
|
||||
name = quote_ident(name, cr._cnx)
|
||||
return SQL(name)
|
||||
|
||||
|
||||
def check_db_management_enabled(method):
|
||||
def if_db_mgt_enabled(method, self, *args, **kwargs):
|
||||
if not odoo.tools.config['list_db']:
|
||||
|
|
@ -92,7 +100,6 @@ def _initialize_db(id, db_name, demo, lang, user_password, login='admin', countr
|
|||
values['email'] = emails[0]
|
||||
env.ref('base.user_admin').write(values)
|
||||
|
||||
cr.execute('SELECT login, password FROM res_users ORDER BY login')
|
||||
cr.commit()
|
||||
except Exception as e:
|
||||
_logger.exception('CREATE DATABASE failed:')
|
||||
|
|
@ -136,10 +143,11 @@ def _create_empty_database(name):
|
|||
cr._cnx.autocommit = True
|
||||
|
||||
# 'C' collate is only safe with template0, but provides more useful indexes
|
||||
collate = sql.SQL("LC_COLLATE 'C'" if chosen_template == 'template0' else "")
|
||||
cr.execute(
|
||||
sql.SQL("CREATE DATABASE {} ENCODING 'unicode' {} TEMPLATE {}").format(
|
||||
sql.Identifier(name), collate, sql.Identifier(chosen_template)
|
||||
cr.execute(SQL(
|
||||
"CREATE DATABASE %s ENCODING 'unicode' %s TEMPLATE %s",
|
||||
database_identifier(cr, name),
|
||||
SQL("LC_COLLATE 'C'") if chosen_template == 'template0' else SQL(""),
|
||||
database_identifier(cr, chosen_template),
|
||||
))
|
||||
|
||||
# TODO: add --extension=trigram,unaccent
|
||||
|
|
@ -185,9 +193,10 @@ def exp_duplicate_database(db_original_name, db_name, neutralize_database=False)
|
|||
# database-altering operations cannot be executed inside a transaction
|
||||
cr._cnx.autocommit = True
|
||||
_drop_conn(cr, db_original_name)
|
||||
cr.execute(sql.SQL("CREATE DATABASE {} ENCODING 'unicode' TEMPLATE {}").format(
|
||||
sql.Identifier(db_name),
|
||||
sql.Identifier(db_original_name)
|
||||
cr.execute(SQL(
|
||||
"CREATE DATABASE %s ENCODING 'unicode' TEMPLATE %s",
|
||||
database_identifier(cr, db_name),
|
||||
database_identifier(cr, db_original_name),
|
||||
))
|
||||
|
||||
registry = odoo.modules.registry.Registry.new(db_name)
|
||||
|
|
@ -234,7 +243,7 @@ def exp_drop(db_name):
|
|||
_drop_conn(cr, db_name)
|
||||
|
||||
try:
|
||||
cr.execute(sql.SQL('DROP DATABASE {}').format(sql.Identifier(db_name)))
|
||||
cr.execute(SQL('DROP DATABASE %s', database_identifier(cr, db_name)))
|
||||
except Exception as e:
|
||||
_logger.info('DROP DB: %s failed:\n%s', db_name, e)
|
||||
raise Exception("Couldn't drop database %s: %s" % (db_name, e))
|
||||
|
|
@ -385,7 +394,7 @@ def exp_rename(old_name, new_name):
|
|||
cr._cnx.autocommit = True
|
||||
_drop_conn(cr, old_name)
|
||||
try:
|
||||
cr.execute(sql.SQL('ALTER DATABASE {} RENAME TO {}').format(sql.Identifier(old_name), sql.Identifier(new_name)))
|
||||
cr.execute(SQL('ALTER DATABASE %s RENAME TO %s', database_identifier(cr, old_name), database_identifier(cr, new_name)))
|
||||
_logger.info('RENAME DB: %s -> %s', old_name, new_name)
|
||||
except Exception as e:
|
||||
_logger.info('RENAME DB: %s -> %s failed:\n%s', old_name, new_name, e)
|
||||
|
|
@ -437,16 +446,15 @@ def list_dbs(force=False):
|
|||
return res
|
||||
|
||||
chosen_template = odoo.tools.config['db_template']
|
||||
templates_list = tuple(set(['postgres', chosen_template]))
|
||||
templates_list = tuple({'postgres', chosen_template})
|
||||
db = odoo.sql_db.db_connect('postgres')
|
||||
with closing(db.cursor()) as cr:
|
||||
try:
|
||||
cr.execute("select datname from pg_database where datdba=(select usesysid from pg_user where usename=current_user) and not datistemplate and datallowconn and datname not in %s order by datname", (templates_list,))
|
||||
res = [odoo.tools.ustr(name) for (name,) in cr.fetchall()]
|
||||
return [name for (name,) in cr.fetchall()]
|
||||
except Exception:
|
||||
_logger.exception('Listing databases failed:')
|
||||
res = []
|
||||
return res
|
||||
return []
|
||||
|
||||
def list_db_incompatible(databases):
|
||||
""""Check a list of databases if they are compatible with this version of Odoo
|
||||
|
|
@ -458,7 +466,7 @@ def list_db_incompatible(databases):
|
|||
server_version = '.'.join(str(v) for v in version_info[:2])
|
||||
for database_name in databases:
|
||||
with closing(db_connect(database_name).cursor()) as cr:
|
||||
if odoo.tools.table_exists(cr, 'ir_module_module'):
|
||||
if odoo.tools.sql.table_exists(cr, 'ir_module_module'):
|
||||
cr.execute("SELECT latest_version FROM ir_module_module WHERE name=%s", ('base',))
|
||||
base_version = cr.fetchone()
|
||||
if not base_version or not base_version[0]:
|
||||
|
|
@ -482,7 +490,7 @@ def exp_list(document=False):
|
|||
return list_dbs()
|
||||
|
||||
def exp_list_lang():
|
||||
return odoo.tools.scan_languages()
|
||||
return odoo.tools.misc.scan_languages()
|
||||
|
||||
def exp_list_countries():
|
||||
list_countries = []
|
||||
|
|
|
|||
|
|
@ -6,20 +6,22 @@ import time
|
|||
from collections.abc import Mapping, Sequence
|
||||
from functools import partial
|
||||
|
||||
from psycopg2 import IntegrityError, OperationalError, errorcodes
|
||||
from psycopg2 import IntegrityError, OperationalError, errorcodes, errors
|
||||
|
||||
import odoo
|
||||
from odoo.exceptions import UserError, ValidationError, AccessError
|
||||
from odoo.models import BaseModel
|
||||
from odoo.http import request
|
||||
from odoo.tools import DotDict
|
||||
from odoo.tools.translate import _, translate_sql_constraint
|
||||
from odoo.modules.registry import Registry
|
||||
from odoo.tools import DotDict, lazy
|
||||
from odoo.tools.translate import translate_sql_constraint
|
||||
|
||||
from . import security
|
||||
from ..tools import lazy
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
PG_CONCURRENCY_ERRORS_TO_RETRY = (errorcodes.LOCK_NOT_AVAILABLE, errorcodes.SERIALIZATION_FAILURE, errorcodes.DEADLOCK_DETECTED)
|
||||
PG_CONCURRENCY_EXCEPTIONS_TO_RETRY = (errors.LockNotAvailable, errors.SerializationFailure, errors.DeadlockDetected)
|
||||
MAX_TRIES_ON_CONCURRENCY_FAILURE = 5
|
||||
|
||||
|
||||
|
|
@ -48,7 +50,7 @@ def dispatch(method, params):
|
|||
|
||||
threading.current_thread().dbname = db
|
||||
threading.current_thread().uid = uid
|
||||
registry = odoo.registry(db).check_signaling()
|
||||
registry = Registry(db).check_signaling()
|
||||
with registry.manage_changes():
|
||||
if method == 'execute':
|
||||
res = execute(db, uid, *params[3:])
|
||||
|
|
@ -65,7 +67,7 @@ def execute_cr(cr, uid, obj, method, *args, **kw):
|
|||
env = odoo.api.Environment(cr, uid, {})
|
||||
recs = env.get(obj)
|
||||
if recs is None:
|
||||
raise UserError(_("Object %s doesn't exist", obj))
|
||||
raise UserError(env._("Object %s doesn't exist", obj))
|
||||
get_public_method(recs, method) # Don't use the result, call_kw will redo the getattr
|
||||
result = retrying(partial(odoo.api.call_kw, recs, method, args, kw), env)
|
||||
# force evaluation of lazy values before the cursor is closed, as it would
|
||||
|
|
@ -80,7 +82,8 @@ def execute_kw(db, uid, obj, method, args, kw=None):
|
|||
|
||||
|
||||
def execute(db, uid, obj, method, *args, **kw):
|
||||
with odoo.registry(db).cursor() as cr:
|
||||
# TODO could be conditionnaly readonly as in _call_kw_readonly
|
||||
with Registry(db).cursor() as cr:
|
||||
res = execute_cr(cr, uid, obj, method, *args, **kw)
|
||||
if res is None:
|
||||
_logger.info('The method %s of the object %s can not return `None`!', method, obj)
|
||||
|
|
@ -90,47 +93,48 @@ def execute(db, uid, obj, method, *args, **kw):
|
|||
def _as_validation_error(env, exc):
|
||||
""" Return the IntegrityError encapsuled in a nice ValidationError """
|
||||
|
||||
unknown = _('Unknown')
|
||||
model = DotDict({'_name': unknown.lower(), '_description': unknown})
|
||||
field = DotDict({'name': unknown.lower(), 'string': unknown})
|
||||
unknown = env._('Unknown')
|
||||
model = DotDict({'_name': 'unknown', '_description': unknown})
|
||||
field = DotDict({'name': 'unknown', 'string': unknown})
|
||||
for _name, rclass in env.registry.items():
|
||||
if exc.diag.table_name == rclass._table:
|
||||
model = rclass
|
||||
field = model._fields.get(exc.diag.column_name) or field
|
||||
break
|
||||
|
||||
if exc.pgcode == errorcodes.NOT_NULL_VIOLATION:
|
||||
return ValidationError(_(
|
||||
"The operation cannot be completed:\n"
|
||||
"- Create/update: a mandatory field is not set.\n"
|
||||
"- Delete: another model requires the record being deleted."
|
||||
" If possible, archive it instead.\n\n"
|
||||
"Model: %(model_name)s (%(model_tech_name)s)\n"
|
||||
"Field: %(field_name)s (%(field_tech_name)s)\n",
|
||||
model_name=model._description,
|
||||
model_tech_name=model._name,
|
||||
field_name=field.string,
|
||||
field_tech_name=field.name,
|
||||
))
|
||||
match exc:
|
||||
case errors.NotNullViolation():
|
||||
return ValidationError(env._(
|
||||
"The operation cannot be completed:\n"
|
||||
"- Create/update: a mandatory field is not set.\n"
|
||||
"- Delete: another model requires the record being deleted."
|
||||
" If possible, archive it instead.\n\n"
|
||||
"Model: %(model_name)s (%(model_tech_name)s)\n"
|
||||
"Field: %(field_name)s (%(field_tech_name)s)\n",
|
||||
model_name=model._description,
|
||||
model_tech_name=model._name,
|
||||
field_name=field.string,
|
||||
field_tech_name=field.name,
|
||||
))
|
||||
|
||||
if exc.pgcode == errorcodes.FOREIGN_KEY_VIOLATION:
|
||||
return ValidationError(_(
|
||||
"The operation cannot be completed: another model requires "
|
||||
"the record being deleted. If possible, archive it instead.\n\n"
|
||||
"Model: %(model_name)s (%(model_tech_name)s)\n"
|
||||
"Constraint: %(constraint)s\n",
|
||||
model_name=model._description,
|
||||
model_tech_name=model._name,
|
||||
constraint=exc.diag.constraint_name,
|
||||
))
|
||||
case errors.ForeignKeyViolation():
|
||||
return ValidationError(env._(
|
||||
"The operation cannot be completed: another model requires "
|
||||
"the record being deleted. If possible, archive it instead.\n\n"
|
||||
"Model: %(model_name)s (%(model_tech_name)s)\n"
|
||||
"Constraint: %(constraint)s\n",
|
||||
model_name=model._description,
|
||||
model_tech_name=model._name,
|
||||
constraint=exc.diag.constraint_name,
|
||||
))
|
||||
|
||||
if exc.diag.constraint_name in env.registry._sql_constraints:
|
||||
return ValidationError(_(
|
||||
return ValidationError(env._(
|
||||
"The operation cannot be completed: %s",
|
||||
translate_sql_constraint(env.cr, exc.diag.constraint_name, env.context.get('lang', 'en_US'))
|
||||
))
|
||||
|
||||
return ValidationError(_("The operation cannot be completed: %s", exc.args[0]))
|
||||
return ValidationError(env._("The operation cannot be completed: %s", exc.args[0]))
|
||||
|
||||
|
||||
def retrying(func, env):
|
||||
|
|
@ -169,7 +173,7 @@ def retrying(func, env):
|
|||
raise RuntimeError(f"Cannot retry request on input file {filename!r} after serialization failure") from exc
|
||||
if isinstance(exc, IntegrityError):
|
||||
raise _as_validation_error(env, exc) from exc
|
||||
if exc.pgcode not in PG_CONCURRENCY_ERRORS_TO_RETRY:
|
||||
if not isinstance(exc, PG_CONCURRENCY_EXCEPTIONS_TO_RETRY):
|
||||
raise
|
||||
if not tryleft:
|
||||
_logger.info("%s, maximum number of tries reached!", errorcodes.lookup(exc.pgcode))
|
||||
|
|
|
|||
|
|
@ -3,18 +3,23 @@
|
|||
|
||||
import odoo
|
||||
import odoo.exceptions
|
||||
from odoo.modules.registry import Registry
|
||||
|
||||
|
||||
def check(db, uid, passwd):
|
||||
res_users = odoo.registry(db)['res.users']
|
||||
res_users = Registry(db)['res.users']
|
||||
return res_users.check(db, uid, passwd)
|
||||
|
||||
def compute_session_token(session, env):
|
||||
self = env['res.users'].browse(session.uid)
|
||||
return self._compute_session_token(session.sid)
|
||||
|
||||
def check_session(session, env):
|
||||
|
||||
def check_session(session, env, request=None):
|
||||
self = env['res.users'].browse(session.uid)
|
||||
expected = self._compute_session_token(session.sid)
|
||||
if expected and odoo.tools.misc.consteq(expected, session.session_token):
|
||||
if request:
|
||||
env['res.device.log']._update_device(request)
|
||||
return True
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -15,17 +15,12 @@ import subprocess
|
|||
import sys
|
||||
import threading
|
||||
import time
|
||||
import unittest
|
||||
import contextlib
|
||||
from email.utils import parsedate_to_datetime
|
||||
from io import BytesIO
|
||||
from itertools import chain
|
||||
|
||||
import psutil
|
||||
import werkzeug.serving
|
||||
from werkzeug.debug import DebuggedApplication
|
||||
|
||||
from ..tests import loader
|
||||
|
||||
if os.name == 'posix':
|
||||
# Unix only for workers
|
||||
|
|
@ -62,7 +57,8 @@ from odoo.modules import get_modules
|
|||
from odoo.modules.registry import Registry
|
||||
from odoo.release import nt_service_name
|
||||
from odoo.tools import config
|
||||
from odoo.tools import stripped_sys_argv, dumpstacks, log_ormcache_stats
|
||||
from odoo.tools.cache import log_ormcache_stats
|
||||
from odoo.tools.misc import stripped_sys_argv, dumpstacks
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -81,10 +77,15 @@ def memory_info(process):
|
|||
|
||||
|
||||
def set_limit_memory_hard():
|
||||
if platform.system() == 'Linux' and config['limit_memory_hard']:
|
||||
if platform.system() != 'Linux':
|
||||
return
|
||||
limit_memory_hard = config['limit_memory_hard']
|
||||
if odoo.evented and config['limit_memory_hard_gevent']:
|
||||
limit_memory_hard = config['limit_memory_hard_gevent']
|
||||
if limit_memory_hard:
|
||||
rlimit = resource.RLIMIT_AS
|
||||
soft, hard = resource.getrlimit(rlimit)
|
||||
resource.setrlimit(rlimit, (config['limit_memory_hard'], hard))
|
||||
resource.setrlimit(rlimit, (limit_memory_hard, hard))
|
||||
|
||||
def empty_pipe(fd):
|
||||
try:
|
||||
|
|
@ -255,21 +256,7 @@ class ThreadedWSGIServerReloadable(LoggingBaseWSGIServerMixIn, werkzeug.serving.
|
|||
t.start_time = time.time()
|
||||
t.start()
|
||||
|
||||
# TODO: Remove this method as soon as either of the revision
|
||||
# - python/cpython@8b1f52b5a93403acd7d112cd1c1bc716b31a418a for Python 3.6,
|
||||
# - python/cpython@908082451382b8b3ba09ebba638db660edbf5d8e for Python 3.7,
|
||||
# is included in all Python 3 releases installed on all operating systems supported by Odoo.
|
||||
# These revisions are included in Python from releases 3.6.8 and Python 3.7.2 respectively.
|
||||
def _handle_request_noblock(self):
|
||||
"""
|
||||
In the python module `socketserver` `process_request` loop,
|
||||
the __shutdown_request flag is not checked between select and accept.
|
||||
Thus when we set it to `True` thanks to the call `httpd.shutdown`,
|
||||
a last request is accepted before exiting the loop.
|
||||
We override this function to add an additional check before the accept().
|
||||
"""
|
||||
if self._BaseServer__shutdown_request:
|
||||
return
|
||||
if self.max_http_threads and not self.http_threads_sem.acquire(timeout=0.1):
|
||||
# If the semaphore is full we will return immediately to the upstream (most probably
|
||||
# socketserver.BaseServer's serve_forever loop which will retry immediately as the
|
||||
|
|
@ -299,7 +286,7 @@ class FSWatcherBase(object):
|
|||
except SyntaxError:
|
||||
_logger.error('autoreload: python code change detected, SyntaxError in %s', path)
|
||||
else:
|
||||
if not getattr(odoo, 'phoenix', False):
|
||||
if not server_phoenix:
|
||||
_logger.info('autoreload: python code updated, autoreload activated')
|
||||
restart()
|
||||
return True
|
||||
|
|
@ -450,7 +437,8 @@ class ThreadedServer(CommonServer):
|
|||
os._exit(0)
|
||||
elif sig == signal.SIGHUP:
|
||||
# restart on kill -HUP
|
||||
odoo.phoenix = True
|
||||
global server_phoenix # noqa: PLW0603
|
||||
server_phoenix = True
|
||||
self.quit_signals_received += 1
|
||||
# interrupt run() to start shutdown
|
||||
raise KeyboardInterrupt()
|
||||
|
|
@ -557,14 +545,13 @@ class ThreadedServer(CommonServer):
|
|||
t.start()
|
||||
_logger.debug("cron%d started!" % i)
|
||||
|
||||
def http_thread(self):
|
||||
self.httpd = ThreadedWSGIServerReloadable(self.interface, self.port, self.app)
|
||||
self.httpd.serve_forever()
|
||||
|
||||
def http_spawn(self):
|
||||
t = threading.Thread(target=self.http_thread, name="odoo.service.httpd")
|
||||
t.daemon = True
|
||||
t.start()
|
||||
self.httpd = ThreadedWSGIServerReloadable(self.interface, self.port, self.app)
|
||||
threading.Thread(
|
||||
target=self.httpd.serve_forever,
|
||||
name="odoo.service.httpd",
|
||||
daemon=True,
|
||||
).start()
|
||||
|
||||
def start(self, stop=False):
|
||||
_logger.debug("Setting signal handlers")
|
||||
|
|
@ -589,7 +576,7 @@ class ThreadedServer(CommonServer):
|
|||
def stop(self):
|
||||
""" Shutdown the WSGI server. Wait for non daemon threads.
|
||||
"""
|
||||
if getattr(odoo, 'phoenix', None):
|
||||
if server_phoenix:
|
||||
_logger.info("Initiating server reload")
|
||||
else:
|
||||
_logger.info("Initiating shutdown")
|
||||
|
|
@ -630,13 +617,13 @@ class ThreadedServer(CommonServer):
|
|||
The first SIGINT or SIGTERM signal will initiate a graceful shutdown while
|
||||
a second one if any will force an immediate exit.
|
||||
"""
|
||||
self.start(stop=stop)
|
||||
|
||||
rc = preload_registries(preload)
|
||||
with Registry._lock:
|
||||
self.start(stop=stop)
|
||||
rc = preload_registries(preload)
|
||||
|
||||
if stop:
|
||||
if config['test_enable']:
|
||||
logger = odoo.tests.result._logger
|
||||
from odoo.tests.result import _logger as logger # noqa: PLC0415
|
||||
with Registry.registries._lock:
|
||||
for db, registry in Registry.registries.d.items():
|
||||
report = registry._assertion_report
|
||||
|
|
@ -671,7 +658,7 @@ class ThreadedServer(CommonServer):
|
|||
# `reload` increments `self.quit_signals_received`
|
||||
# and the loop will end after this iteration,
|
||||
# therefore leading to the server stop.
|
||||
# `reload` also sets the `phoenix` flag
|
||||
# `reload` also sets the `server_phoenix` flag
|
||||
# to tell the server to restart the server after shutting down.
|
||||
else:
|
||||
time.sleep(1)
|
||||
|
|
@ -697,7 +684,8 @@ class GeventServer(CommonServer):
|
|||
_logger.warning("Gevent Parent changed: %s", self.pid)
|
||||
restart = True
|
||||
memory = memory_info(psutil.Process(self.pid))
|
||||
if config['limit_memory_soft'] and memory > config['limit_memory_soft']:
|
||||
limit_memory_soft = config['limit_memory_soft_gevent'] or config['limit_memory_soft']
|
||||
if limit_memory_soft and memory > limit_memory_soft:
|
||||
_logger.warning('Gevent virtual memory limit reached: %s', memory)
|
||||
restart = True
|
||||
if restart:
|
||||
|
|
@ -891,7 +879,8 @@ class PreforkServer(CommonServer):
|
|||
raise KeyboardInterrupt
|
||||
elif sig == signal.SIGHUP:
|
||||
# restart on kill -HUP
|
||||
odoo.phoenix = True
|
||||
global server_phoenix # noqa: PLW0603
|
||||
server_phoenix = True
|
||||
raise KeyboardInterrupt
|
||||
elif sig == signal.SIGQUIT:
|
||||
# dump stacks on kill -3
|
||||
|
|
@ -1308,6 +1297,7 @@ class WorkerCron(Worker):
|
|||
#----------------------------------------------------------
|
||||
|
||||
server = None
|
||||
server_phoenix = False
|
||||
|
||||
def load_server_wide_modules():
|
||||
server_wide_modules = list(odoo.conf.server_wide_modules)
|
||||
|
|
@ -1336,9 +1326,11 @@ def _reexec(updated_modules=None):
|
|||
# We should keep the LISTEN_* environment variabled in order to support socket activation on reexec
|
||||
os.execve(sys.executable, args, os.environ)
|
||||
|
||||
|
||||
def load_test_file_py(registry, test_file):
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from odoo.tests.suite import OdooSuite
|
||||
from odoo.tests import loader # noqa: PLC0415
|
||||
from odoo.tests.suite import OdooSuite # noqa: PLC0415
|
||||
threading.current_thread().testing = True
|
||||
try:
|
||||
test_path, _ = os.path.splitext(os.path.abspath(test_file))
|
||||
|
|
@ -1346,8 +1338,7 @@ def load_test_file_py(registry, test_file):
|
|||
for mod_mod in loader.get_test_modules(mod):
|
||||
mod_path, _ = os.path.splitext(getattr(mod_mod, '__file__', ''))
|
||||
if test_path == config._normalize(mod_path):
|
||||
tests = loader.unwrap_suite(
|
||||
unittest.TestLoader().loadTestsFromModule(mod_mod))
|
||||
tests = loader.get_module_test_cases(mod_mod)
|
||||
suite = OdooSuite(tests)
|
||||
_logger.log(logging.INFO, 'running tests %s.', mod_mod.__name__)
|
||||
suite(registry._assertion_report)
|
||||
|
|
@ -1357,6 +1348,7 @@ def load_test_file_py(registry, test_file):
|
|||
finally:
|
||||
threading.current_thread().testing = False
|
||||
|
||||
|
||||
def preload_registries(dbnames):
|
||||
""" Preload a registries, possibly run a test file."""
|
||||
# TODO: move all config checks to args dont check tools.config here
|
||||
|
|
@ -1381,6 +1373,7 @@ def preload_registries(dbnames):
|
|||
|
||||
# run post-install tests
|
||||
if config['test_enable']:
|
||||
from odoo.tests import loader # noqa: PLC0415
|
||||
t0 = time.time()
|
||||
t0_sql = odoo.sql_db.sql_counter
|
||||
module_names = (registry.updated_modules if update_module else
|
||||
|
|
@ -1400,7 +1393,7 @@ def preload_registries(dbnames):
|
|||
odoo.sql_db.sql_counter - t0_sql)
|
||||
|
||||
registry._assertion_report.log_stats()
|
||||
if not registry._assertion_report.wasSuccessful():
|
||||
if registry._assertion_report and not registry._assertion_report.wasSuccessful():
|
||||
rc += 1
|
||||
except Exception:
|
||||
_logger.critical('Failed to initialize database `%s`.', dbname, exc_info=True)
|
||||
|
|
@ -1421,11 +1414,6 @@ def start(preload=None, stop=False):
|
|||
_logger.warning("Unit testing in workers mode could fail; use --workers 0.")
|
||||
|
||||
server = PreforkServer(odoo.http.root)
|
||||
|
||||
# Workaround for Python issue24291, fixed in 3.6 (see Python issue26721)
|
||||
if sys.version_info[:2] == (3,5):
|
||||
# turn on buffering also for wfile, to avoid partial writes (Default buffer = 8k)
|
||||
werkzeug.serving.WSGIRequestHandler.wbufsize = -1
|
||||
else:
|
||||
if platform.system() == "Linux" and sys.maxsize > 2**32 and "MALLOC_ARENA_MAX" not in os.environ:
|
||||
# glibc's malloc() uses arenas [1] in order to efficiently handle memory allocation of multi-threaded
|
||||
|
|
@ -1471,7 +1459,7 @@ def start(preload=None, stop=False):
|
|||
if watcher:
|
||||
watcher.stop()
|
||||
# like the legend of the phoenix, all ends with beginnings
|
||||
if getattr(odoo, 'phoenix', False):
|
||||
if server_phoenix:
|
||||
_reexec()
|
||||
|
||||
return rc if rc else 0
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
import warnings
|
||||
import odoo.http
|
||||
|
||||
|
||||
def application(environ, start_response):
|
||||
|
||||
warnings.warn("The WSGI application entrypoint moved from "
|
||||
"odoo.service.wsgi_server.application to odoo.http.root "
|
||||
"in 15.3.",
|
||||
DeprecationWarning, stacklevel=1)
|
||||
return odoo.http.root(environ, start_response)
|
||||
Loading…
Add table
Add a link
Reference in a new issue