merge upstream

bzr revid: chs@openerp.com-20121128184100-rkr90mrx38fh9q4l
This commit is contained in:
Christophe Simonis 2012-11-28 19:41:00 +01:00
commit a208447a3d
12 changed files with 112 additions and 79 deletions

View File

@ -149,7 +149,6 @@ CREATE TABLE res_users (
active boolean default True,
login varchar(64) NOT NULL UNIQUE,
password varchar(64) default null,
tz varchar(64) default null,
lang varchar(64) default '',
-- No FK references below, will be added later by ORM
-- (when the destination rows exist)

View File

@ -88,6 +88,7 @@ gk//2Q==</field>
<record model="res.partner" id="base.partner_root">
<field name="email">admin@example.com</field>
<field name="tz">Europe/Brussels</field>
<field name="image">/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEP
ERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4e
Hh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCACmAKYDASIA

View File

@ -18,7 +18,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from docutils import io, nodes
from docutils.core import publish_string
from docutils.transforms import Transform, writer_aux
from docutils.writers.html4css1 import Writer
import imp
import logging
import os
@ -37,6 +40,7 @@ except ImportError:
import openerp
from openerp import modules, pooler, tools, addons
from openerp.modules.db import create_categories
from openerp.tools.parse_version import parse_version
from openerp.tools.translate import _
from openerp.osv import fields, osv, orm
@ -104,6 +108,32 @@ class module_category(osv.osv):
'visible': 1,
}
class MyFilterMessages(Transform):
"""
Custom docutils transform to remove `system message` for a document and
generate warnings.
(The standard filter removes them based on some `report_level` passed in
the `settings_override` dictionary, but if we use it, we can't see them
and generate warnings.)
"""
default_priority = 870
def apply(self):
for node in self.document.traverse(nodes.system_message):
_logger.warning("docutils' system message present: %s", str(node))
node.parent.remove(node)
class MyWriter(Writer):
"""
Custom docutils html4ccs1 writer that doesn't add the warnings to the
output document.
"""
def get_transforms(self):
return [MyFilterMessages, writer_aux.Admonitions]
class module(osv.osv):
_name = "ir.module.module"
_rec_name = "shortdesc"
@ -123,7 +153,7 @@ class module(osv.osv):
res = dict.fromkeys(ids, '')
for module in self.browse(cr, uid, ids, context=context):
overrides = dict(embed_stylesheet=False, doctitle_xform=False, output_encoding='unicode')
output = publish_string(source=module.description, writer_name='html', settings_overrides=overrides)
output = publish_string(source=module.description, settings_overrides=overrides, writer=MyWriter())
res[module.id] = output
return res
@ -692,21 +722,8 @@ class module(osv.osv):
categs = category.split('/')
if categs != current_category_path:
p_id = None
while categs:
if p_id is not None:
cr.execute('SELECT id FROM ir_module_category WHERE name=%s AND parent_id=%s', (categs[0], p_id))
else:
cr.execute('SELECT id FROM ir_module_category WHERE name=%s AND parent_id is NULL', (categs[0],))
c_id = cr.fetchone()
if not c_id:
cr.execute('INSERT INTO ir_module_category (name, parent_id) VALUES (%s, %s) RETURNING id', (categs[0], p_id))
c_id = cr.fetchone()[0]
else:
c_id = c_id[0]
p_id = c_id
categs = categs[1:]
self.write(cr, uid, [mod_browse.id], {'category_id': p_id})
cat_id = create_categories(cr, categs)
mod_browse.write({'category_id': cat_id})
def update_translations(self, cr, uid, ids, filter_lang=None, context=None):
if not filter_lang:

View File

@ -19,6 +19,7 @@
#
##############################################################################
import datetime
import math
import openerp
from osv import osv, fields
@ -178,6 +179,12 @@ class res_partner(osv.osv, format_address):
result[obj.id] = tools.image_get_resized_images(obj.image)
return result
def _get_tz_offset(self, cr, uid, ids, name, args, context=None):
result = dict.fromkeys(ids, False)
for obj in self.browse(cr, uid, ids, context=context):
result[obj.id] = datetime.datetime.now(pytz.timezone(obj.tz or 'GMT')).strftime('%z')
return result
def _set_image(self, cr, uid, id, name, value, args, context=None):
return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)
@ -195,6 +202,7 @@ class res_partner(osv.osv, format_address):
help="The partner's timezone, used to output proper date and time values inside printed reports. "
"It is important to set a value for this field. You should use the same timezone "
"that is otherwise used to pick and render date and time values: your computer's timezone."),
'tz_offset': fields.function(_get_tz_offset, type='char', size=5, string='Timezone offset', store=True),
'user_id': fields.many2one('res.users', 'Salesperson', help='The internal user that is in charge of communicating with this contact if any.'),
'vat': fields.char('TIN', size=32, help="Tax Identification Number. Check the box if this contact is subjected to taxes. Used by the some of the legal statements."),
'bank_ids': fields.one2many('res.partner.bank', 'partner_id', 'Banks'),

View File

@ -343,7 +343,7 @@ class res_users(osv.osv):
for k in self._all_columns.keys():
if k.startswith('context_'):
context_key = k[8:]
elif k in ['lang', 'tz']:
elif k in ['lang', 'tz', 'tz_offset']:
context_key = k
else:
context_key = False

View File

@ -94,7 +94,11 @@ def setup_pid_file():
def preload_registry(dbname):
""" Preload a registry, and start the cron."""
try:
db, registry = openerp.pooler.get_db_and_pool(dbname, update_module=openerp.tools.config['init'] or openerp.tools.config['update'], pooljobs=False)
config = openerp.tools.config
update_module = True if config['init'] or config['update'] else False
db, registry = openerp.pooler.get_db_and_pool(
dbname, update_module=update_module, pooljobs=False,
force_demo=not config['without_demo'])
# jobs will start to be processed later, when openerp.cron.start_master_thread() is called by openerp.service.start_services()
registry.schedule_cron_jobs()
@ -105,7 +109,9 @@ def run_test_file(dbname, test_file):
""" Preload a registry, possibly run a test file, and start the cron."""
try:
config = openerp.tools.config
db, registry = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False)
update_module = True if config['init'] or config['update'] else False
db, registry = openerp.pooler.get_db_and_pool(
dbname, update_module=update_module, pooljobs=False, force_demo=not config['without_demo'])
cr = db.cursor()
_logger.info('loading test file %s', test_file)
openerp.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'test', True)

View File

@ -3,7 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010 OpenERP s.a. (<http://openerp.com>).
# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -119,21 +119,17 @@ def create_categories(cr, categories):
category = []
while categories:
category.append(categories[0])
if p_id is not None:
cr.execute('SELECT id \
FROM ir_module_category \
WHERE name=%s AND parent_id=%s', (categories[0], p_id))
else:
cr.execute('SELECT id \
FROM ir_module_category \
WHERE name=%s AND parent_id IS NULL', (categories[0],))
xml_id = 'module_category_' + ('_'.join(map(lambda x: x.lower(), category))).replace('&', 'and').replace(' ', '_')
# search via xml_id (because some categories are renamed)
cr.execute("SELECT res_id FROM ir_model_data WHERE name=%s AND module=%s AND model=%s",
(xml_id, "base", "ir.module.category"))
c_id = cr.fetchone()
if not c_id:
cr.execute('INSERT INTO ir_module_category \
(name, parent_id) \
VALUES (%s, %s) RETURNING id', (categories[0], p_id))
c_id = cr.fetchone()[0]
xml_id = 'module_category_' + ('_'.join(map(lambda x: x.lower(), category))).replace('&', 'and').replace(' ', '_')
cr.execute('INSERT INTO ir_model_data (module, name, res_id, model) \
VALUES (%s, %s, %s, %s)', ('base', xml_id, c_id, 'ir.module.category'))
else:

View File

@ -87,15 +87,19 @@ class Graph(dict):
for k, v in additional_data[package.name].items():
setattr(package, k, v)
def add_module(self, cr, module, force=None):
self.add_modules(cr, [module], force)
def add_module(self, cr, module, force_demo=False):
self.add_modules(cr, [module], force_demo)
def add_modules(self, cr, module_list, force=None):
if force is None:
force = []
def add_modules(self, cr, module_list, force_demo=False):
packages = []
len_graph = len(self)
for module in module_list:
if force_demo:
cr.execute("""
UPDATE ir_module_module
SET demo='t'
WHERE name = %s""",
(module,))
# This will raise an exception if no/unreadable descriptor file.
# NOTE The call to load_information_from_description_file is already
# done by db.initialize, so it is possible to not do it again here.
@ -121,9 +125,6 @@ class Graph(dict):
current.remove(package)
node = self.add_node(package, info)
node.data = info
for kind in ('init', 'demo', 'update'):
if package in tools.config[kind] or 'all' in tools.config[kind] or kind in force:
setattr(node, kind, True)
else:
later.add(package)
packages.append((package, info))
@ -185,18 +186,11 @@ class Node(Singleton):
node.depth = self.depth + 1
if node not in self.children:
self.children.append(node)
for attr in ('init', 'update', 'demo'):
if hasattr(self, attr):
setattr(node, attr, True)
self.children.sort(lambda x, y: cmp(x.name, y.name))
return node
def __setattr__(self, name, value):
super(Singleton, self).__setattr__(name, value)
if name in ('init', 'update', 'demo'):
tools.config[name][self.name] = 1
for child in self.children:
setattr(child, name, value)
if name == 'depth':
for child in self.children:
setattr(child, name, value + 1)

View File

@ -42,6 +42,7 @@ from openerp import SUPERUSER_ID
from openerp import SUPERUSER_ID
from openerp.tools.translate import _
from openerp.tools import assertion_report
from openerp.modules.module import initialize_sys_path, \
load_openerp_module, init_module_models
@ -157,7 +158,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
models = pool.load(cr, package)
loaded_modules.append(package.name)
if hasattr(package, 'init') or hasattr(package, 'update') or package.state in ('to install', 'to upgrade'):
if package.state in ('to install', 'to upgrade'):
init_module_models(cr, package.name, models)
pool._init_modules.add(package.name)
status['progress'] = float(index) / len(graph)
@ -171,18 +172,19 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
idref = {}
mode = 'update'
if hasattr(package, 'init') or package.state == 'to install':
if package.state == 'to install':
mode = 'init'
else:
mode = 'update'
if hasattr(package, 'init') or hasattr(package, 'update') or package.state in ('to install', 'to upgrade'):
if package.state in ('to install', 'to upgrade'):
if package.state=='to upgrade':
# upgrading the module information
modobj.write(cr, SUPERUSER_ID, [module_id], modobj.get_values_from_terp(package.data))
load_init_xml(module_name, idref, mode)
load_update_xml(module_name, idref, mode)
load_data(module_name, idref, mode)
if hasattr(package, 'demo') or (package.dbdemo and package.state != 'installed'):
if package.dbdemo and package.state != 'installed':
status['progress'] = (index + 0.75) / len(graph)
load_demo_xml(module_name, idref, mode)
load_demo(module_name, idref, mode)
@ -212,9 +214,6 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
modobj.update_translations(cr, SUPERUSER_ID, [module_id], None)
package.state = 'installed'
for kind in ('init', 'demo', 'update'):
if hasattr(package, kind):
delattr(package, kind)
cr.commit()
@ -269,10 +268,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
if not openerp.modules.db.is_initialized(cr):
_logger.info("init db")
openerp.modules.db.initialize(cr)
tools.config["init"]["all"] = 1
tools.config['update']['all'] = 1
if not tools.config['without_demo']:
tools.config["demo"]['all'] = 1
update_module = True
# This is a brand new pool, just created in pooler.get_db_and_pool()
pool = pooler.get_pool(cr.dbname)
@ -282,43 +278,51 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
# STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps)
graph = openerp.modules.graph.Graph()
graph.add_module(cr, 'base', force)
graph.add_module(cr, 'base', force_demo)
if not graph:
_logger.critical('module base cannot be loaded! (hint: verify addons-path)')
raise osv.osv.except_osv(_('Could not load base module'), _('module base cannot be loaded! (hint: verify addons-path)'))
# processed_modules: for cleanup step after install
# loaded_modules: to avoid double loading
report = pool._assertion_report
loaded_modules, processed_modules = load_module_graph(cr, graph, status, perform_checks=(not update_module), report=report)
# After load_module_graph(), 'base' has been installed or updated and its state is 'installed'.
report = assertion_report.assertion_report()
loaded_modules, processed_modules = load_module_graph(cr, graph, status, report=report)
if tools.config['load_language']:
for lang in tools.config['load_language'].split(','):
tools.load_language(cr, lang)
# STEP 2: Mark other modules to be loaded/updated
# This is a one-shot use of tools.config[init|update] from the command line
# arguments. It is directly cleared to not interfer with later create/update
# issued via RPC.
if update_module:
modobj = pool.get('ir.module.module')
if ('base' in tools.config['init']) or ('base' in tools.config['update']):
if ('base' in tools.config['init']) or ('base' in tools.config['update']) \
or ('all' in tools.config['init']) or ('all' in tools.config['update']):
_logger.info('updating modules list')
modobj.update_list(cr, SUPERUSER_ID)
if 'all' in tools.config['init']:
ids = modobj.search(cr, 1, [])
tools.config['init'] = dict.fromkeys([m['name'] for m in modobj.read(cr, 1, ids, ['name'])], 1)
_check_module_names(cr, itertools.chain(tools.config['init'].keys(), tools.config['update'].keys()))
mods = [k for k in tools.config['init'] if tools.config['init'][k]]
if mods:
ids = modobj.search(cr, SUPERUSER_ID, ['&', ('state', '=', 'uninstalled'), ('name', 'in', mods)])
if ids:
modobj.button_install(cr, SUPERUSER_ID, ids)
mods = [k for k in tools.config['init'] if tools.config['init'][k] and k not in ('base', 'all')]
ids = modobj.search(cr, SUPERUSER_ID, ['&', ('state', '=', 'uninstalled'), ('name', 'in', mods)])
if ids:
modobj.button_install(cr, SUPERUSER_ID, ids) # goes from 'uninstalled' to 'to install'
mods = [k for k in tools.config['update'] if tools.config['update'][k]]
if mods:
ids = modobj.search(cr, SUPERUSER_ID, ['&', ('state', '=', 'installed'), ('name', 'in', mods)])
if ids:
modobj.button_upgrade(cr, SUPERUSER_ID, ids)
cr.execute("update ir_module_module set state=%s where name=%s", ('installed', 'base'))
mods = [k for k in tools.config['update'] if tools.config['update'][k] and k not in ('base', 'all')]
ids = modobj.search(cr, SUPERUSER_ID, ['&', ('state', '=', 'installed'), ('name', 'in', mods)])
if ids:
modobj.button_upgrade(cr, SUPERUSER_ID, ids) # goes from 'installed' to 'to upgrade'
# Remove that funky global one-shot thingy.
for kind in ('init', 'demo', 'update'):
tools.config[kind] = {}
# STEP 3: Load marked modules (skipping base which was done in STEP 1)
# IMPORTANT: this is done in two parts, first loading all installed or
@ -370,9 +374,6 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
# Cleanup orphan records
pool.get('ir.model.data')._process_end(cr, SUPERUSER_ID, processed_modules)
for kind in ('init', 'demo', 'update'):
tools.config[kind] = {}
cr.commit()
# STEP 5: Cleanup menus

View File

@ -205,10 +205,15 @@ class db(netsvc.ExportService):
# Try to terminate all other connections that might prevent
# dropping the database
try:
cr.execute("""SELECT pg_terminate_backend(procpid)
# PostgreSQL 9.2 renamed pg_stat_activity.procpid to pid:
# http://www.postgresql.org/docs/9.2/static/release-9-2.html#AEN110389
pid_col = 'pid' if cr._cnx.server_version >= 90200 else 'procpid'
cr.execute("""SELECT pg_terminate_backend(%(pid_col)s)
FROM pg_stat_activity
WHERE datname = %s AND
procpid != pg_backend_pid()""",
WHERE datname = %%s AND
%(pid_col)s != pg_backend_pid()""" % {'pid_col': pid_col},
(db_name,))
except Exception:
pass

View File

@ -1140,6 +1140,10 @@ class test_datetime(ImporterCase):
""" If there is no tz either in the context or on the user, falls back
to UTC
"""
self.registry('res.users').write(
self.cr, openerp.SUPERUSER_ID, [openerp.SUPERUSER_ID],
{'tz': False})
result = self.import_(['value'], [['2012-02-03 11:11:11']])
self.assertFalse(result['messages'])
self.assertEqual(

View File

@ -46,6 +46,8 @@ def _eval_expr(cr, ident, workitem, action):
assert action, 'You used a NULL action in a workflow, use dummy node instead.'
for line in action.split('\n'):
line = line.strip()
if not line:
continue
uid=ident[0]
model=ident[1]
ids=[ident[2]]