This commit is contained in:
Nicolas Évrard
2011-07-20 18:38:11 +02:00
88 changed files with 1709 additions and 1063 deletions
+3
View File
@@ -1,3 +1,6 @@
* Drop support of Python 2.5
* Remove support of Many2Many field in record XML
* Change Pool into a Singleton
* Remove support of zipped modules
Version 2.0.0 - 2011-04-26
+3
View File
@@ -37,6 +37,8 @@ def parse_commandline():
help="file where the server pid will be stored")
parser.add_option("--logfile", dest="logfile",
help="file where the server log will be stored")
parser.add_option("--disable-cron", dest="cron",
action="store_false", help="disable cron")
(opt, _) = parser.parse_args()
@@ -51,6 +53,7 @@ def parse_commandline():
'debug_mode',
'pidfile',
'logfile',
'cron',
):
if getattr(opt, arg) is not None:
options[arg] = getattr(opt, arg)
+2 -2
View File
@@ -508,7 +508,7 @@ A many-to-many relation field.
Instance methods:
.. method:: Many2Many.get_target(pool)
.. method:: Many2Many.get_target()
Return the target :class:`~trytond.model.Model`.
@@ -530,7 +530,7 @@ A one-to-one relation field.
Instance methods:
.. method:: One2One.get_target(pool)
.. method:: One2One.get_target()
Return the target :class:`~trytond.model.Model`.
+1 -1
View File
@@ -7,7 +7,7 @@ How to install Tryton
Prerequisites
=============
* Python 2.5 or later (http://www.python.org/)
* Python 2.6 or later (http://www.python.org/)
* lxml 2.0 or later (http://codespeak.net/lxml/)
* relatorio 0.2.0 or later (http://relatorio.openhex.org/)
* python-dateutil (http://labix.org/python-dateutil)
+2 -2
View File
@@ -61,7 +61,7 @@ When defining an `ir.action.report` the following attributes are available:
* ``name``: The name of the report.
* ``report_name``: The name of the report model, for example
my_module.my_report. This is the name you would use with `pool.get`
my_module.my_report. This is the name you would use with `Pool().get`
* ``module_name``: If this report is of an existing model this is its name.
For example my_module.my_model. Custom reports that aren't of a specific
@@ -228,7 +228,7 @@ context. Now the invoice report will be able to access the employee object.
class InvoiceReport(Report):
_name = 'account.invoice'
def parse(self, report, objects, datas, localcontext):
employee_obj = self.pool.get('company.employee')
employee_obj = Pool().get('company.employee')
employee = False
if Transaction().context.get('employee'):
employee = employee_obj.browse(Transaction().context['employee'])
+3
View File
@@ -90,3 +90,6 @@
# Prevent database listing
#prevent_dblist = False
# Enable cron
# cron = True
+1 -6
View File
@@ -8,10 +8,6 @@ import sys
execfile(os.path.join('trytond', 'version.py'))
SIMPLEJSON = []
if sys.version_info < (2, 6):
SIMPLEJSON = ['simplejson']
def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
@@ -52,7 +48,6 @@ setup(name=PACKAGE,
'Natural Language :: Russian',
'Natural Language :: Spanish',
'Operating System :: OS Independent',
'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Topic :: Software Development :: Libraries :: Application Frameworks',
@@ -63,7 +58,7 @@ setup(name=PACKAGE,
'relatorio >= 0.2.0',
'Genshi',
'python-dateutil',
] + SIMPLEJSON,
],
extras_require={
'PostgreSQL': ['psycopg2 >= 2.0'],
'MySQL': ['MySQL-python'],
+6 -2
View File
@@ -1,5 +1,6 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from trytond.const import CONTEXT_CACHE_SIZE, MODEL_CACHE_SIZE
DatabaseIntegrityError = None
DatabaseOperationalError = None
@@ -103,7 +104,8 @@ class CursorInterface(object):
IN_MAX = 1000
def __init__(self):
self.cache = {}
from trytond.cache import LRUDict
self.cache = LRUDict(CONTEXT_CACHE_SIZE)
def get_cache(self, context=None):
'''
@@ -112,6 +114,7 @@ class CursorInterface(object):
:param context: the context
:return: the cache dictionary
'''
from trytond.cache import LRUDict
if context is None:
context = {}
cache_ctx = context.copy()
@@ -119,7 +122,8 @@ class CursorInterface(object):
'_delete_records'):
if i in cache_ctx:
del cache_ctx[i]
return self.cache.setdefault(repr(cache_ctx), {})
return self.cache.setdefault(repr(cache_ctx),
LRUDict(MODEL_CACHE_SIZE))
def execute(self, sql, params=None):
'''
-1
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
from trytond.backend.database import DatabaseInterface, CursorInterface
from trytond.config import CONFIG
import MySQLdb
+4 -4
View File
@@ -84,10 +84,10 @@ CREATE TABLE res_group (
) ENGINE=InnoDB;
CREATE TABLE `res_user-res_group` (
uid BIGINT NOT NULL,
gid BIGINT NOT NULL,
CONSTRAINT `res_user-res_group_uid_fkey` FOREIGN KEY (uid) REFERENCES res_user (id) ON DELETE CASCADE,
CONSTRAINT `res_user-res_group_gid_fkey` FOREIGN KEY (gid) REFERENCES res_group (id) ON DELETE CASCADE
`user` BIGINT NOT NULL,
`group` BIGINT NOT NULL,
CONSTRAINT `res_user-res_group_user_fkey` FOREIGN KEY (`user`) REFERENCES res_user (id) ON DELETE CASCADE,
CONSTRAINT `res_user-res_group_group_fkey` FOREIGN KEY (`group`) REFERENCES res_group (id) ON DELETE CASCADE
) ENGINE=InnoDB;
CREATE TABLE wkf (
-1
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
from trytond.backend.database import DatabaseInterface, CursorInterface
from trytond.config import CONFIG
from trytond.session import Session
+4 -4
View File
@@ -102,10 +102,10 @@ CREATE SEQUENCE "res_user-res_group_id_seq";
CREATE TABLE "res_user-res_group" (
id INTEGER DEFAULT NEXTVAL('res_user-res_group_id_seq') NOT NULL,
uid INTEGER NOT NULL,
gid INTEGER NOT NULL,
FOREIGN KEY (uid) REFERENCES res_user (id) ON DELETE CASCADE,
FOREIGN KEY (gid) REFERENCES res_group (id) ON DELETE CASCADE,
"user" INTEGER NOT NULL,
"group" INTEGER NOT NULL,
FOREIGN KEY ("user") REFERENCES res_user (id) ON DELETE CASCADE,
FOREIGN KEY ("group") REFERENCES res_group (id) ON DELETE CASCADE,
PRIMARY KEY(id)
);
+8 -6
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
from trytond.backend.database import DatabaseInterface, CursorInterface
from trytond.config import CONFIG
from trytond.session import Session
@@ -9,6 +8,7 @@ import re
from decimal import Decimal
import datetime
import time
import sys
_FIX_ROWCOUNT = False
try:
@@ -144,10 +144,9 @@ class Database(DatabaseInterface):
return
path = os.path.join(CONFIG['data_path'],
database_name + '.sqlite')
conn = sqlite.connect(path)
cursor = conn.cursor()
cursor.close()
conn.close()
with sqlite.connect(path) as conn:
cursor = conn.cursor()
cursor.close()
def drop(self, cursor, database_name):
if database_name == ':memory:':
@@ -358,7 +357,10 @@ class Cursor(CursorInterface):
return select
sqlite.register_converter('NUMERIC', lambda val: Decimal(val))
sqlite.register_adapter(Decimal, lambda val: buffer(str(val)))
if sys.version_info[0] == 2:
sqlite.register_adapter(Decimal, lambda val: buffer(str(val)))
else:
sqlite.register_adapter(Decimal, lambda val: bytes(str(val)))
sqlite.register_adapter(Session, int)
def adapt_datetime(val):
return val.replace(tzinfo=None).isoformat(" ")
+2 -2
View File
@@ -73,8 +73,8 @@ CREATE TABLE res_group (
CREATE TABLE "res_user-res_group" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uid INTEGER,
gid INTEGER
"user" INTEGER,
"group" INTEGER
);
CREATE TABLE wkf (
+1 -1
View File
@@ -127,7 +127,7 @@ class TableHandler(TableHandlerInterface):
match = re.match(r'(\w+)(\((.*?)\))?', type_)
if match:
typname = match.group(1).upper()
size = match.group(3) and int(match.group(3)) or None
size = match.group(3) and int(match.group(3)) or 0
else:
typname = type_.upper()
size = -1
+30
View File
@@ -7,6 +7,7 @@ from threading import Lock
from trytond.transaction import Transaction
from trytond.config import CONFIG
from trytond.backend import Database
from trytond.tools import OrderedDict
class Cache(object):
@@ -167,3 +168,32 @@ class Cache(object):
cursor.commit()
cursor.close()
Cache._resets_lock.release()
class LRUDict(OrderedDict):
"""
Dictionary with a size limit.
If size limit is reached, it will remove the first added items.
"""
def __init__(self, size_limit, *args, **kwargs):
assert size_limit > 0
self.size_limit = size_limit
super(LRUDict, self).__init__(*args, **kwargs)
self._check_size_limit()
def __setitem__(self, key, value):
super(LRUDict, self).__setitem__(key, value)
self._check_size_limit()
def update(self, *args, **kwargs):
super(LRUDict, self).update(*args, **kwargs)
self._check_size_limit()
def setdefault(self, key, default=None):
default = super(LRUDict, self).setdefault(key, default=default)
self._check_size_limit()
return default
def _check_size_limit(self):
while len(self) > self.size_limit:
self.popitem(last=False)
+2 -4
View File
@@ -51,6 +51,7 @@ class ConfigManager(object):
'prevent_dblist': False,
'init': {},
'update': {},
'cron': True,
}
self.configfile = None
@@ -82,12 +83,9 @@ class ConfigManager(object):
if not self.configfile:
return
fp = open(self.configfile)
parser = ConfigParser.ConfigParser()
try:
with open(self.configfile) as fp:
parser.readfp(fp)
finally:
fp.close()
for (name, value) in parser.items('options'):
if value == 'True' or value == 'true':
value = True
+3
View File
@@ -18,4 +18,7 @@ OPERATORS = (
'>',
)
CONTEXT_CACHE_SIZE = 10
MODEL_CACHE_SIZE = 200
RECORD_CACHE_SIZE = 2000
BROWSE_FIELD_TRESHOLD = 100
+7 -40
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import time
from xml import sax
from decimal import Decimal
@@ -110,16 +109,7 @@ class MenuitemTagHandler:
values['icon'] = 'tryton-new'
if values.get('groups'):
g_names = values['groups'].split(',')
groups_value = []
for group in g_names:
if group.startswith('-'):
group_id = self.mh.get_id(group[1:])
groups_value.append(('remove', group_id))
else:
group_id = self.mh.get_id(group)
groups_value.append(('add', group_id))
values['groups'] = groups_value
raise Exception("Please use separate records for groups")
if not values.get('name'):
if not action_name:
@@ -205,17 +195,8 @@ class RecordTagHandler:
search_model = self.model._columns[field_name].model_name
f_obj = self.mh.pool.get(search_model)
with Transaction().set_context(active_test=False):
answer = f_obj.browse(f_obj.search(safe_eval(search_attr)))
if not answer: return
if self.model._columns[field_name]._type == 'many2many':
self.values[field_name] = [
('set', [x['id'] for x in answer]),
]
elif self.model._columns[field_name]._type == 'many2one':
self.values[field_name] = answer[0]['id']
self.values[field_name], = \
f_obj.search(safe_eval(search_attr))
elif ref_attr:
self.values[field_name] = self.mh.get_id(ref_attr)
@@ -527,7 +508,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
ref_id = ref_id[0]
return ref_mode + ',' + str(ref_id)
elif field_type in ['one2many', 'many2many']:
raise Unhandled_field()
raise Unhandled_field("Unhandled field %s" % key)
else:
return browse_record[key]
@@ -695,13 +676,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
to_update = {}
for key in values:
try:
db_field = self._clean_value(key, db_val, object_ref)
except Unhandled_field:
logging.getLogger("convert").info(
'Field %s on %s : integrity not tested.'%(key, model))
to_update[key] = values[key]
continue
db_field = self._clean_value(key, db_val, object_ref)
# if the fs value is the same has in the db, whe ignore it
val = values[key]
@@ -813,11 +788,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
if not db_val:
db_val = object_ref.browse(db_id)
for key in to_update:
try:
values[key] = self._clean_value(
key, db_val, object_ref)
except Unhandled_field:
continue
values[key] = self._clean_value( key, db_val, object_ref)
if module != self.module:
temp_values = old_values.copy()
@@ -904,11 +875,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
# in the model_data table:
db_val = object_ref.browse(db_id)
for key in values:
try:
values[key] = self._clean_value(key, db_val,
object_ref)
except Unhandled_field:
continue
values[key] = self._clean_value(key, db_val, object_ref)
for table in inherit_db_ids.keys():
self.modeldata_obj.create({
+3 -2
View File
@@ -1,6 +1,7 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from trytond.transaction import Transaction
from trytond.pool import Pool
class WarningErrorMixin(object):
@@ -24,7 +25,7 @@ class WarningErrorMixin(object):
(or tuple if error_description is not empty) instead of raising an
exception.
'''
translation_obj = self.pool.get('ir.translation')
translation_obj = Pool().get('ir.translation')
error = self._error_messages.get(error, error)
@@ -92,7 +93,7 @@ class WarningErrorMixin(object):
:param warning_description_args: the arguments that will be used
for "%"-based substitution
'''
warning_obj = self.pool.get('res.user.warning')
warning_obj = Pool().get('res.user.warning')
if warning_obj.check(warning_name):
if warning_description:
warning, warning_description = self.raise_user_error(warning,
+27 -15
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import base64
import os
from trytond.model import ModelView, ModelSQL, ModelStorage, fields
@@ -9,6 +8,7 @@ from trytond.backend import TableHandler
from trytond.pyson import PYSONEncoder, CONTEXT, PYSON
from trytond.transaction import Transaction
from trytond.cache import Cache
from trytond.pool import Pool
class Action(ModelSQL, ModelView):
@@ -20,7 +20,7 @@ class Action(ModelSQL, ModelView):
usage = fields.Char('Usage')
keywords = fields.One2Many('ir.action.keyword', 'action',
'Keywords')
groups = fields.Many2Many('ir.action-res.group', 'action_id', 'gid',
groups = fields.Many2Many('ir.action-res.group', 'action', 'group',
'Groups')
icon = fields.Many2One('ir.ui.icon', 'Icon')
active = fields.Boolean('Active', select=2)
@@ -38,6 +38,7 @@ class Action(ModelSQL, ModelView):
return True
def get_action_id(self, action_id):
pool = Pool()
with Transaction().set_context(active_test=False):
if self.search([
('id', '=', action_id),
@@ -49,7 +50,7 @@ class Action(ModelSQL, ModelView):
'ir.action.wizard',
'ir.action.url',
):
action_obj = self.pool.get(action_type)
action_obj = pool.get(action_type)
action_id2 = action_obj.search([
('id', '=', action_id),
])
@@ -88,7 +89,8 @@ class ActionKeyword(ModelSQL, ModelView):
})
def check_wizard_model(self, ids):
action_wizard_obj = self.pool.get('ir.action.wizard')
pool = Pool()
action_wizard_obj = pool.get('ir.action.wizard')
for action_keyword in self.browse(ids):
if action_keyword.action.type == 'ir.action.wizard':
action_wizard_id = action_wizard_obj.search([
@@ -103,13 +105,15 @@ class ActionKeyword(ModelSQL, ModelView):
def _convert_vals(self, vals):
vals = vals.copy()
action_obj = self.pool.get('ir.action')
pool = Pool()
action_obj = pool.get('ir.action')
if 'action' in vals:
vals['action'] = action_obj.get_action_id(vals['action'])
return vals
def models_get(self):
model_obj = self.pool.get('ir.model')
pool = Pool()
model_obj = pool.get('ir.model')
model_ids = model_obj.search([])
res = []
for model in model_obj.browse(model_ids):
@@ -117,36 +121,39 @@ class ActionKeyword(ModelSQL, ModelView):
return res
def delete(self, ids):
pool = Pool()
if isinstance(ids, (int, long)):
ids = [ids]
for keyword in self.browse(ids):
# Restart the cache view
try:
self.pool.get(keyword.model.split(',')[0]
pool.get(keyword.model.split(',')[0]
).fields_view_get.reset()
except Exception:
pass
return super(ActionKeyword, self).delete(ids)
def create(self, vals):
pool = Pool()
vals = self._convert_vals(vals)
if 'model' in vals:
# Restart the cache view
try:
self.pool.get(vals['model'].split(',')[0]
pool.get(vals['model'].split(',')[0]
).fields_view_get.reset()
except Exception:
pass
return super(ActionKeyword, self).create(vals)
def write(self, ids, vals):
pool = Pool()
vals = self._convert_vals(vals)
if isinstance(ids, (int, long)):
ids = [ids]
for keyword in self.browse(ids):
# Restart the cache view
try:
self.pool.get(keyword.model.split(',')[0]
pool.get(keyword.model.split(',')[0]
).fields_view_get.reset()
except Exception:
pass
@@ -154,13 +161,14 @@ class ActionKeyword(ModelSQL, ModelView):
for keyword in self.browse(ids):
# Restart the cache view
try:
self.pool.get(keyword.model.split(',')[0]
pool.get(keyword.model.split(',')[0]
).fields_view_get.reset()
except Exception:
pass
return res
def get_keyword(self, keyword, value):
pool = Pool()
res = []
model, model_id = value
@@ -176,7 +184,7 @@ class ActionKeyword(ModelSQL, ModelView):
]))
for action_keyword in self.browse(action_keyword_ids):
try:
action_obj = self.pool.get(action_keyword.action.type)
action_obj = pool.get(action_keyword.action.type)
except Exception:
continue
action_id = action_obj.search([
@@ -369,7 +377,8 @@ class ActionReport(ModelSQL, ModelView):
return super(ActionReport, self).write(ids, vals)
def delete(self, ids):
action_obj = self.pool.get('ir.action')
pool = Pool()
action_obj = pool.get('ir.action')
if isinstance(ids, (int, long)):
ids = [ids]
@@ -563,7 +572,8 @@ class ActionActWindow(ModelSQL, ModelView):
return new_id
def delete(self, ids):
action_obj = self.pool.get('ir.action')
pool = Pool()
action_obj = pool.get('ir.action')
if isinstance(ids, (int, long)):
ids = [ids]
@@ -639,7 +649,8 @@ class ActionWizard(ModelSQL, ModelView):
return new_id
def delete(self, ids):
action_obj = self.pool.get('ir.action')
pool = Pool()
action_obj = pool.get('ir.action')
if isinstance(ids, (int, long)):
ids = [ids]
@@ -773,7 +784,8 @@ class ActionURL(ModelSQL, ModelView):
return new_id
def delete(self, ids):
action_obj = self.pool.get('ir.action')
pool = Pool()
action_obj = pool.get('ir.action')
if isinstance(ids, (int, long)):
ids = [ids]
-5
View File
@@ -33,7 +33,6 @@ this repository contains the full copyright notices and license terms. -->
</field>
</page>
<page name="groups">
<separator name="groups" colspan="4"/>
<field name="groups" colspan="4"/>
</page>
</notebook>
@@ -119,7 +118,6 @@ this repository contains the full copyright notices and license terms. -->
</field>
</page>
<page name="groups">
<separator name="groups" colspan="4"/>
<field name="groups" colspan="4"/>
</page>
</notebook>
@@ -218,7 +216,6 @@ this repository contains the full copyright notices and license terms. -->
</field>
</page>
<page name="groups">
<separator name="groups" colspan="4"/>
<field name="groups" colspan="4"/>
</page>
</notebook>
@@ -294,7 +291,6 @@ this repository contains the full copyright notices and license terms. -->
</field>
</page>
<page name="groups">
<separator name="groups" colspan="4"/>
<field name="groups" colspan="4"/>
</page>
</notebook>
@@ -423,7 +419,6 @@ this repository contains the full copyright notices and license terms. -->
</field>
</page>
<page name="groups">
<separator name="groups" colspan="4"/>
<field name="groups" colspan="4"/>
</page>
</notebook>
+8 -5
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import os
try:
import hashlib
@@ -13,6 +12,7 @@ from trytond.config import CONFIG
from trytond.backend import TableHandler
from trytond.transaction import Transaction
from trytond.pyson import Not, Equal, Eval
from trytond.pool import Pool
def firstline(description):
try:
@@ -84,7 +84,8 @@ class Attachment(ModelSQL, ModelView):
return 0
def models_get(self):
model_obj = self.pool.get('ir.model')
pool = Pool()
model_obj = pool.get('ir.model')
model_ids = model_obj.search([])
res = []
for model in model_obj.browse(model_ids):
@@ -189,7 +190,8 @@ class Attachment(ModelSQL, ModelView):
def check_access(self, ids, mode='read'):
model_access_obj = self.pool.get('ir.model.access')
pool = Pool()
model_access_obj = pool.get('ir.model.access')
if Transaction().user == 0:
return
if not ids:
@@ -224,7 +226,8 @@ class Attachment(ModelSQL, ModelView):
return res
def view_header_get(self, value, view_type='form'):
ir_model_obj = self.pool.get('ir.model')
pool = Pool()
ir_model_obj = pool.get('ir.model')
value = super(Attachment, self).view_header_get(value,
view_type=view_type)
resource = Transaction().context.get('resource')
@@ -232,7 +235,7 @@ class Attachment(ModelSQL, ModelView):
model_name, record_id = resource.split(',', 1)
ir_model_id, = ir_model_obj.search([('model', '=', model_name)])
ir_model = ir_model_obj.browse(ir_model_id)
model_obj = self.pool.get(model_name)
model_obj = pool.get(model_name)
record = model_obj.browse(int(record_id))
value = '%s - %s - %s' % (ir_model.name, record.rec_name, value)
return value
+109 -114
View File
@@ -1,18 +1,19 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import contextlib
import datetime
from dateutil.relativedelta import relativedelta
import traceback
import sys
import logging
from trytond.backend import Database
from trytond.model import ModelView, ModelSQL, fields
from trytond.tools import safe_eval
from trytond.transaction import Transaction
from trytond.pool import Pool
from trytond.backend import TableHandler
_INTERVALTYPES = {
'work_days': lambda interval: relativedelta(days=interval),
'days': lambda interval: relativedelta(days=interval),
'hours': lambda interval: relativedelta(hours=interval),
'weeks': lambda interval: relativedelta(weeks=interval),
@@ -26,7 +27,8 @@ class Cron(ModelSQL, ModelView):
_description = __doc__
name = fields.Char('Name', required=True, translate=True)
user = fields.Many2One('res.user', 'Execution User', required=True,
help="The user used to execute this action")
domain=[('active', '=', False)],
help="The user used to execute this action")
request_user = fields.Many2One(
'res.user', 'Request User', required=True,
help="The user who will receive requests in case of failure")
@@ -35,24 +37,20 @@ class Cron(ModelSQL, ModelView):
interval_type = fields.Selection( [
('minutes', 'Minutes'),
('hours', 'Hours'),
('work_days', 'Work Days'),
('days', 'Days'),
('weeks', 'Weeks'),
('months', 'Months'),
], 'Interval Unit')
numbercall = fields.Integer('Number of calls', select=1,
help='Number of times the function is called,\n' \
'a negative number indicates that the function ' \
'will always be called')
doall = fields.Boolean('Repeat missed')
nextcall = fields.DateTime('Next call date', required=True,
number_calls = fields.Integer('Number of Calls', select=1,
help=('Number of times the function is called, a negative '
'number indicates that the function will always be '
'called'))
repeat_missed = fields.Boolean('Repeat Missed')
next_call = fields.DateTime('Next Call', required=True,
select=1)
model = fields.Char('Model')
function = fields.Char('Function')
args = fields.Text('Arguments')
priority = fields.Integer('Priority',
help='0=Very Urgent\n10=Not urgent')
running = fields.Boolean('Running', readonly=True, select=1)
def __init__(self):
super(Cron, self).__init__()
@@ -62,135 +60,132 @@ class Cron(ModelSQL, ModelView):
"properly: \"%s\"\n Traceback: \n\n%s\n"
})
def default_nextcall(self):
def init(self, module_name):
cursor = Transaction().cursor
# Migration from 2.0: rename numbercall, doall and nextcall
table = TableHandler(cursor, self, module_name)
table.column_rename('numbercall', 'number_calls')
table.column_rename('doall', 'repeat_missed')
table.column_rename('nextcall', 'next_call')
super(Cron, self).init(module_name)
# Migration from 2.0: work_days removed
cursor.execute('UPDATE "%s" '
'SET interval_type = %%s '
'WHERE interval_type = %%s' % self._table,
('days', 'work_days'))
def default_next_call(self):
return datetime.datetime.now()
def default_priority(self):
return 5
def default_user(self):
return int(Transaction().user)
def default_interval_number(self):
return 1
def default_interval_type(self):
return 'months'
def default_numbercall(self):
return 1
def default_number_calls(self):
return -1
def default_active(self):
return True
def default_doall(self):
def default_repeat_missed(self):
return True
def default_running(self):
return False
def check_xml_record(self, ids, values):
return True
def get_delta(self, cron):
'''
Return the relativedelta for the next call
'''
return _INTERVALTYPES[cron.interval_type](cron.interval_number)
def _get_request_values(self, cron):
tb_s = reduce(lambda x, y: x + y,
traceback.format_exception(*sys.exc_info()))
tb_s = tb_s.decode('utf-8', 'ignore')
name = self.raise_user_error('request_title',
raise_exception=False)
body = self.raise_user_error('request_body', (cron.name, tb_s),
raise_exception=False)
values = {
'name': name,
'priority': '2',
'act_from': cron.user.id,
'act_to': cron.request_user.id,
'body': body,
'date_sent': datetime.datetime.now(),
'references': [
('create', {
'reference': '%s,%s' % (self._name, cron.id),
}),
],
'state': 'waiting',
'trigger_date': datetime.datetime.now(),
}
return values
def _callback(self, cron):
pool = Pool()
try:
args = (cron['args'] or []) and safe_eval(cron['args'])
obj = self.pool.get(cron['model'])
if not obj and hasattr(obj, cron['function']):
return False
fct = getattr(obj, cron['function'])
with Transaction().set_user(cron['user']):
fct(*args)
args = (cron.args or []) and safe_eval(cron.args)
model_obj = pool.get(cron.model)
with Transaction().set_user(cron.user.id):
getattr(model_obj, cron.function)(*args)
except Exception, error:
Transaction().cursor.rollback()
tb_s = ''
for line in traceback.format_exception(*sys.exc_info()):
try:
line = line.encode('utf-8', 'ignore')
except Exception:
continue
tb_s += line
try:
tb_s += str(error).decode('utf-8', 'ignore')
except Exception:
pass
request_obj = pool.get('res.request')
req_user = cron.request_user
language = (req_user.language.code if req_user.language
else 'en_US')
with contextlib.nested(Transaction().set_user(cron.user.id),
Transaction().set_context(language=language)):
values = self._get_request_values(cron)
rid = request_obj.create(values)
Transaction().cursor.commit()
request_obj = self.pool.get('res.request')
try:
user_obj = self.pool.get('res.user')
req_user = user_obj.browse(cron['request_user'])
language = (req_user.language.code if req_user.language
else 'en_US')
with contextlib.nested(Transaction().set_user(cron['user']),
Transaction().set_context(language=language)):
rid = request_obj.create({
'name': self.raise_user_error('request_title',
raise_exception=False),
'priority': '2',
'act_from': cron['user'],
'act_to': cron['request_user'],
'body': self.raise_user_error('request_body',
(cron['name'], tb_s), raise_exception=False),
'date_sent': datetime.datetime.now(),
'references': [
('create', {
'reference': "ir.cron,%s" % cron['id'],
}),
],
'state': 'waiting',
'trigger_date': datetime.datetime.now(),
})
Transaction().cursor.commit()
except Exception:
Transaction().cursor.rollback()
def pool_jobs(self, db_name):
def run(self, db_name):
now = datetime.datetime.now()
with Transaction().start(db_name, 0) as transaction:
try:
transaction.cursor.lock(self._table)
transaction.cursor.execute('SELECT * FROM ir_cron '
'WHERE numbercall <> 0 '
'AND active '
'AND nextcall <= %s '
'AND NOT running '
'ORDER BY priority', (datetime.datetime.now(),))
crons = transaction.cursor.dictfetchall()
transaction.cursor.lock(self._table)
cron_ids = self.search([
('number_calls', '!=', 0),
('next_call', '<=', datetime.datetime.now()),
])
crons = self.browse(cron_ids)
for cron in crons:
transaction.cursor.execute('UPDATE ir_cron '
'SET running = %s '
'WHERE id = %s', (True, cron['id']))
nextcall = cron['nextcall']
numbercall = cron['numbercall']
done = False
while nextcall < now and numbercall:
if numbercall > 0:
numbercall -= 1
if not done or cron['doall']:
for cron in crons:
try:
next_call = cron.next_call
number_calls = cron.number_calls
first = True
while next_call < now and number_calls != 0:
if first or cron.repeat_missed:
self._callback(cron)
if numbercall:
nextcall += _INTERVALTYPES[cron['interval_type']](
cron['interval_number'])
done = True
next_call += self.get_delta(cron)
if number_calls > 0:
number_calls -= 1
first = False
addsql = ''
addsql_param = []
if not numbercall:
addsql = ', active = %s'
addsql_param = [False]
transaction.cursor.execute("UPDATE ir_cron "
"SET nextcall = %s, "
"running = %s, "
"numbercall = %s" + addsql + " "
"WHERE id = %s",
[nextcall, False, numbercall] + addsql_param +
[cron['id']])
values = {
'next_call': next_call,
'number_calls': number_calls,
}
if not number_calls:
values['active'] = False
self.write(cron.id, values)
transaction.cursor.commit()
except Exception:
transaction.cursor.rollback()
raise
except Exception:
transaction.cursor.rollback()
tb_s = reduce(lambda x, y: x + y,
traceback.format_exception(*sys.exc_info()))
tb_s = tb_s.decode('utf-8', 'ignore')
logger = logging.getLogger('cron')
logger.error('Exception:\n%s' % tb_s)
Cron()
+17 -23
View File
@@ -12,16 +12,14 @@ this repository contains the full copyright notices and license terms. -->
<field name="arch" type="xml">
<![CDATA[
<tree string="Scheduled Actions">
<field name="nextcall"/>
<field name="next_call"/>
<field name="name" select="1"/>
<field name="user" select="1"/>
<field name="request_user" select="2"/>
<field name="priority" select="2"/>
<field name="interval_number"/>
<field name="interval_type"/>
<field name="numbercall" select="2"/>
<field name="number_calls" select="2"/>
<field name="active" select="2"/>
<field name="running" select="2"/>
</tree>
]]>
</field>
@@ -31,37 +29,33 @@ this repository contains the full copyright notices and license terms. -->
<field name="type">form</field>
<field name="arch" type="xml">
<![CDATA[
<form string="Scheduled Action" col="6">
<form string="Scheduled Action">
<label name="name"/>
<field name="name"/>
<label name="active"/>
<field name="active"/>
<label name="user"/>
<field name="user"/>
<label name="request_user"/>
<field name="request_user"/>
<label name="numbercall"/>
<field name="numbercall"/>
<label name="priority"/>
<field name="priority"/>
<label name="active"/>
<field name="active"/>
<label name="interval_number"/>
<field name="interval_number"/>
<label name="interval_type"/>
<field name="interval_type"/>
<label name="nextcall"/>
<field name="nextcall"/>
<label name="doall"/>
<field name="doall"/>
<separator string="Action to trigger" colspan="6"
<label name="number_calls"/>
<field name="number_calls"/>
<label name="next_call"/>
<field name="next_call"/>
<label name="repeat_missed"/>
<field name="repeat_missed"/>
<separator string="Action to trigger" colspan="4"
id="action_trigger"/>
<label name="model"/>
<field name="model" readonly="1"/>
<field name="model"/>
<label name="function"/>
<field name="function" readonly="1"/>
<label name="running"/>
<field name="running"/>
<separator name="args" colspan="6"/>
<field name="args" colspan="6" readonly="1"/>
<field name="function"/>
<label name="args"/>
<field name="args" colspan="3" widget="char"/>
</form>
]]>
</field>
@@ -69,7 +63,7 @@ this repository contains the full copyright notices and license terms. -->
<record model="ir.action.act_window" id="act_cron_form">
<field name="name">Scheduled Actions</field>
<field name="res_model">ir.cron</field>
<field name="context">{'active_test': False}</field>
<field name="context"></field>
</record>
<record model="ir.action.act_window.view"
id="act_cron_form_view1">
-1
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import time
import locale
import os
+3 -2
View File
@@ -1,12 +1,12 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import time
import datetime
from trytond.model import ModelView, ModelSQL, fields
from trytond.model.cacheable import Cacheable
from trytond.tools import safe_eval, datetime_strftime
from trytond.transaction import Transaction
from trytond.pool import Pool
from time_locale import TIME_LOCALE
from locale import CHAR_MAX
@@ -57,7 +57,8 @@ class Lang(ModelSQL, ModelView, Cacheable):
return [('name',) + clause[1:]]
def read(self, ids, fields_names=None):
translation_obj = self.pool.get('ir.translation')
pool = Pool()
translation_obj = pool.get('ir.translation')
res = super(Lang, self).read(ids, fields_names=fields_names)
if (Transaction().context.get('translate_name')
and (not fields_names or 'name' in fields_names)):
+37 -22
View File
@@ -8,6 +8,7 @@ from trytond.report import Report
from trytond.wizard import Wizard
from trytond.transaction import Transaction
from trytond.cache import Cache
from trytond.pool import Pool
IDENTIFIER = re.compile(r'^[a-zA-z_][a-zA-Z0-9_]*$')
@@ -47,21 +48,24 @@ class Model(ModelSQL, ModelView):
return True
def create(self, vals):
property_obj = self.pool.get('ir.property')
pool = Pool()
property_obj = pool.get('ir.property')
res = super(Model, self).create(vals)
# Restart the cache of models_get
property_obj.models_get.reset()
return res
def write(self, ids, vals):
property_obj = self.pool.get('ir.property')
pool = Pool()
property_obj = pool.get('ir.property')
res = super(Model, self).write(ids, vals)
# Restart the cache of models_get
property_obj.models_get.reset()
return res
def delete(self, ids):
property_obj = self.pool.get('ir.property')
pool = Pool()
property_obj = pool.get('ir.property')
res = super(Model, self).delete(ids)
# Restart the cache of models_get
property_obj.models_get.reset()
@@ -117,7 +121,8 @@ class ModelField(ModelSQL, ModelView):
return True
def read(self, ids, fields_names=None):
translation_obj = self.pool.get('ir.translation')
pool = Pool()
translation_obj = pool.get('ir.translation')
to_delete = []
if Transaction().context.get('language'):
@@ -249,8 +254,9 @@ class ModelAccess(ModelSQL, ModelView):
if Transaction().user == 0:
return True
ir_model_obj = self.pool.get('ir.model')
user_group_obj = self.pool.get('res.user-res.group')
pool = Pool()
ir_model_obj = pool.get('ir.model')
user_group_obj = pool.get('res.user-res.group')
cursor = Transaction().cursor
cursor.execute('SELECT MAX(CASE WHEN a.perm_%s THEN 1 ELSE 0 END) '
@@ -258,8 +264,8 @@ class ModelAccess(ModelSQL, ModelView):
'JOIN "%s" AS m '
'ON (a.model = m.id) '
'LEFT JOIN "%s" AS gu '
'ON (gu.gid = a."group") '
'WHERE m.model = %%s AND (gu.uid = %%s OR a."group" IS NULL)'
'ON (gu."group" = a."group") '
'WHERE m.model = %%s AND (gu."user" = %%s OR a."group" IS NULL)'
% (mode, self._table, ir_model_obj._table,
user_group_obj._table),
(model_name, Transaction().user))
@@ -275,7 +281,8 @@ class ModelAccess(ModelSQL, ModelView):
res = super(ModelAccess, self).write(ids, vals)
# Restart the cache
self.check.reset()
for _, model in self.pool.iterobject():
pool = Pool()
for _, model in pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
@@ -286,7 +293,8 @@ class ModelAccess(ModelSQL, ModelView):
res = super(ModelAccess, self).create(vals)
# Restart the cache
self.check.reset()
for _, model in self.pool.iterobject():
pool = Pool()
for _, model in pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
@@ -297,7 +305,8 @@ class ModelAccess(ModelSQL, ModelView):
res = super(ModelAccess, self).delete(ids)
# Restart the cache
self.check.reset()
for _, model in self.pool.iterobject():
pool = Pool()
for _, model in pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
@@ -359,9 +368,10 @@ class ModelFieldAccess(ModelSQL, ModelView):
return dict((x, True) for x in fields)
return True
ir_model_obj = self.pool.get('ir.model')
ir_model_field_obj = self.pool.get('ir.model.field')
user_group_obj = self.pool.get('res.user-res.group')
pool = Pool()
ir_model_obj = pool.get('ir.model')
ir_model_field_obj = pool.get('ir.model.field')
user_group_obj = pool.get('res.user-res.group')
cursor = Transaction().cursor
@@ -373,8 +383,8 @@ class ModelFieldAccess(ModelSQL, ModelView):
'JOIN "%s" AS m '
'ON (f.model = m.id) '
'LEFT JOIN "%s" AS gu '
'ON (gu.gid = a."group") '
'WHERE m.model = %%s AND (gu.uid = %%s OR a."group" IS NULL) '
'ON (gu."group" = a."group") '
'WHERE m.model = %%s AND (gu."user" = %%s OR a."group" IS NULL) '
'GROUP BY f.name'
% (mode, self._table, ir_model_field_obj._table,
ir_model_obj._table, user_group_obj._table),
@@ -394,7 +404,8 @@ class ModelFieldAccess(ModelSQL, ModelView):
res = super(ModelFieldAccess, self).write(ids, vals)
# Restart the cache
self.check.reset()
for _, model in self.pool.iterobject():
pool = Pool()
for _, model in pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
@@ -405,7 +416,8 @@ class ModelFieldAccess(ModelSQL, ModelView):
res = super(ModelFieldAccess, self).create(vals)
# Restart the cache
self.check.reset()
for _, model in self.pool.iterobject():
pool = Pool()
for _, model in pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
@@ -416,7 +428,8 @@ class ModelFieldAccess(ModelSQL, ModelView):
res = super(ModelFieldAccess, self).delete(ids)
# Restart the cache
self.check.reset()
for _, model in self.pool.iterobject():
pool = Pool()
for _, model in pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
@@ -525,8 +538,9 @@ class ModelGraph(Report):
def execute(self, ids, datas):
import pydot
model_obj = self.pool.get('ir.model')
action_report_obj = self.pool.get('ir.action.report')
pool = Pool()
model_obj = pool.get('ir.model')
action_report_obj = pool.get('ir.action.report')
if not datas['form']['filter']:
filter = None
@@ -560,7 +574,8 @@ class ModelGraph(Report):
models
'''
import pydot
model_obj = self.pool.get('ir.model')
pool = Pool()
model_obj = pool.get('ir.model')
sub_models = set()
if level > 0:
+21 -15
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import os
from trytond.model import ModelView, ModelSQL, fields
import trytond.tools as tools
@@ -216,7 +215,8 @@ class Module(ModelSQL, ModelView):
# update the list of available packages
def update_list(self):
lang_obj = self.pool.get('ir.lang')
pool = Pool()
lang_obj = pool.get('ir.lang')
res = 0
with Transaction().set_context(language=False):
lang_ids = lang_obj.search([
@@ -313,7 +313,8 @@ class Module(ModelSQL, ModelView):
return res
def _update_dependencies(self, module, depends=None):
dependency_obj = self.pool.get('ir.module.module.dependency')
pool = Pool()
dependency_obj = pool.get('ir.module.module.dependency')
dependency_obj.delete([x.id for x in module.dependencies
if x.name not in depends])
if depends is None:
@@ -354,7 +355,8 @@ class ModuleDependency(ModelSQL, ModelView):
def get_state(self, ids, name):
result = {}
module_obj = self.pool.get('ir.module.module')
pool = Pool()
module_obj = pool.get('ir.module.module')
for dependency in self.browse(ids):
ids = module_obj.search([
('name', '=', dependency.name),
@@ -442,7 +444,8 @@ class ModuleConfigWizard(Wizard):
return res
def _action_wizard(self, data):
item_obj = self.pool.get('ir.module.module.config_wizard.item')
pool = Pool()
item_obj = pool.get('ir.module.module.config_wizard.item')
item_ids = item_obj.search([
('state', '=', 'open'),
], limit=1)
@@ -458,7 +461,8 @@ class ModuleConfigWizard(Wizard):
return {}
def _next(self, data):
item_obj = self.pool.get('ir.module.module.config_wizard.item')
pool = Pool()
item_obj = pool.get('ir.module.module.config_wizard.item')
item_ids = item_obj.search([
('state', '=', 'open'),
])
@@ -491,7 +495,8 @@ class ModuleInstallUpgrade(Wizard):
_name = 'ir.module.module.install_upgrade'
def _get_install(self, data):
module_obj = self.pool.get('ir.module.module')
pool = Pool()
module_obj = pool.get('ir.module.module')
module_ids = module_obj.search([
('state', 'in', ['to upgrade', 'to remove', 'to install']),
])
@@ -502,9 +507,9 @@ class ModuleInstallUpgrade(Wizard):
}
def _upgrade_module(self, data):
module_obj = self.pool.get('ir.module.module')
lang_obj = self.pool.get('ir.lang')
dbname = Transaction().cursor.dbname
pool = Pool()
module_obj = pool.get('ir.module.module')
lang_obj = pool.get('ir.lang')
with Transaction().new_cursor() as transaction:
module_ids = module_obj.search([
('state', 'in', ['to upgrade', 'to remove', 'to install']),
@@ -515,7 +520,6 @@ class ModuleInstallUpgrade(Wizard):
lang = [x.code for x in lang_obj.browse(lang_ids)]
transaction.cursor.commit()
if module_ids:
pool = Pool(dbname)
pool.init(update=True, lang=lang)
new_wizard = pool.get('ir.module.module.install_upgrade',
type='wizard')
@@ -563,8 +567,9 @@ class ModuleInstallUpgrade(Wizard):
}
def _menu(self, data):
model_data_obj = self.pool.get('ir.model.data')
act_window_obj = self.pool.get('ir.action.act_window')
pool = Pool()
model_data_obj = pool.get('ir.model.data')
act_window_obj = pool.get('ir.action.act_window')
act_window_id = model_data_obj.get_id('ir', 'act_menu_tree')
res = act_window_obj.read(act_window_id)
return res
@@ -592,8 +597,9 @@ class ModuleConfig(Wizard):
}
def _action_open(self, datas):
model_data_obj = self.pool.get('ir.model.data')
act_window_obj = self.pool.get('ir.action.act_window')
pool = Pool()
model_data_obj = pool.get('ir.model.data')
act_window_obj = pool.get('ir.action.act_window')
act_window_id = model_data_obj.get_id('ir', 'act_module_form')
res = act_window_obj.read(act_window_id)
return res
+8 -6
View File
@@ -1,10 +1,10 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
from decimal import Decimal
from trytond.model import ModelView, ModelSQL, fields
from trytond.transaction import Transaction
from trytond.cache import Cache
from trytond.pool import Pool
class Property(ModelSQL, ModelView):
@@ -32,7 +32,8 @@ class Property(ModelSQL, ModelView):
:param res_ids: a list of record ids
:return: a dictionary
"""
model_access_obj = self.pool.get('ir.model.access')
pool = Pool()
model_access_obj = pool.get('ir.model.access')
res = {}
model_access_obj.check(model, 'read')
@@ -44,7 +45,7 @@ class Property(ModelSQL, ModelView):
if res_ids is None:
res_ids = []
model_obj = self.pool.get(model)
model_obj = pool.get(model)
fields = dict((name, field)
for name, field in model_obj._columns.iteritems()
if name in names)
@@ -126,8 +127,9 @@ class Property(ModelSQL, ModelView):
:param val: the value
:return: the id of the record created
"""
model_field_obj = self.pool.get('ir.model.field')
model_access_obj = self.pool.get('ir.model.access')
pool = Pool()
model_field_obj = pool.get('ir.model.field')
model_access_obj = pool.get('ir.model.access')
model_access_obj.check(model, 'write')
@@ -135,7 +137,7 @@ class Property(ModelSQL, ModelView):
('name', '=', name),
('model.model', '=', model),
], order=[], limit=1)[0]
model_obj = self.pool.get(model)
model_obj = pool.get(model)
field = model_obj._columns[name]
property_ids = self.search([
+25 -24
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import contextlib
import time
from trytond.model import ModelView, ModelSQL, fields
@@ -9,6 +8,7 @@ from trytond.pyson import Eval, Get
from trytond.transaction import Transaction
from trytond.cache import Cache
from trytond.const import OPERATORS
from trytond.pool import Pool
class RuleGroup(ModelSQL, ModelView):
@@ -26,9 +26,9 @@ class RuleGroup(ModelSQL, ModelView):
rules = fields.One2Many('ir.rule', 'rule_group', 'Tests',
help="The rule is satisfied if at least one test is True")
groups = fields.Many2Many('ir.rule.group-res.group',
'rule_group_id', 'group_id', 'Groups')
'rule_group', 'group', 'Groups')
users = fields.Many2Many('ir.rule.group-res.user',
'rule_group_id', 'user_id', 'Users')
'rule_group', 'user', 'Users')
perm_read = fields.Boolean('Read Access')
perm_write = fields.Boolean('Write Access')
perm_create = fields.Boolean('Create Access')
@@ -65,19 +65,19 @@ class RuleGroup(ModelSQL, ModelView):
def delete(self, ids):
res = super(RuleGroup, self).delete(ids)
# Restart the cache on the domain_get method of ir.rule
self.pool.get('ir.rule').domain_get.reset()
Pool().get('ir.rule').domain_get.reset()
return res
def create(self, vals):
res = super(RuleGroup, self).create(vals)
# Restart the cache on the domain_get method of ir.rule
self.pool.get('ir.rule').domain_get.reset()
Pool().get('ir.rule').domain_get.reset()
return res
def write(self, ids, vals):
res = super(RuleGroup, self).write(ids, vals)
# Restart the cache on the domain_get method of ir.rule
self.pool.get('ir.rule').domain_get.reset()
Pool().get('ir.rule').domain_get.reset()
return res
RuleGroup()
@@ -115,7 +115,7 @@ class Rule(ModelSQL, ModelView):
if not recur:
recur = []
with Transaction().set_context(language='en_US'):
obj_fields = self.pool.get(obj_name).fields_get()
obj_fields = Pool().get(obj_name).fields_get()
key = obj_fields.keys()
key.sort()
for k in key:
@@ -158,12 +158,13 @@ class Rule(ModelSQL, ModelView):
with Transaction().set_user(Transaction().context['user']):
return self.domain_get(model_name)
rule_group_obj = self.pool.get('ir.rule.group')
model_obj = self.pool.get('ir.model')
rule_group_user_obj = self.pool.get('ir.rule.group-res.user')
rule_group_group_obj = self.pool.get('ir.rule.group-res.group')
user_group_obj = self.pool.get('res.user-res.group')
user_obj = self.pool.get('res.user')
pool = Pool()
rule_group_obj = pool.get('ir.rule.group')
model_obj = pool.get('ir.model')
rule_group_user_obj = pool.get('ir.rule.group-res.user')
rule_group_group_obj = pool.get('ir.rule.group-res.group')
user_group_obj = pool.get('res.user-res.group')
user_obj = pool.get('res.user')
cursor = Transaction().cursor
cursor.execute('SELECT r.id FROM "' + self._table + '" r ' \
@@ -173,21 +174,21 @@ class Rule(ModelSQL, ModelView):
"WHERE m.model = %s "
"AND g.perm_" + mode + " "
"AND (g.id IN (" \
'SELECT rule_group_id ' \
'SELECT rule_group ' \
'FROM "' + rule_group_user_obj._table + '" ' \
"WHERE user_id = %s " \
"UNION SELECT rule_group_id " \
'WHERE "user" = %s ' \
"UNION SELECT rule_group " \
'FROM "' + rule_group_group_obj._table + '" g_rel ' \
'JOIN "' + user_group_obj._table + '" u_rel ' \
"ON (g_rel.group_id = u_rel.gid) " \
"WHERE u_rel.uid = %s) " \
'ON (g_rel."group" = u_rel."group") ' \
'WHERE u_rel."user" = %s) ' \
"OR default_p " \
"OR g.global_p)",
(model_name, Transaction().user, Transaction().user))
ids = [x[0] for x in cursor.fetchall()]
if not ids:
return '', []
obj = self.pool.get(model_name)
obj = pool.get(model_name)
clause = {}
clause_global = {}
operand2query = self._operand_get('res.user', level=1,
@@ -222,14 +223,14 @@ class Rule(ModelSQL, ModelView):
'WHERE m.model = %s ' \
'AND (g.id NOT IN (SELECT rule_group ' \
'FROM "' + self._table + '")) ' \
'AND (g.id IN (SELECT rule_group_id ' \
'AND (g.id IN (SELECT rule_group ' \
'FROM "' + rule_group_user_obj._table + '" ' \
'WHERE user_id = %s ' \
'UNION SELECT rule_group_id ' \
'WHERE "user" = %s ' \
'UNION SELECT rule_group ' \
'FROM "' + rule_group_group_obj._table + '" g_rel ' \
'JOIN "' + user_group_obj._table + '" u_rel ' \
'ON g_rel.group_id = u_rel.gid ' \
'WHERE u_rel.uid = %s))',
'ON g_rel."group" = u_rel."group" ' \
'WHERE u_rel."user" = %s))',
(model_name, user_id, user_id))
fetchone = cursor.fetchone()
if fetchone:
+6 -4
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
from string import Template
import datetime
import time
@@ -8,6 +7,7 @@ from trytond.model import ModelView, ModelSQL, fields
from trytond.tools import datetime_strftime
from trytond.pyson import In, Eval, Not
from trytond.transaction import Transaction
from trytond.pool import Pool
class SequenceType(ModelSQL, ModelView):
@@ -49,7 +49,7 @@ class Sequence(ModelSQL, ModelView):
states={
'invisible': Not(In(Eval('type'), ['incremental'])),
}, depends=['type'])
timestamp_rounding = fields.Integer('Timestamp Rounding', required=True,
timestamp_rounding = fields.Float('Timestamp Rounding', required=True,
states={
'invisible': Not(In(Eval('type'),
['decimal timestamp', 'hexadecimal timestamp'])),
@@ -105,7 +105,8 @@ class Sequence(ModelSQL, ModelView):
return Transaction().context.get('code', False)
def code_get(self):
sequence_type_obj = self.pool.get('ir.sequence.type')
pool = Pool()
sequence_type_obj = pool.get('ir.sequence.type')
sequence_type_ids = sequence_type_obj.search([])
sequence_types = sequence_type_obj.browse(sequence_type_ids)
return [(x.code, x.name) for x in sequence_types]
@@ -131,7 +132,8 @@ class Sequence(ModelSQL, ModelView):
return True
def _process(self, string, date=None):
date_obj = self.pool.get('ir.date')
pool = Pool()
date_obj = pool.get('ir.date')
if not date:
date = date_obj.today()
year = datetime_strftime(date, '%Y')
+51 -36
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import contextlib
import base64
try:
@@ -17,6 +16,7 @@ try:
from hashlib import md5
except ImportError:
from md5 import md5
from functools import reduce
from trytond.model import ModelView, ModelSQL, fields
from trytond.model.cacheable import Cacheable
from trytond.wizard import Wizard
@@ -25,6 +25,7 @@ from trytond.tools import file_open, reduce_ids
from trytond.backend import TableHandler, FIELDS
from trytond.pyson import PYSONEncoder
from trytond.transaction import Transaction
from trytond.pool import Pool
TRANSLATION_TYPE = [
('field', 'Field'),
@@ -143,7 +144,8 @@ class Translation(ModelSQL, ModelView, Cacheable):
return [('id', 'in', [x[0] for x in cursor.fetchall()])]
def get_language(self):
lang_obj = self.pool.get('ir.lang')
pool = Pool()
lang_obj = pool.get('ir.lang')
lang_ids = lang_obj.search([])
langs = lang_obj.browse(lang_ids)
res = [(lang.code, lang.name) for lang in langs]
@@ -153,8 +155,9 @@ class Translation(ModelSQL, ModelView, Cacheable):
return md5((src or '').encode('utf-8')).hexdigest()
def _get_ids(self, name, ttype, lang, ids):
model_fields_obj = self.pool.get('ir.model.field')
model_obj = self.pool.get('ir.model')
pool = Pool()
model_fields_obj = pool.get('ir.model.field')
model_obj = pool.get('ir.model')
translations, to_fetch = {}, []
name = unicode(name)
@@ -220,8 +223,9 @@ class Translation(ModelSQL, ModelView, Cacheable):
return translations
def _set_ids(self, name, ttype, lang, ids, value):
model_fields_obj = self.pool.get('ir.model.field')
model_obj = self.pool.get('ir.model')
pool = Pool()
model_fields_obj = pool.get('ir.model.field')
model_obj = pool.get('ir.model')
if lang == 'en_US':
return 0
@@ -262,7 +266,7 @@ class Translation(ModelSQL, ModelView, Cacheable):
'fuzzy': False,
})
return len(ids)
model_obj = self.pool.get(model_name)
model_obj = pool.get(model_name)
for record in model_obj.browse(ids):
ids2 = self.search([
('lang', '=', lang),
@@ -439,7 +443,8 @@ class Translation(ModelSQL, ModelView, Cacheable):
return super(Translation, self).write(ids, vals)
def translation_import(self, lang, module, datas):
model_data_obj = self.pool.get('ir.model.data')
pool = Pool()
model_data_obj = pool.get('ir.model.data')
model_data_ids = model_data_obj.search([
('module', '=', module),
])
@@ -537,7 +542,8 @@ class Translation(ModelSQL, ModelView, Cacheable):
return len(translation_ids)
def translation_export(self, lang, module):
model_data_obj = self.pool.get('ir.model.data')
pool = Pool()
model_data_obj = pool.get('ir.model.data')
model_data_ids = model_data_obj.search([
('module', '=', module),
@@ -651,7 +657,9 @@ class ReportTranslationSet(Wizard):
return strings
def _set_report_translation(self, data):
report_obj = self.pool.get('ir.action.report')
pool = Pool()
report_obj = pool.get('ir.action.report')
translation_obj = pool.get('ir.translation')
with Transaction().set_context(active_test=False):
report_ids = report_obj.search([])
@@ -713,7 +721,7 @@ class ReportTranslationSet(Wizard):
strings += self._translate_report(document.documentElement)
for string in {}.fromkeys(strings).keys():
src_md5 = self.get_src_md5(string)
src_md5 = translation_obj.get_src_md5(string)
done = False
if string in trans_reports:
del trans_reports[string]
@@ -807,9 +815,10 @@ class TranslationClean(Wizard):
}
def _clean_translation(self, data):
translation_obj = self.pool.get('ir.translation')
model_data_obj = self.pool.get('ir.model.data')
report_obj = self.pool.get('ir.action.report')
pool = Pool()
translation_obj = pool.get('ir.translation')
model_data_obj = pool.get('ir.model.data')
report_obj = pool.get('ir.action.report')
offset = 0
cursor = Transaction().cursor
@@ -828,10 +837,10 @@ class TranslationClean(Wizard):
except ValueError:
to_delete.append(translation.id)
continue
if model_name not in self.pool.object_name_list():
if model_name not in pool.object_name_list():
to_delete.append(translation.id)
continue
model_obj = self.pool.get(model_name)
model_obj = pool.get(model_name)
if field_name not in model_obj._columns:
to_delete.append(translation.id)
continue
@@ -841,11 +850,11 @@ class TranslationClean(Wizard):
except ValueError:
to_delete.append(translation.id)
continue
if model_name not in self.pool.object_name_list():
if model_name not in pool.object_name_list():
to_delete.append(translation.id)
continue
if translation.res_id:
model_obj = self.pool.get(model_name)
model_obj = pool.get(model_name)
if field_name not in model_obj._columns:
to_delete.append(translation.id)
continue
@@ -870,10 +879,10 @@ class TranslationClean(Wizard):
except ValueError:
to_delete.append(translation.id)
continue
if model_name not in self.pool.object_name_list():
if model_name not in pool.object_name_list():
to_delete.append(translation.id)
continue
model_obj = self.pool.get(model_name)
model_obj = pool.get(model_name)
if field_name not in model_obj._columns:
to_delete.append(translation.id)
continue
@@ -890,7 +899,7 @@ class TranslationClean(Wizard):
continue
elif translation.type == 'view':
model_name = translation.name
if model_name not in self.pool.object_name_list():
if model_name not in pool.object_name_list():
to_delete.append(translation.id)
continue
elif translation.type == 'wizard_button':
@@ -901,10 +910,10 @@ class TranslationClean(Wizard):
to_delete.append(translation.id)
continue
if wizard_name not in \
self.pool.object_name_list(type='wizard'):
pool.object_name_list(type='wizard'):
to_delete.append(translation.id)
continue
wizard = self.pool.get(wizard_name, type='wizard')
wizard = pool.get(wizard_name, type='wizard')
if not wizard:
to_delete.append(translation.id)
continue
@@ -925,10 +934,10 @@ class TranslationClean(Wizard):
except ValueError:
to_delete.append(translation.id)
continue
if model_name not in self.pool.object_name_list():
if model_name not in pool.object_name_list():
to_delete.append(translation.id)
continue
model_obj = self.pool.get(model_name)
model_obj = pool.get(model_name)
if field_name not in model_obj._columns:
to_delete.append(translation.id)
continue
@@ -961,8 +970,8 @@ class TranslationClean(Wizard):
'search_function_missing',
):
continue
if model_name in self.pool.object_name_list():
model_obj = self.pool.get(model_name)
if model_name in pool.object_name_list():
model_obj = pool.get(model_name)
errors = model_obj._error_messages.values() + \
model_obj._sql_error_messages.values()
for _, _, error in model_obj._sql_constraints:
@@ -970,8 +979,8 @@ class TranslationClean(Wizard):
if translation.src not in errors:
to_delete.append(translation.id)
continue
elif model_name in self.pool.object_name_list(type='wizard'):
wizard_obj = self.pool.get(model_name, type='wizard')
elif model_name in pool.object_name_list(type='wizard'):
wizard_obj = pool.get(model_name, type='wizard')
errors = wizard_obj._error_messages.values()
if translation.src not in errors:
to_delete.append(translation.id)
@@ -1005,7 +1014,8 @@ class TranslationUpdateInit(ModelView):
return Transaction().context.get('language', False)
def get_language(self):
lang_obj = self.pool.get('ir.lang')
pool = Pool()
lang_obj = pool.get('ir.lang')
lang_ids = lang_obj.search([('translatable', '=', True)])
langs = lang_obj.browse(lang_ids)
res = [(lang.code, lang.name) for lang in langs if lang.code != 'en_US']
@@ -1019,7 +1029,8 @@ class TranslationUpdate(Wizard):
_name = "ir.translation.update"
def _update_translation(self, data):
translation_obj = self.pool.get('ir.translation')
pool = Pool()
translation_obj = pool.get('ir.translation')
cursor = Transaction().cursor
cursor.execute('SELECT name, res_id, type, src, module ' \
'FROM ir_translation ' \
@@ -1107,8 +1118,9 @@ class TranslationUpdate(Wizard):
return {}
def _action_translation_open(self, data):
model_data_obj = self.pool.get('ir.model.data')
act_window_obj = self.pool.get('ir.action.act_window')
pool = Pool()
model_data_obj = pool.get('ir.model.data')
act_window_obj = pool.get('ir.action.act_window')
model_data_ids = model_data_obj.search([
('fs_id', '=', 'act_translation_form'),
@@ -1161,7 +1173,8 @@ class TranslationExportInit(ModelView):
return Transaction().context.get('language', False)
def get_language(self):
lang_obj = self.pool.get('ir.lang')
pool = Pool()
lang_obj = pool.get('ir.lang')
lang_ids = lang_obj.search([
('translatable', '=', True),
])
@@ -1170,7 +1183,8 @@ class TranslationExportInit(ModelView):
return res
def get_module(self):
module_obj = self.pool.get('ir.module.module')
pool = Pool()
module_obj = pool.get('ir.module.module')
module_ids = module_obj.search([
('state', 'in', ['installed', 'to upgrade', 'to remove']),
])
@@ -1195,7 +1209,8 @@ class TranslationExport(Wizard):
_name = "ir.translation.export"
def _export_translation(self, data):
translation_obj = self.pool.get('ir.translation')
pool = Pool()
translation_obj = pool.get('ir.translation')
file_data = translation_obj.translation_export(data['form']['lang'],
data['form']['module'])
return {
+8 -4
View File
@@ -9,6 +9,7 @@ from trytond.backend import TableHandler
from trytond.tools import reduce_ids
from trytond.transaction import Transaction
from trytond.cache import Cache
from trytond.pool import Pool
class Trigger(ModelSQL, ModelView):
@@ -135,7 +136,8 @@ class Trigger(ModelSQL, ModelView):
:param record: a BrowseRecord of the tested model
:return: a boolean
"""
model_obj = self.pool.get(trigger.model.model)
pool = Pool()
model_obj = pool.get(trigger.model.model)
env = {}
env['current_date'] = datetime.datetime.today()
env['time'] = time
@@ -150,9 +152,10 @@ class Trigger(ModelSQL, ModelView):
:param ids: the list of record ids triggered
:param trigger_id: the trigger id
"""
trigger_log_obj = self.pool.get('ir.trigger.log')
pool = Pool()
trigger_log_obj = pool.get('ir.trigger.log')
trigger = self.browse(trigger_id)
model_obj = self.pool.get(trigger.action_model.model)
model_obj = pool.get(trigger.action_model.model)
cursor = Transaction().cursor
# Filter on limit_number
@@ -220,11 +223,12 @@ class Trigger(ModelSQL, ModelView):
'''
Trigger time actions
'''
pool = Pool()
trigger_ids = self.search([
('on_time', '=', True),
])
for trigger in self.browse(trigger_ids):
model_obj = self.pool.get(trigger.model.model)
model_obj = pool.get(trigger.model.model)
triggered_ids = []
# TODO add a domain
record_ids = model_obj.search([])
-1
View File
@@ -1,6 +1,5 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of this
# repository contains the full copyright notices and license terms.
from __future__ import with_statement
import os
+51 -19
View File
@@ -1,8 +1,8 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
from trytond.model import ModelView, ModelSQL, fields
from trytond.transaction import Transaction
from trytond.pool import Pool
def one_in(i, j):
"""Check the presence of an element of setA in setB
@@ -58,6 +58,7 @@ CLIENT_ICONS = [(x, x) for x in (
'tryton-system',
'tryton-undo',
'tryton-web-browser')]
SEPARATOR = ' / '
class UIMenu(ModelSQL, ModelView):
@@ -70,9 +71,9 @@ class UIMenu(ModelSQL, ModelView):
parent = fields.Many2One('ir.ui.menu', 'Parent Menu', select=1,
ondelete='CASCADE')
groups = fields.Many2Many('ir.ui.menu-res.group',
'menu_id', 'gid', 'Groups')
'menu', 'group', 'Groups')
complete_name = fields.Function(fields.Char('Complete Name',
order_field='name'), 'get_full_name')
order_field='name'), 'get_rec_name', searcher='search_rec_name')
icon = fields.Selection('list_icons', 'Icon')
action = fields.Function(fields.Reference('Action',
selection=[
@@ -86,6 +87,14 @@ class UIMenu(ModelSQL, ModelView):
def __init__(self):
super(UIMenu, self).__init__()
self._order.insert(0, ('sequence', 'ASC'))
self._constraints += [
('check_recursion', 'recursive_menu'),
('check_name', 'wrong_name'),
]
self._error_messages.update({
'recursive_menu': 'You can not create recursive menu!',
'wrong_name': 'You can not use "%s" in name field!' % SEPARATOR,
})
def default_icon(self):
return 'tryton-open'
@@ -97,24 +106,45 @@ class UIMenu(ModelSQL, ModelView):
return True
def list_icons(self):
icon_obj = self.pool.get('ir.ui.icon')
pool = Pool()
icon_obj = pool.get('ir.ui.icon')
return sorted(CLIENT_ICONS
+ [(name, name) for _, name in icon_obj.list_icons()])
def get_full_name(self, ids, name):
res = {}
def check_name(self, ids):
for menu in self.browse(ids):
res[menu.id] = self._get_one_full_name(menu)
if SEPARATOR in menu.name:
return False
return True
def get_rec_name(self, ids, name):
if not ids:
return {}
res = {}
def _name(menu):
if menu.id in res:
return res[menu.id]
elif menu.parent:
return _name(menu.parent) + SEPARATOR + menu.name
else:
return menu.name
for menu in self.browse(ids):
res[menu.id] = _name(menu)
return res
def _get_one_full_name(self, menu, level=6):
if level <= 0:
return '...'
if menu.parent:
parent_path = self._get_one_full_name(menu.parent, level-1) + "/"
else:
parent_path = ''
return parent_path + menu.name
def search_rec_name(self, name, clause):
if isinstance(clause[2], basestring):
values = clause[2].split(SEPARATOR)
values.reverse()
domain = []
field = 'name'
for name in values:
domain.append((field, clause[1], name))
field = 'parent.' + field
ids = self.search(domain, order=[])
return [('id', 'in', ids)]
#TODO Handle list
return [('name',) + tuple(clause[1:])]
def search(self, domain, offset=0, limit=None, order=None, count=False,
query_string=False):
@@ -137,7 +167,8 @@ class UIMenu(ModelSQL, ModelView):
return res
def get_action(self, ids, name):
action_keyword_obj = self.pool.get('ir.action.keyword')
pool = Pool()
action_keyword_obj = pool.get('ir.action.keyword')
res = {}
for menu_id in ids:
res[menu_id] = False
@@ -149,7 +180,7 @@ class UIMenu(ModelSQL, ModelView):
for action_keyword in action_keyword_obj.browse(action_keyword_ids):
model_id = int(
action_keyword.model.split(',')[1].split(',')[0].strip('('))
action_obj = self.pool.get(action_keyword.action.type)
action_obj = pool.get(action_keyword.action.type)
with Transaction().set_context(active_test=False):
action_id = action_obj.search([
('action', '=', action_keyword.action.id),
@@ -164,7 +195,8 @@ class UIMenu(ModelSQL, ModelView):
def set_action(self, ids, name, value):
if not value:
return
action_keyword_obj = self.pool.get('ir.action.keyword')
pool = Pool()
action_keyword_obj = pool.get('ir.action.keyword')
action_keyword_ids = []
cursor = Transaction().cursor
for i in range(0, len(ids), cursor.IN_MAX):
@@ -180,7 +212,7 @@ class UIMenu(ModelSQL, ModelView):
action_type, action_id = value.split(',')
if not int(action_id):
return
action_obj = self.pool.get(action_type)
action_obj = pool.get(action_type)
action = action_obj.browse(int(action_id))
for menu_id in ids:
with Transaction().set_context(_timestamp=False):
+16 -6
View File
@@ -24,7 +24,7 @@ this repository contains the full copyright notices and license terms. -->
<field name="arch" type="xml">
<![CDATA[
<tree string="Menu" fill="1">
<field name="rec_name" icon="icon"/>
<field name="complete_name" icon="icon" select="1"/>
</tree>
]]>
</field>
@@ -50,7 +50,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="sequence"/>
<label name="complete_name"/>
<field name="complete_name" colspan="3"/>
<separator name="groups" colspan="4"/>
<field name="groups" colspan="4"/>
</form>
]]>
@@ -69,14 +68,25 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="menu_view_tree_tree"/>
<field name="act_window" ref="act_menu_tree"/>
</record>
<record model="ir.action.act_window" id="act_menu_list">
<field name="name">Menu</field>
<field name="res_model">ir.ui.menu</field>
</record>
<record model="ir.action.act_window.view"
id="act_menu_form_view2">
<field name="sequence" eval="2"/>
id="act_menu_list_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="menu_view_list"/>
<field name="act_window" ref="act_menu_list"/>
</record>
<record model="ir.action.act_window.view"
id="act_menu_list_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="menu_view_form"/>
<field name="act_window" ref="act_menu_tree"/>
<field name="act_window" ref="act_menu_list"/>
</record>
<menuitem parent="menu_ui"
action="act_menu_tree" id="menu_menu_tree"/>
action="act_menu_list" id="menu_menu_list"/>
</data>
</tryton>
+23 -14
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import os
import logging
from lxml import etree
@@ -11,6 +10,7 @@ from trytond.pyson import PYSONEncoder, CONTEXT, Eval, Not, Bool, Equal
from trytond.tools import safe_eval
from trytond.transaction import Transaction
from trytond.wizard import Wizard
from trytond.pool import Pool
class View(ModelSQL, ModelView):
@@ -66,7 +66,8 @@ class View(ModelSQL, ModelView):
def check_xml(self, ids):
"Check XML"
translation_obj = self.pool.get('ir.translation')
pool = Pool()
translation_obj = pool.get('ir.translation')
cursor = Transaction().cursor
views = self.browse(ids)
for view in views:
@@ -188,7 +189,8 @@ class View(ModelSQL, ModelView):
def delete(self, ids):
res = super(View, self).delete(ids)
# Restart the cache
for _, model in self.pool.iterobject():
pool = Pool()
for _, model in pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
@@ -198,7 +200,8 @@ class View(ModelSQL, ModelView):
def create(self, vals):
res = super(View, self).create(vals)
# Restart the cache
for _, model in self.pool.iterobject():
pool = Pool()
for _, model in pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
@@ -208,7 +211,8 @@ class View(ModelSQL, ModelView):
def write(self, ids, vals):
res = super(View, self).write(ids, vals)
# Restart the cache
for _, model in self.pool.iterobject():
pool = Pool()
for _, model in pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
@@ -274,8 +278,9 @@ class AddShortcut(Wizard):
}
def _add_shortcut(self, data):
view_sc_obj = self.pool.get('ir.ui.view_sc')
model_obj = self.pool.get(data['model'])
pool = Pool()
view_sc_obj = pool.get('ir.ui.view_sc')
model_obj = pool.get(data['model'])
record = model_obj.browse(data['id'])
view_sc_obj.create({
@@ -304,8 +309,9 @@ class OpenShortcut(Wizard):
}
def _open(self, data):
view_sc_obj = self.pool.get('ir.ui.view_sc')
action_keyword_obj = self.pool.get('ir.action.keyword')
pool = Pool()
view_sc_obj = pool.get('ir.ui.view_sc')
action_keyword_obj = pool.get('ir.action.keyword')
view_sc = view_sc_obj.browse(data['id'])
models = (
@@ -323,7 +329,7 @@ class OpenShortcut(Wizard):
if not action_keyword_ids:
return {}
action_keyword = action_keyword_obj.browse(action_keyword_ids[0])
action_obj = self.pool.get(action_keyword.action.type)
action_obj = pool.get(action_keyword.action.type)
action_ids = action_obj.search([
('action.id', '=', action_keyword.action.id),
])
@@ -352,37 +358,40 @@ class ViewTreeWidth(ModelSQL, ModelView):
})
def delete(self, ids):
pool = Pool()
if isinstance(ids, (int, long)):
ids = [ids]
views = self.browse(ids)
for view in views:
# Restart the cache
try:
self.pool.get(view.model).fields_view_get.reset()
pool.get(view.model).fields_view_get.reset()
except Exception:
pass
res = super(ViewTreeWidth, self).delete(ids)
return res
def create(self, vals):
pool = Pool()
res = super(ViewTreeWidth, self).create(vals)
if 'model' in vals:
model = vals['model']
# Restart the cache
try:
self.pool.get(model).fields_view_get.reset()
pool.get(model).fields_view_get.reset()
except Exception:
pass
return res
def write(self, ids, vals):
pool = Pool()
if isinstance(ids, (int, long)):
ids = [ids]
views = self.browse(ids)
for view in views:
# Restart the cache
try:
self.pool.get(view.model).fields_view_get.reset()
pool.get(view.model).fields_view_get.reset()
except Exception:
pass
res = super(ViewTreeWidth, self).write(ids, vals)
@@ -390,7 +399,7 @@ class ViewTreeWidth(ModelSQL, ModelView):
for view in views:
# Restart the cache
try:
self.pool.get(view.model).fields_view_get.reset()
pool.get(view.model).fields_view_get.reset()
except Exception:
pass
return res
+165 -147
View File
@@ -1,11 +1,14 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import contextlib
from itertools import islice, ifilter, ifilterfalse
from itertools import islice, ifilter, ifilterfalse, chain
from trytond.model import fields
from trytond.transaction import Transaction
from trytond.const import BROWSE_FIELD_TRESHOLD
from trytond.pool import Pool
from trytond.cache import LRUDict
from trytond.const import MODEL_CACHE_SIZE, RECORD_CACHE_SIZE, \
BROWSE_FIELD_TRESHOLD
class BrowseRecordList(list):
'''
@@ -46,164 +49,177 @@ class BrowseRecord(object):
An object that represents record defined by a ORM object.
'''
def __init__(self, record_id, model, local_cache=None):
def __init__(self, record_id, model, ids, local_cache):
assert isinstance(ids, list)
if ids:
assert record_id in ids
self._cursor = Transaction().cursor
self._user = Transaction().user
self._id = record_id
self.id = record_id
self._model = model
self._model_name = self._model._name
self._context = Transaction().context
self._pool = Pool()
self._ids = ids
cache = self._cursor.get_cache(self._context)
cache.setdefault(model._name, {})
cache.setdefault('_language_cache', {})
if model._name not in cache:
cache[model._name] = LRUDict(RECORD_CACHE_SIZE)
self._data = cache[model._name]
if not record_id in self._data:
self._data[record_id] = {'id': record_id}
self._cache = cache
if local_cache is None:
local_cache = {}
self._local_cache = local_cache
self._local_cache.setdefault(model._name, {})
self._local_cache.setdefault('_language_cache', {})
self._local_data = self._local_cache[model._name]
if not record_id in self._local_data:
self._local_data[record_id] = {}
assert isinstance(local_cache, LRUDict)
self._local_data = local_cache
def __getitem__(self, name):
if name == 'id':
return self._id
if name == 'setLang':
return self.setLang
if not self._data[self._id].has_key(name) \
and not self._local_data[self._id].has_key(name):
# build the list of fields we will fetch
# Access to LRUDict must be atomic
result = self._local_data.get(self.id, {}).get(name)
if (self.id in self._local_data
and name in self._local_data[self.id]):
return result
result = self._data.get(self.id, {}).get(name)
if self.id in self._data and name in self._data[self.id]:
return result
# fetch the definition of the field which was asked for
if name in self._model._columns:
col = self._model._columns[name]
elif name in self._model._inherit_fields:
col = self._model._inherit_fields[name][2]
elif hasattr(self._model, name):
return getattr(self._model, name)
else:
raise Exception('Error', 'Programming error: field "%s" ' \
'does not exist in model "%s"!' \
% (name, self._model._name))
# build the list of fields we will fetch
# fetch the definition of the field which was asked for
if name in self._model._columns:
col = self._model._columns[name]
elif name in self._model._inherit_fields:
col = self._model._inherit_fields[name][2]
elif hasattr(self._model, name):
return getattr(self._model, name)
else:
raise Exception('Error', 'Programming error: field "%s" ' \
'does not exist in model "%s"!' \
% (name, self._model._name))
ffields = {}
if col.loading == 'eager':
field_access_obj = self._model.pool.get('ir.model.field.access')
fread_accesses = {}
for inherit_name in self._model._inherits:
inherit_obj = self._model.pool.get(inherit_name)
fread_accesses.update(field_access_obj.check(inherit_name,
inherit_obj._columns.keys(), 'read', access=True))
fread_accesses.update(field_access_obj.check(self._model._name,
self._model._columns.keys(), 'read', access=True))
to_remove = set(x for x, y in fread_accesses.iteritems()
if not y and x != name)
ffields = {}
if col.loading == 'eager':
field_access_obj = self._pool.get('ir.model.field.access')
fread_accesses = {}
for inherit_name in self._model._inherits:
inherit_obj = self._pool.get(inherit_name)
fread_accesses.update(field_access_obj.check(inherit_name,
inherit_obj._columns.keys(), 'read', access=True))
fread_accesses.update(field_access_obj.check(self._model._name,
self._model._columns.keys(), 'read', access=True))
to_remove = set(x for x, y in fread_accesses.iteritems()
if not y and x != name)
threshold = BROWSE_FIELD_TRESHOLD
inherit_threshold = threshold - len(self._model._columns)
threshold = BROWSE_FIELD_TRESHOLD
inherit_threshold = threshold - len(self._model._columns)
def not_cached(item):
fname, field = item
return (fname not in self._data[self._id]
and fname not in self._local_data[self._id])
def to_load(item):
fname, field = item
return (field.loading == 'eager'
and fname not in to_remove)
def overrided(item):
fname, field = item
return fname in self._model._columns
def not_cached(item):
fname, field = item
return (fname not in self._data.get(self.id, {})
and fname not in self._local_data.get(self.id, {}))
def to_load(item):
fname, field = item
return (field.loading == 'eager'
and fname not in to_remove)
def overrided(item):
fname, field = item
return fname in self._model._columns
if inherit_threshold > 0:
ifields = ((fname, field)
for fname, (_, _, field) in
self._model._inherit_fields.iteritems())
ifields = ifilterfalse(overrided,
ifilter(to_load,
ifilter(not_cached, ifields)))
ifields = islice(ifields, 0, inherit_threshold)
ffields.update(ifields)
threshold -= inherit_threshold
ifields = ifilter(to_load,
ifilter(not_cached,
self._model._columns.iteritems()))
ifields = islice(ifields, 0, threshold)
if inherit_threshold > 0:
ifields = ((fname, field)
for fname, (_, _, field) in
self._model._inherit_fields.iteritems())
ifields = ifilterfalse(overrided,
ifilter(to_load,
ifilter(not_cached, ifields)))
ifields = islice(ifields, 0, inherit_threshold)
ffields.update(ifields)
threshold -= inherit_threshold
ffields[name] = col
ifields = ifilter(to_load,
ifilter(not_cached,
self._model._columns.iteritems()))
ifields = islice(ifields, 0, threshold)
ffields.update(ifields)
# add datetime_field
for field in ffields:
if hasattr(field, 'datetime_field') and field.datetime_field:
if field.datetime_field in self._model._columns:
date_field = self._model._columns[field.datetime_field]
else:
date_field = self._model._inherit_fields[
field.datetime_field][2]
ffields[field.datetime_field] = datetime_field
ffields[name] = col
if len(self._data) <= self._cursor.IN_MAX:
iterids = self._data.iterkeys()
else:
iterids = self._local_data.iterkeys()
ids = [x for x in iterids \
if not self._data.setdefault(x, {}).has_key(name) \
and not self._local_data.setdefault(x, {}).has_key(name)]
# read the data
with contextlib.nested(Transaction().set_cursor(self._cursor),
Transaction().set_user(self._user),
Transaction().set_context(self._context)):
datas = self._model.read(ids, ffields.keys())
# add datetime_field
for field in ffields:
if hasattr(field, 'datetime_field') and field.datetime_field:
if field.datetime_field in self._model._columns:
date_field = self._model._columns[field.datetime_field]
else:
date_field = self._model._inherit_fields[
field.datetime_field][2]
ffields[field.datetime_field] = datetime_field
# create browse records for 'remote' models
for data in datas:
for i, j in ffields.iteritems():
model = None
if (hasattr(j, 'model_name') and
j.model_name in
self._model.pool.object_name_list()):
model = self._model.pool.get(j.model_name)
elif hasattr(j, 'get_target'):
model = j.get_target(self._model.pool)
if model and j._type in ('many2one', 'one2one'):
if (not data[i]
and not (isinstance(data[i], (int, long))
and not isinstance(data[i],
type(False)))):
data[i] = BrowseRecordNull()
else:
_datetime = None
if (hasattr(j, 'datetime_field')
and j.datetime_field):
_datetime = data[j.datetime_field]
with Transaction().set_context(
_datetime=_datetime):
data[i] = BrowseRecord(data[i], model,
local_cache=self._local_cache)
elif (model
and j._type in ('one2many', 'many2many')
and len(data[i])):
def filter_(id_):
if (id_ in self._local_data
and name in self._local_data[id_]):
return False
if id_ in self._data and name in self._data[id_]:
return False
return True
index = self._ids.index(self.id)
ids = chain(islice(self._ids, index, None),
islice(self._ids, 0, max(index - 1, 0)))
ids = list(islice(ifilter(filter_, ids), self._cursor.IN_MAX))
model2ids = {}
model2cache = {}
# read the data
with contextlib.nested(Transaction().set_cursor(self._cursor),
Transaction().set_user(self._user),
Transaction().set_context(self._context)):
# create browse records for 'remote' models
for data in self._model.read(ids, ffields.keys()):
for i, j in ffields.iteritems():
model = None
if (hasattr(j, 'model_name') and
j.model_name in
self._pool.object_name_list()):
model = self._pool.get(j.model_name)
elif hasattr(j, 'get_target'):
model = j.get_target()
if model and j._type in ('many2one', 'one2one'):
if (not data[i]
and not (isinstance(data[i], (int, long))
and not isinstance(data[i],
type(False)))):
data[i] = BrowseRecordNull()
else:
_datetime = None
if hasattr(j, 'datetime_field') and j.datetime_field:
if (hasattr(j, 'datetime_field')
and j.datetime_field):
_datetime = data[j.datetime_field]
with Transaction().set_context(
_datetime=_datetime):
data[i] = BrowseRecordList(BrowseRecord(
x, model, local_cache=self._local_cache)
for x in data[i])
if isinstance(j, fields.Function):
self._local_data.setdefault(data['id'], {})[i] = data[i]
del data[i]
self._data[data['id']].update(data)
if name in self._local_data[self._id]:
return self._local_data[self._id][name]
return self._data[self._id][name]
ids = model2ids.setdefault(model, [])
ids.append(data[i])
local_cache = model2cache.setdefault(model,
LRUDict(RECORD_CACHE_SIZE))
data[i] = BrowseRecord(data[i], model,
ids, local_cache)
elif (model
and j._type in ('one2many', 'many2many')
and len(data[i])):
_datetime = None
if hasattr(j, 'datetime_field') and j.datetime_field:
_datetime = data[j.datetime_field]
with Transaction().set_context(
_datetime=_datetime):
ids = model2ids.setdefault(model, [])
ids.extend(data[i])
local_cache = model2cache.setdefault(model,
LRUDict(RECORD_CACHE_SIZE))
data[i] = BrowseRecordList(
BrowseRecord(x, model, ids, local_cache)
for x in data[i])
if isinstance(j, fields.Function):
if data['id'] == self.id and i == name:
result = data[i]
self._local_data.setdefault(data['id'], {})[i] = data[i]
del data[i]
self._data.setdefault(data['id'], {}).update(data)
if data['id'] == self.id and name in data:
result = data[name]
return result
def __getattr__(self, name):
# TODO raise an AttributeError exception
@@ -218,16 +234,16 @@ class BrowseRecord(object):
return name in self
def __int__(self):
return self._id
return self.id
def __str__(self):
return "BrowseRecord(%s, %d)" % (self._model_name, self._id)
return "BrowseRecord(%s, %d)" % (self._model_name, self.id)
def __eq__(self, other):
return (self._model_name, self._id) == (other._model_name, other._id)
return (self._model_name, self.id) == (other._model_name, other.id)
def __ne__(self, other):
return (self._model_name, self._id) != (other._model_name, other._id)
return (self._model_name, self.id) != (other._model_name, other.id)
# we need to define __unicode__ even though we've already defined __str__
# because we have overridden __getattr__
@@ -235,7 +251,7 @@ class BrowseRecord(object):
return unicode(str(self))
def __hash__(self):
return hash((self._model_name, self._id))
return hash((self._model_name, self.id))
def __nonzero__(self):
return True
@@ -246,22 +262,23 @@ class BrowseRecord(object):
self._context = self._context.copy()
prev_lang = self._context.get('language') or 'en_US'
self._context['language'] = lang
for cache in (self._cache, self._local_cache):
language_cache = cache['_language_cache']
for cache in (self._cache, self._local_data):
language_cache = cache.setdefault('_language_cache', {})
for model in cache:
if model == '_language_cache':
continue
for record_id in cache[model]:
language_cache.setdefault(prev_lang,
{}).setdefault(model, {})[record_id] = \
cache[model][record_id]
LRUDict(MODEL_CACHE_SIZE)).setdefault(model,
LRUDict(RECORD_CACHE_SIZE))[record_id] = \
cache[model][record_id]
if lang in language_cache \
and model in language_cache[lang] \
and record_id in language_cache[lang][model]:
cache[model][record_id] = \
language_cache[lang][model][record_id]
else:
cache[model][record_id] = {'id': record_id}
cache[model][record_id] = {}
def get_eval(self, name):
res = self[name]
@@ -280,6 +297,7 @@ class EvalEnvironment(dict):
super(EvalEnvironment, self).__init__()
self._record = record
self._model = model
self._pool = Pool()
def __getitem__(self, item):
if item.startswith('_parent_'):
@@ -288,7 +306,7 @@ class EvalEnvironment(dict):
model_name = self._model._columns[field].model_name
else:
model_name = self._model._inherit_fields[field][2].model_name
model = self._model.pool.get(model_name)
model = self._pool.get(model_name)
return EvalEnvironment(self._record[field], model)
if item in self._model._columns \
or item in self._model._inherit_fields:
+16 -12
View File
@@ -3,6 +3,7 @@
from itertools import chain
from trytond.model.fields.field import Field
from trytond.transaction import Transaction
from trytond.pool import Pool
class Many2Many(Field):
@@ -63,7 +64,12 @@ class Many2Many(Field):
for i in ids:
res[i] = []
relation_obj = model.pool.get(self.relation_name)
if self.order is None:
order = [(self.target, 'ASC')]
else:
order = self.order
relation_obj = Pool().get(self.relation_name)
relation_ids = []
for i in range(0, len(ids), Transaction().cursor.IN_MAX):
@@ -71,12 +77,11 @@ class Many2Many(Field):
relation_ids.append(relation_obj.search([
(self.origin, 'in', sub_ids),
(self.target + '.id', '!=', False),
], order=self.order))
], order=order))
relation_ids = list(chain(*relation_ids))
for relation in relation_obj.read(relation_ids,
[self.origin, self.target]):
res[relation[self.origin]].append(relation[self.target])
for relation in relation_obj.browse(relation_ids):
res[relation[self.origin].id].append(relation[self.target].id)
return res
def set(self, ids, model, name, values):
@@ -97,8 +102,8 @@ class Many2Many(Field):
'''
if not values:
return
relation_obj = model.pool.get(self.relation_name)
target_obj = self.get_target(model.pool)
relation_obj = Pool().get(self.relation_name)
target_obj = self.get_target()
for act in values:
if act[0] == 'create':
for record_id in ids:
@@ -173,20 +178,19 @@ class Many2Many(Field):
else:
raise Exception('Bad arguments')
def get_target(self, pool):
def get_target(self):
'''
Return the target model.
:param pool: The pool
:return: A Model
'''
relation_obj = pool.get(self.relation_name)
relation_obj = Pool().get(self.relation_name)
if not self.target:
return relation_obj
if self.target in relation_obj._columns:
target_obj = pool.get(
target_obj = Pool().get(
relation_obj._columns[self.target].model_name)
else:
target_obj = pool.get(
target_obj = Pool().get(
relation_obj._inherit_fields[self.target][2].model_name)
return target_obj
+7 -4
View File
@@ -3,6 +3,7 @@
from itertools import chain
from trytond.model.fields.field import Field
from trytond.transaction import Transaction
from trytond.pool import Pool
def add_remove_validate(value):
if value:
@@ -70,13 +71,14 @@ class One2Many(Field):
:param values: a dictionary with the read values
:return: a dictionary with ids as key and values as value
'''
pool = Pool()
res = {}
for i in ids:
res[i] = []
ids2 = []
for i in range(0, len(ids), Transaction().cursor.IN_MAX):
sub_ids = ids[i:i + Transaction().cursor.IN_MAX]
ids2.append(model.pool.get(self.model_name).search([
ids2.append(pool.get(self.model_name).search([
(self.field, 'in', sub_ids),
], order=self.order))
@@ -91,12 +93,12 @@ class One2Many(Field):
ids3.append(i)
if ids3:
for i in model.pool.get(self.model_name).read(ids3, [self.field]):
for i in pool.get(self.model_name).read(ids3, [self.field]):
res[i[self.field]].append(i['id'])
index_of_ids2 = dict((i, index) for index, i in enumerate(chain(*ids2)))
for val in res.values():
val.sort(lambda x, y: cmp(index_of_ids2[x], index_of_ids2[y]))
val.sort(key=lambda x: index_of_ids2[x])
return res
def set(self, ids, model, name, values):
@@ -116,9 +118,10 @@ class One2Many(Field):
(``unlink_all``),
(``set``, ``<ids>``)
'''
pool = Pool()
if not values:
return
model = model.pool.get(self.model_name)
model = pool.get(self.model_name)
for act in values:
if act[0] == 'create':
for record_id in ids:
+3 -1
View File
@@ -3,6 +3,7 @@
from trytond.model.fields.many2many import Many2Many
from trytond.transaction import Transaction
from trytond.pool import Pool
class One2One(Many2Many):
@@ -35,7 +36,8 @@ class One2One(Many2Many):
:param name: A string with the name of the field
:param value: The id to link
'''
relation_obj = model.pool.get(self.relation_name)
pool = Pool()
relation_obj = pool.get(self.relation_name)
relation_ids = relation_obj.search([
(self.origin, 'in', ids),
])
+10 -6
View File
@@ -6,6 +6,7 @@ from trytond.model.fields.function import Function
from trytond.model.fields.field import Field
from trytond import backend
from trytond.transaction import Transaction
from trytond.pool import Pool
class Property(Function):
@@ -34,7 +35,8 @@ class Property(Function):
:param values:
:return: a dictionary with ids as key and values as value
'''
property_obj = model.pool.get('ir.property')
pool = Pool()
property_obj = pool.get('ir.property')
res = property_obj.get(name, model._name, ids)
return res
@@ -48,7 +50,8 @@ class Property(Function):
:param name: The name of the field.
:param value: The value to set.
'''
property_obj = model.pool.get('ir.property')
pool = Pool()
property_obj = pool.get('ir.property')
return property_obj.set(name, model._name, ids,
(value and getattr(self, 'model_name', '') + ',' + str(value)) or
False)
@@ -60,10 +63,11 @@ class Property(Function):
:param clause: The search domain clause. See ModelStorage.search
:return: New list of domain.
'''
rule_obj = model.pool.get('ir.rule')
property_obj = model.pool.get('ir.property')
model_obj = model.pool.get('ir.model')
field_obj = model.pool.get('ir.model.field')
pool = Pool()
rule_obj = pool.get('ir.rule')
property_obj = pool.get('ir.property')
model_obj = pool.get('ir.model')
field_obj = pool.get('ir.model.field')
cursor = Transaction().cursor
field_class = backend.FIELDS[self._type]
+4 -3
View File
@@ -1,10 +1,10 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import contextlib
from trytond.model.fields.field import Field
from trytond.tools import safe_eval
from trytond.transaction import Transaction
from trytond.pool import Pool
class Reference(Field):
@@ -42,6 +42,7 @@ class Reference(Field):
:param values: a dictionary with the read values
:return: a dictionary with ids as key and values as value
'''
pool = Pool()
if values is None:
values = {}
res = {}
@@ -76,10 +77,10 @@ class Reference(Field):
with contextlib.nested(Transaction().set_context(active_test=False),
Transaction().set_user(0)):
for ref_model, (ref_ids, ids) in ref_to_check.iteritems():
if ref_model not in model.pool.object_name_list():
if ref_model not in pool.object_name_list():
res.update(dict((i, False) for i in ids))
continue
ref_obj = model.pool.get(ref_model)
ref_obj = pool.get(ref_model)
ref_ids = ref_obj.search([
('id', 'in', list(ref_ids)),
], order=[])
+34 -27
View File
@@ -2,6 +2,7 @@
#this repository contains the full copyright notices and license terms.
import copy
import collections
from trytond.model import fields
from trytond.error import WarningErrorMixin
from trytond.pool import Pool
@@ -16,7 +17,6 @@ class Model(WarningErrorMixin):
_name = None
_inherits = {}
_description = ''
pool = None #XXX change to avoid collision with field
__columns = None
__xxx2many_targets = None
__defaults = None
@@ -54,7 +54,7 @@ class Model(WarningErrorMixin):
fields_names += self._inherit_fields.keys()
for field_name in fields_names:
default_method = getattr(self, 'default_%s' % field_name, False)
if callable(default_method):
if isinstance(default_method, collections.Callable):
res[field_name] = default_method
self.__defaults = res
return res
@@ -98,16 +98,19 @@ class Model(WarningErrorMixin):
for attribute in ('on_change', 'on_change_with', 'autocomplete'):
function_name = '%s_%s' % (attribute, field_name)
if (getattr(field, attribute, False)
and callable(getattr(self, function_name, False))):
and isinstance(getattr(self, function_name, False),
collections.Callable)):
self._rpc.setdefault(function_name, False)
def __getattr__(self, name):
pool = Pool()
# Search if a function exists in inherits parents
for model_name, field_name in self._inherits.iteritems():
model_obj = self.pool.get(model_name)
if hasattr(model_obj, name) and \
callable(getattr(model_obj, name)):
return getattr(model_obj, name)
model_obj = pool.get(model_name)
if (hasattr(model_obj, name)
and isinstance(getattr(model_obj, name),
collections.Callable)):
return getattr(model_obj, name)
raise AttributeError(name)
def _inherits_reload(self):
@@ -115,19 +118,20 @@ class Model(WarningErrorMixin):
Reconstruct _inherit_fields
"""
res = {}
pool = Pool()
for model in self._inherits:
res.update(self.pool.get(model)._inherit_fields)
for field_name in self.pool.get(model)._columns.keys():
res.update(pool.get(model)._inherit_fields)
for field_name in pool.get(model)._columns.keys():
res[field_name] = (model, self._inherits[model],
self.pool.get(model)._columns[field_name])
for field_name in self.pool.get(model)._inherit_fields.keys():
pool.get(model)._columns[field_name])
for field_name in pool.get(model)._inherit_fields.keys():
res[field_name] = (model, self._inherits[model],
self.pool.get(model)._inherit_fields[field_name][2])
pool.get(model)._inherit_fields[field_name][2])
self._inherit_fields = res
self._reset_xxx2many_targets()
# Update objects that uses this one to update their _inherits fields
for obj_name in self.pool.object_name_list():
obj = self.pool.get(obj_name)
for obj_name in pool.object_name_list():
obj = pool.get(obj_name)
if self._name in obj._inherits:
obj._inherits_reload()
@@ -148,7 +152,7 @@ class Model(WarningErrorMixin):
continue
if hasattr(field, 'get_target'):
try:
model_name = field.get_target(self.pool)._name
model_name = field.get_target()._name
except KeyError:
to_cache = False
continue
@@ -166,7 +170,7 @@ class Model(WarningErrorMixin):
continue
if hasattr(field, 'get_target'):
try:
model_name = field.get_target(self.pool)._name
model_name = field.get_target()._name
except KeyError:
to_cache = False
continue
@@ -186,7 +190,7 @@ class Model(WarningErrorMixin):
:param module_name: the module name
"""
translation_obj = self.pool.get('ir.translation')
translation_obj = Pool().get('ir.translation')
cursor = Transaction().cursor
# Add model in ir_model
@@ -388,7 +392,8 @@ class Model(WarningErrorMixin):
:return: a dictionary with field name as key
and default value as value
'''
property_obj = self.pool.get('ir.property')
pool = Pool()
property_obj = pool.get('ir.property')
value = {}
# get the default values defined in the object
@@ -407,7 +412,7 @@ class Model(WarningErrorMixin):
if (with_rec_name
and field._type in ('many2one',)
and value.get(field_name)):
obj = self.pool.get(field.model_name)
obj = pool.get(field.model_name)
if 'rec_name' in obj._columns:
value[field_name + '.rec_name'] = obj.browse(
value[field_name]).rec_name
@@ -427,10 +432,11 @@ class Model(WarningErrorMixin):
:param value: a dictionnary with the default value
:return: a new dictionnary of default value
"""
pool = Pool()
res = value.copy()
val = {}
for i in self._inherits.keys():
val.update(self.pool.get(i)._default_on_change(value))
val.update(pool.get(i)._default_on_change(value))
for field in value.keys():
if field in self._columns:
if self._columns[field].on_change:
@@ -443,7 +449,7 @@ class Model(WarningErrorMixin):
args[arg] = args[arg][0]
val.update(getattr(self, 'on_change_' + field)(args))
if self._columns[field]._type in ('one2many',):
obj = self.pool.get(self._columns[field].model_name)
obj = pool.get(self._columns[field].model_name)
for val2 in res[field]:
val2.update(obj._default_on_change(val2))
res.update(val)
@@ -457,12 +463,13 @@ class Model(WarningErrorMixin):
:return: a dictionary with field name as key and definition as value
"""
res = {}
translation_obj = self.pool.get('ir.translation')
model_access_obj = self.pool.get('ir.model.access')
field_access_obj = self.pool.get('ir.model.field.access')
pool = Pool()
translation_obj = pool.get('ir.translation')
model_access_obj = pool.get('ir.model.access')
field_access_obj = pool.get('ir.model.field.access')
for parent in self._inherits:
res.update(self.pool.get(parent).fields_get(fields_names))
res.update(pool.get(parent).fields_get(fields_names))
write_access = model_access_obj.check(self._name, 'write',
raise_exception=False)
@@ -576,8 +583,8 @@ class Model(WarningErrorMixin):
if hasattr(self._columns[field], 'model_name'):
relation = copy.copy(self._columns[field].model_name)
else:
relation = copy.copy(self._columns[field].get_target(
self.pool)._name)
relation = copy.copy(
self._columns[field].get_target()._name)
res[field]['relation'] = relation
res[field]['domain'] = copy.copy(self._columns[field].domain)
res[field]['context'] = copy.copy(self._columns[field].context)
+69 -55
View File
@@ -1,17 +1,20 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import contextlib
import datetime
import re
from functools import reduce
from decimal import Decimal
from itertools import islice
from trytond.model import ModelStorage
from trytond.model import fields
from trytond.backend import FIELDS, TableHandler
from trytond.backend import DatabaseIntegrityError, Database
from trytond.tools import reduce_ids
from trytond.const import OPERATORS
from trytond.const import OPERATORS, RECORD_CACHE_SIZE
from trytond.transaction import Transaction
from trytond.pool import Pool
from trytond.cache import LRUDict
_RE_UNIQUE = re.compile('UNIQUE\s*\((.*)\)', re.I)
_RE_CHECK = re.compile('CHECK\s*\((.*)\)', re.I)
@@ -43,6 +46,8 @@ class ModelSQL(ModelStorage):
if self.table_query():
return
pool = Pool()
# create/update table in the database
table = TableHandler(Transaction().cursor, self, module_name)
if self._history:
@@ -133,7 +138,7 @@ class ModelSQL(ModelStorage):
if field.model_name in ('res.user', 'res.group'):
ref = field.model_name.replace('.','_')
else:
ref = self.pool.get(field.model_name)._table
ref = pool.get(field.model_name)._table
table.add_fk(field_name, ref, field.ondelete)
table.index_action(
@@ -202,10 +207,11 @@ class ModelSQL(ModelStorage):
'''
Return the default value for sequence field.
'''
pool = Pool()
table = self._table
if 'sequence' not in self._columns:
for model in self._inherits:
model_obj = self.pool.get(model)
model_obj = pool.get(model)
if 'sequence' in model_obj._columns:
table = model_obj._table
break
@@ -229,6 +235,7 @@ class ModelSQL(ModelStorage):
def create(self, values):
super(ModelSQL, self).create(values)
cursor = Transaction().cursor
pool = Pool()
if self.table_query():
return False
@@ -284,11 +291,10 @@ class ModelSQL(ModelStorage):
continue
if inherits in tocreate:
tocreate[inherits][i] = values[i]
if i not in self._columns:
del values[i]
del values[i]
for inherits in tocreate:
inherits_obj = self.pool.get(inherits)
inherits_obj = pool.get(inherits)
inherits_id = inherits_obj.create(tocreate[inherits])
values[self._inherits[inherits]] = inherits_id
@@ -354,7 +360,7 @@ class ModelSQL(ModelStorage):
field_name))
if isinstance(field, fields.Many2One) \
and values.get(field_name):
model_obj = self.pool.get(field.model_name)
model_obj = pool.get(field.model_name)
create_records = Transaction().create_records.get(
field.model_name, set())
delete_records = Transaction().delete_records.get(
@@ -375,7 +381,7 @@ class ModelSQL(ModelStorage):
self.raise_user_error(error)
raise
domain1, domain2 = self.pool.get('ir.rule').domain_get(self._name,
domain1, domain2 = pool.get('ir.rule').domain_get(self._name,
mode='create')
if domain1:
cursor.execute('SELECT id FROM "' + self._table + '" ' \
@@ -388,7 +394,7 @@ class ModelSQL(ModelStorage):
for field in values:
if getattr(self._columns[field], 'translate', False):
self.pool.get('ir.translation')._set_ids(
pool.get('ir.translation')._set_ids(
self._name + ',' + field, 'model',
Transaction().language, [id_new], values[field])
@@ -417,8 +423,9 @@ class ModelSQL(ModelStorage):
return id_new
def read(self, ids, fields_names=None):
rule_obj = self.pool.get('ir.rule')
translation_obj = self.pool.get('ir.translation')
pool = Pool()
rule_obj = pool.get('ir.rule')
translation_obj = pool.get('ir.translation')
super(ModelSQL, self).read(ids, fields_names=fields_names)
cursor = Transaction().cursor
@@ -561,7 +568,7 @@ class ModelSQL(ModelStorage):
for field_related in fields_related[inherit_field]:
inherit_related_fields.append(
inherit_field + '.' + field_related)
res2 = self.pool.get(table).read([x[field] for x in res],
res2 = pool.get(table).read([x[field] for x in res],
fields_names=inherits_fields + inherit_related_fields)
res3 = {}
@@ -633,9 +640,9 @@ class ModelSQL(ModelStorage):
fields_related2values.setdefault(field, {})
if self._columns[field]._type in ('many2one', 'one2one'):
if hasattr(self._columns[field], 'model_name'):
obj = self.pool.get(self._columns[field].model_name)
obj = pool.get(self._columns[field].model_name)
else:
obj = self._columns[field].get_target(self.pool)
obj = self._columns[field].get_target()
if hasattr(self._columns[field], 'datetime_field') \
and self._columns[field].datetime_field:
for record in res:
@@ -669,7 +676,7 @@ class ModelSQL(ModelStorage):
record_id = int(record_id)
if not record_id:
continue
obj = self.pool.get(model_name)
obj = pool.get(model_name)
record2 = obj.read(record_id, fields_related[field])
del record2['id']
fields_related2values[field][record_id] = record2
@@ -708,6 +715,8 @@ class ModelSQL(ModelStorage):
def write(self, ids, values):
cursor = Transaction().cursor
pool = Pool()
translation_obj = pool.get('ir.translation')
# Call before cursor cache cleaning
trigger_eligibles = self.trigger_write_get_eligibles(
@@ -757,7 +766,7 @@ class ModelSQL(ModelStorage):
cursor.execute("SELECT id " \
'FROM "' + self._table + '" ' \
'WHERE ' + ' OR '.join(
(clause,) * (len(args)/2)), args)
(clause,) * (len(args) // 2)), args)
if cursor.fetchone():
raise Exception('ConcurrencyException',
'Records were modified in the meanwhile')
@@ -816,7 +825,7 @@ class ModelSQL(ModelStorage):
upd1.append(Transaction().user)
upd1.append(datetime.datetime.now())
domain1, domain2 = self.pool.get('ir.rule').domain_get(self._name,
domain1, domain2 = pool.get('ir.rule').domain_get(self._name,
mode='write')
if domain1:
domain1 = ' AND (' + domain1 + ') '
@@ -869,7 +878,7 @@ class ModelSQL(ModelStorage):
field_name))
if isinstance(field, fields.Many2One) \
and values[field_name]:
model_obj = self.pool.get(field.model_name)
model_obj = pool.get(field.model_name)
create_records = Transaction().create_records.get(
field.model_name, set())
delete_records = Transaction().delete_records.get(
@@ -892,7 +901,7 @@ class ModelSQL(ModelStorage):
for field in direct:
if getattr(self._columns[field], 'translate', False):
self.pool.get('ir.translation')._set_ids(
translation_obj._set_ids(
self._name + ',' + field, 'model',
Transaction().language, ids, values[field])
@@ -925,7 +934,7 @@ class ModelSQL(ModelStorage):
for val in updend:
if self._inherit_fields[val][0] == table:
values2[val] = values[val]
self.pool.get(table).write(nids, values2)
pool.get(table).write(nids, values2)
self._validate(ids)
@@ -951,6 +960,7 @@ class ModelSQL(ModelStorage):
def delete(self, ids):
cursor = Transaction().cursor
pool = Pool()
if not ids:
return True
@@ -1006,7 +1016,7 @@ class ModelSQL(ModelStorage):
foreign_keys_tocheck = []
foreign_keys_toupdate = []
foreign_keys_todelete = []
for _, model in self.pool.iterobject():
for _, model in pool.iterobject():
if hasattr(model, 'table_query') \
and model.table_query():
continue
@@ -1027,7 +1037,7 @@ class ModelSQL(ModelStorage):
Transaction().delete.setdefault(self._name, set()).update(ids)
domain1, domain2 = self.pool.get('ir.rule').domain_get(self._name,
domain1, domain2 = pool.get('ir.rule').domain_get(self._name,
mode='delete')
if domain1:
domain1 = ' AND (' + domain1 + ') '
@@ -1123,7 +1133,8 @@ class ModelSQL(ModelStorage):
def search(self, domain, offset=0, limit=None, order=None, count=False,
query_string=False):
rule_obj = self.pool.get('ir.rule')
pool = Pool()
rule_obj = pool.get('ir.rule')
cursor = Transaction().cursor
# Get domain clauses
@@ -1196,11 +1207,11 @@ class ModelSQL(ModelStorage):
datas = cursor.dictfetchmany(cursor.IN_MAX)
cache = cursor.get_cache()
cache.setdefault(self._name, {})
cache.setdefault(self._name, LRUDict(RECORD_CACHE_SIZE))
delete_records = Transaction().delete_records.setdefault(self._name,
set())
keys = None
for data in datas:
for data in islice(datas, 0, cache.size_limit):
if data['id'] in delete_records:
continue
if not keys:
@@ -1215,8 +1226,7 @@ class ModelSQL(ModelStorage):
continue
for k in keys:
del data[k]
cache[self._name].setdefault(data['id'], {})
cache[self._name][data['id']].update(data)
cache[self._name].setdefault(data['id'], {}).update(data)
if len(datas) >= cursor.IN_MAX:
select_fields2 = [select_fields[0]]
@@ -1284,6 +1294,7 @@ class ModelSQL(ModelStorage):
return qu1, qu2, tables, tables_args
def __search_domain_oper(self, domain, tables, tables_args):
pool = Pool()
operator = 'AND'
if len(domain) and isinstance(domain[0], basestring):
if domain[0] not in ('AND', 'OR'):
@@ -1323,6 +1334,7 @@ class ModelSQL(ModelStorage):
return qu1, qu2
def __search_domain_calc(self, domain, tables, tables_args):
pool = Pool()
domain = domain[:]
cursor = Transaction().cursor
@@ -1336,7 +1348,7 @@ class ModelSQL(ModelStorage):
table = self
fargs = domain[i][0].split('.', 1)
if fargs[0] in self._inherit_fields:
itable = self.pool.get(self._inherit_fields[fargs[0]][0])
itable = pool.get(self._inherit_fields[fargs[0]][0])
table_query = ''
table_arg = []
if itable.table_query():
@@ -1344,7 +1356,7 @@ class ModelSQL(ModelStorage):
table_query = '(' + table_query + ') AS '
table_join = 'LEFT JOIN ' + table_query + \
'"' + itable._table + '" ON ' \
'"%s".id = "%s".%s' % (itable._table, self._table,
'"%s".id = "%s"."%s"' % (itable._table, self._table,
self._inherits[itable._name])
if table_join not in tables:
tables.append(table_join)
@@ -1354,11 +1366,11 @@ class ModelSQL(ModelStorage):
if not fargs[0] in self._inherit_fields:
raise Exception('ValidateError', 'Field "%s" doesn\'t ' \
'exist on "%s"' % (fargs[0], self._name))
table = self.pool.get(self._inherit_fields[fargs[0]][0])
table = pool.get(self._inherit_fields[fargs[0]][0])
field = table._columns.get(fargs[0], False)
if len(fargs) > 1:
if field._type == 'many2one':
target_obj = self.pool.get(field.model_name)
target_obj = pool.get(field.model_name)
if hasattr(field, 'search'):
domain.extend([(fargs[0], 'in', target_obj.search([
(fargs[1], domain[i][1], domain[i][2]),
@@ -1372,11 +1384,11 @@ class ModelSQL(ModelStorage):
continue
elif field._type in ('one2one', 'many2many', 'one2many'):
if hasattr(field, 'model_name'):
target_obj = self.pool.get(field.model_name)
target_obj = pool.get(field.model_name)
else:
target_obj = field.get_target(self.pool)
target_obj = field.get_target()
if hasattr(field, 'relation_name'):
relation_obj = self.pool.get(field.relation_name)
relation_obj = pool.get(field.relation_name)
origin, target = field.origin, field.target
else:
relation_obj = target_obj
@@ -1403,7 +1415,7 @@ class ModelSQL(ModelStorage):
clause = domain.pop(i)
domain.extend(field.search(table, clause[0], clause))
elif field._type == 'one2many':
field_obj = self.pool.get(field.model_name)
field_obj = pool.get(field.model_name)
if isinstance(domain[i][2], basestring):
# get the ids of the records of the "distant" resource
@@ -1459,9 +1471,9 @@ class ModelSQL(ModelStorage):
elif field._type in ('many2many', 'one2one'):
# XXX must find a solution for long id list
if hasattr(field, 'model_name'):
target_obj = self.pool.get(field.model_name)
target_obj = pool.get(field.model_name)
else:
target_obj = field.get_target(self.pool)
target_obj = field.get_target()
if domain[i][1] in ('child_of', 'not child_of'):
if isinstance(domain[i][2], basestring):
ids2 = [x[0] for x in target_obj.search([
@@ -1489,7 +1501,7 @@ class ModelSQL(ModelStorage):
ids2 = target_obj.search([
(domain[i][3], 'child_of', ids2),
], order=[])
relation_obj = self.pool.get(field.relation_name)
relation_obj = pool.get(field.relation_name)
red_sql, red_ids = reduce_ids('"' + field.target + '"',
ids2)
query1 = 'SELECT "' + field.origin + '" ' \
@@ -1510,7 +1522,7 @@ class ModelSQL(ModelStorage):
table, domain[i][0]))
else:
if isinstance(domain[i][2], bool):
relation_obj = self.pool.get(field.relation_name)
relation_obj = pool.get(field.relation_name)
query1 = 'SELECT "' + field.origin + '" ' \
'FROM "' + relation_obj._table + '" '\
'WHERE "' + field.origin + '" IS NOT NULL'
@@ -1524,7 +1536,7 @@ class ModelSQL(ModelStorage):
target_field = 'rec_name'
else:
target_field = 'id'
relation_obj = self.pool.get(field.relation_name)
relation_obj = pool.get(field.relation_name)
query1, query2 = target_obj.search([
(target_field, domain[i][1], domain[i][2]),
@@ -1539,7 +1551,7 @@ class ModelSQL(ModelStorage):
# XXX must find a solution for long id list
if domain[i][1] in ('child_of', 'not child_of'):
if isinstance(domain[i][2], basestring):
field_obj = self.pool.get(field.model_name)
field_obj = pool.get(field.model_name)
ids2 = [x[0] for x in field_obj.search([
('rec_name', 'like', domain[i][2]),
], order=[])]
@@ -1562,7 +1574,7 @@ class ModelSQL(ModelStorage):
raise Exception('Error', 'Programming error: ' \
'child_of on field "%s" is not allowed!' % \
(domain[i][0],))
ids2 = self.pool.get(field.model_name).search([
ids2 = pool.get(field.model_name).search([
(domain[i][3], 'child_of', ids2),
], order=[])
if domain[i][1] == 'child_of':
@@ -1599,9 +1611,9 @@ class ModelSQL(ModelStorage):
ids2, table, domain[i][0]), table)
else:
if isinstance(domain[i][2], basestring):
field_obj = self.pool.get(field.model_name)
field_obj = pool.get(field.model_name)
res_ids = field_obj.search([
(field_obj._rec_name, domain[i][1], domain[i][2]),
('rec_name', domain[i][1], domain[i][2]),
], order=[])
domain[i] = (domain[i][0], 'in', res_ids, table)
else:
@@ -1652,7 +1664,7 @@ class ModelSQL(ModelStorage):
table_query, table_args = table.table_query()
table_query = '(' + table_query + ') AS '
translation_obj = self.pool.get('ir.translation')
translation_obj = pool.get('ir.translation')
qu1, qu2, tables, table_args = \
translation_obj.search_domain([
@@ -1803,6 +1815,7 @@ class ModelSQL(ModelStorage):
return qu1, qu2
def _order_calc(self, field, otype):
pool = Pool()
order_by = []
tables = []
tables_args = {}
@@ -1820,7 +1833,7 @@ class ModelSQL(ModelStorage):
field_name = self._columns[field].order_field
if isinstance(self._columns[field], fields.Many2One):
obj = self.pool.get(self._columns[field].model_name)
obj = pool.get(self._columns[field].model_name)
table_name = obj._table
link_field = field
field_name = None
@@ -1836,7 +1849,7 @@ class ModelSQL(ModelStorage):
otype)
table_join = 'LEFT JOIN "' + table_name + '" AS ' \
'"' + table_name + '.' + link_field + '" ON ' \
'"%s.%s".id = "%s".%s' % (table_name, link_field,
'"%s.%s".id = "%s"."%s"' % (table_name, link_field,
self._table, link_field)
for i in range(len(order_by)):
if table_name in order_by[i]:
@@ -1855,12 +1868,12 @@ class ModelSQL(ModelStorage):
obj2 = None
if obj._rec_name in obj._inherit_fields.keys():
obj2 = self.pool.get(
obj2 = pool.get(
obj._inherit_fields[obj._rec_name][0])
field_name = obj._rec_name
if obj._order_name in obj._inherit_fields.keys():
obj2 = self.pool.get(
obj2 = pool.get(
obj._inherit_fields[obj._order_name][0])
field_name = obj._order_name
@@ -1872,7 +1885,7 @@ class ModelSQL(ModelStorage):
table_join = 'LEFT JOIN "' + table_name + '" AS ' \
'"' + table_name + '.' + link_field + '" ON ' \
'"%s.%s".id = "%s".%s' % \
'"%s.%s".id = "%s"."%s"' % \
(table_name, link_field, self._table, link_field)
for i in range(len(order_by)):
if table_name in order_by[i]:
@@ -1891,7 +1904,7 @@ class ModelSQL(ModelStorage):
table_join2 = 'LEFT JOIN "' + table_name2 + '" AS ' \
'"' + table_name2 + '.' + link_field2 + '" ON ' \
'"%s.%s".id = "%s.%s".%s' % \
'"%s.%s".id = "%s.%s"."%s"' % \
(table_name2, link_field2, table_name, link_field,
link_field2)
for i in range(len(order_by)):
@@ -1994,18 +2007,19 @@ class ModelSQL(ModelStorage):
return order_by, tables, tables_args
if field in self._inherit_fields.keys():
obj = self.pool.get(self._inherit_fields[field][0])
obj = pool.get(self._inherit_fields[field][0])
table_name = obj._table
link_field = self._inherits[obj._name]
order_by, tables, tables_args = obj._order_calc(field, otype)
table_join = 'LEFT JOIN "' + table_name + '" ON ' \
'"%s".id = "%s".%s' % \
'"%s".id = "%s"."%s"' % \
(table_name, self._table, link_field)
if table_join not in tables:
tables.insert(0, table_join)
return order_by, tables, tables_args
raise Exception('Error', 'Wrong field name (%s) in order!' % field)
raise Exception('Error', 'Wrong field name (%s) for %s in order!' %
(field, self._name))
def _rebuild_tree(self, parent, parent_id, left):
'''
+52 -36
View File
@@ -1,7 +1,6 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import datetime
import time
from decimal import Decimal
@@ -12,6 +11,9 @@ try:
except ImportError:
import StringIO
import csv
from functools import reduce
import traceback
import sys
from trytond.model import Model
from trytond.model import fields
from trytond.model.browse import BrowseRecordList, BrowseRecord, \
@@ -19,8 +21,10 @@ from trytond.model.browse import BrowseRecordList, BrowseRecord, \
from trytond.model.browse import EvalEnvironment
from trytond.tools import safe_eval, reduce_domain
from trytond.pyson import PYSONEncoder, PYSONDecoder, PYSON
from trytond.const import OPERATORS
from trytond.const import OPERATORS, RECORD_CACHE_SIZE
from trytond.transaction import Transaction
from trytond.pool import Pool
from trytond.cache import LRUDict
class ModelStorage(Model):
@@ -62,7 +66,7 @@ class ModelStorage(Model):
def __clean_xxx2many_cache(self):
# Clean cursor cache
to_clean = [(model._name, field_name)
for model_name, model in self.pool.iterobject(type='model')
for model_name, model in Pool().iterobject(type='model')
for field_name, target_name in model._xxx2many_targets
if target_name == self._name]
for cache in Transaction().cursor.cache.values():
@@ -81,8 +85,9 @@ class ModelStorage(Model):
and created values as value
:return: the id of the created record
'''
model_access_obj = self.pool.get('ir.model.access')
model_field_access_obj = self.pool.get('ir.model.field.access')
pool = Pool()
model_access_obj = pool.get('ir.model.access')
model_field_access_obj = pool.get('ir.model.field.access')
model_access_obj.check(self._name, 'create')
model_field_access_obj.check(self._name,
@@ -96,7 +101,7 @@ class ModelStorage(Model):
:param id: the created id
'''
trigger_obj = self.pool.get('ir.trigger')
trigger_obj = Pool().get('ir.trigger')
trigger_ids = trigger_obj.get_triggers(self._name, 'create')
if not trigger_ids:
return
@@ -116,8 +121,9 @@ class ModelStorage(Model):
the dictionnaries will have fields names as key
and fields value as value. The list will not be in the same order.
'''
model_access_obj = self.pool.get('ir.model.access')
model_field_access_obj = self.pool.get('ir.model.field.access')
pool = Pool()
model_access_obj = pool.get('ir.model.access')
model_field_access_obj = pool.get('ir.model.field.access')
model_access_obj.check(self._name, 'read')
model_field_access_obj.check(self._name,
@@ -135,8 +141,9 @@ class ModelStorage(Model):
and written values as value
:return: True if succeed
'''
model_access_obj = self.pool.get('ir.model.access')
model_field_access_obj = self.pool.get('ir.model.field.access')
pool = Pool()
model_access_obj = pool.get('ir.model.access')
model_field_access_obj = pool.get('ir.model.field.access')
model_access_obj.check(self._name, 'write')
model_field_access_obj.check(self._name,
@@ -165,7 +172,7 @@ class ModelStorage(Model):
:param ids: a list of ids
:return: a dictionary of the lists of eligible ids by triggers
'''
trigger_obj = self.pool.get('ir.trigger')
trigger_obj = Pool().get('ir.trigger')
trigger_ids = trigger_obj.get_triggers(self._name, 'write')
if not trigger_ids:
return {}
@@ -185,11 +192,11 @@ class ModelStorage(Model):
:param eligibles: a dictionary of the lists of eligible ids by triggers
'''
trigger_obj = self.pool.get('ir.trigger')
trigger_obj = Pool().get('ir.trigger')
trigger_ids = eligibles.keys()
if not trigger_ids:
return
records = self.browse(chain(*eligibles.values()))
records = self.browse(list(chain(*eligibles.values())))
id2record = dict((x.id, x) for x in records)
triggers = trigger_obj.browse(trigger_ids)
for trigger in triggers:
@@ -208,7 +215,7 @@ class ModelStorage(Model):
:param ids: a list of ids or an id
:return: True if succeed
'''
model_access_obj = self.pool.get('ir.model.access')
model_access_obj = Pool().get('ir.model.access')
model_access_obj.check(self._name, 'delete')
if not self.check_xml_record(ids, None):
@@ -234,7 +241,7 @@ class ModelStorage(Model):
:param ids: the deleted ids
'''
trigger_obj = self.pool.get('ir.trigger')
trigger_obj = Pool().get('ir.trigger')
trigger_ids = trigger_obj.get_triggers(self._name, 'delete')
if not trigger_ids:
return
@@ -257,7 +264,8 @@ class ModelStorage(Model):
new value for the field as value
:return: a list of new ids or the new id
'''
lang_obj = self.pool.get('ir.lang')
pool = Pool()
lang_obj = pool.get('ir.lang')
if default is None:
default = {}
@@ -314,7 +322,7 @@ class ModelStorage(Model):
data, data_o2m = convert_data(field_defs, data)
new_ids[data_id] = self.create(data)
for field_name in data_o2m:
relation_model = self.pool.get(
relation_model = pool.get(
field_defs[field_name]['relation'])
relation_field = field_defs[field_name]['relation_field']
if relation_field:
@@ -511,13 +519,14 @@ class ModelStorage(Model):
:param ids: a list of ids or an id
:return: a BrowseRecordList or a BrowseRecord
'''
local_cache = LRUDict(RECORD_CACHE_SIZE)
if isinstance(ids, (int, long)):
return BrowseRecord(ids, self)
local_cache = {}
return BrowseRecordList((BrowseRecord(x, self, local_cache=local_cache)
return BrowseRecord(ids, self, [ids], local_cache)
return BrowseRecordList((BrowseRecord(x, self, ids, local_cache)
for x in ids))
def __export_row(self, record, fields_names):
pool = Pool()
lines = []
data = ['' for x in range(len(fields_names))]
done = []
@@ -531,7 +540,7 @@ class ModelStorage(Model):
if not isinstance(value, BrowseRecord):
break
field_name = fields_tree[i]
model_obj = self.pool.get(value._model_name)
model_obj = pool.get(value._model_name)
field = model_obj._columns[field_name]
if field.states and 'invisible' in field.states:
pyson_invisible = PYSONEncoder().encode(
@@ -603,6 +612,7 @@ class ModelStorage(Model):
- the exception if failed
- the warning if failed
'''
pool = Pool()
def process_lines(self, datas, prefix, fields_def, position=0):
def warn(msgname, *args):
@@ -625,7 +635,7 @@ class ModelStorage(Model):
def get_many2one(relation, value):
if not value:
return False
relation_obj = self.pool.get(relation)
relation_obj = pool.get(relation)
res = relation_obj.search([
('rec_name', '=', value),
], limit=2)
@@ -643,7 +653,7 @@ class ModelStorage(Model):
if not value:
return False
res = []
relation_obj = self.pool.get(relation)
relation_obj = pool.get(relation)
for word in csv.reader(StringIO.StringIO(value), delimiter=',',
quoting=csv.QUOTE_NONE, escapechar='\\').next():
res2 = relation_obj.search([
@@ -670,7 +680,7 @@ class ModelStorage(Model):
except Exception:
warn('reference_syntax_error', value, '/'.join(field))
return False
relation_obj = self.pool.get(relation)
relation_obj = pool.get(relation)
res = relation_obj.search([
('rec_name', '=', value),
], limit=2)
@@ -775,7 +785,7 @@ class ModelStorage(Model):
# Import one2many fields
nbrmax = 1
for field in todo:
newfd = self.pool.get(fields_def[field]['relation']
newfd = pool.get(fields_def[field]['relation']
).fields_get()
res = process_lines(self, datas, prefix + [field], newfd,
position)
@@ -806,7 +816,7 @@ class ModelStorage(Model):
datas.pop(0)
return (row, nbrmax, translate)
ir_model_data_obj = self.pool.get('ir.model.data')
ir_model_data_obj = pool.get('ir.model.data')
# logger for collecting warnings for the client
warnings = logging.Logger("import")
@@ -840,7 +850,9 @@ class ModelStorage(Model):
logger.error(exp)
# XXX should raise Exception
Transaction().cursor.rollback()
warning = '\n'.join(map(str, exp[1:]) + [warning])
tb_s = reduce(lambda x, y: x + y,
traceback.format_exception(*sys.exc_info()))
warning = '%s\n%s' % (tb_s, warning)
return (-1, res, exp, warning)
done += 1
return (done, 0, 0, 0)
@@ -861,7 +873,7 @@ class ModelStorage(Model):
written values as value
:return: True or False
"""
model_data_obj = self.pool.get('ir.model.data')
model_data_obj = Pool().get('ir.model.data')
# Allow root user to update/delete
if Transaction().user == 0:
return True
@@ -934,7 +946,8 @@ class ModelStorage(Model):
return True
def _get_error_args(self, field_name):
model_field_obj = self.pool.get('ir.model.field')
pool = Pool()
model_field_obj = pool.get('ir.model.field')
error_args = (field_name, self._name)
if model_field_obj:
model_field_ids = model_field_obj.search([
@@ -949,6 +962,7 @@ class ModelStorage(Model):
def _validate(self, ids):
pool = Pool()
if (Transaction().user == 0
and Transaction().context.get('user')):
with Transaction().set_user(Transaction().context.get('user')):
@@ -958,12 +972,12 @@ class ModelStorage(Model):
if not getattr(self, field[0])(ids):
self.raise_user_error(field[1])
if not 'res.user' in self.pool.object_name_list() \
if not 'res.user' in pool.object_name_list() \
or Transaction().user == 0:
ctx_pref = {
}
else:
user_obj = self.pool.get('res.user')
user_obj = pool.get('res.user')
ctx_pref = user_obj.get_preferences(context_only=True)
def is_pyson(test):
@@ -989,9 +1003,9 @@ class ModelStorage(Model):
('many2one', 'many2many', 'one2many', 'one2one')
and field.domain):
if field._type in ('many2one', 'one2many'):
relation_obj = self.pool.get(field.model_name)
relation_obj = pool.get(field.model_name)
else:
relation_obj = field.get_target(self.pool)
relation_obj = field.get_target()
if is_pyson(field.domain):
pyson_domain = PYSONEncoder().encode(field.domain)
for record in records:
@@ -1110,6 +1124,7 @@ class ModelStorage(Model):
field_name)
def _clean_defaults(self, defaults):
pool = Pool()
vals = {}
for field in defaults.keys():
fld_def = (field in self._columns) and self._columns[field] \
@@ -1120,7 +1135,7 @@ class ModelStorage(Model):
else:
vals[field] = defaults[field]
elif fld_def._type in ('one2many',):
obj = self.pool.get(fld_def.model_name)
obj = pool.get(fld_def.model_name)
vals[field] = []
for defaults2 in defaults[field]:
vals2 = obj._clean_defaults(defaults2)
@@ -1139,8 +1154,9 @@ class ModelStorage(Model):
:param ids: a list of id or an id
'''
trigger_obj = self.pool.get('workflow.trigger')
instance_obj = self.pool.get('workflow.instance')
pool = Pool()
trigger_obj = pool.get('workflow.trigger')
instance_obj = pool.get('workflow.instance')
if isinstance(ids, (int, long)):
ids = [ids]
+13 -10
View File
@@ -12,6 +12,7 @@ from trytond.tools import safe_eval
from trytond.pyson import PYSONEncoder, CONTEXT
from trytond.transaction import Transaction
from trytond.cache import Cache
from trytond.pool import Pool
def _find(tree, element):
if element.tag == 'xpath':
@@ -112,6 +113,7 @@ class ModelView(Model):
- md5: the check sum of the dictionary without this checksum
'''
result = {'model': self._name}
pool = Pool()
test = True
model = True
@@ -149,7 +151,7 @@ class ModelView(Model):
# Check if view is not from an inherited model
if sql_res[5] != self._name:
inherit_obj = self.pool.get(sql_res[5])
inherit_obj = pool.get(sql_res[5])
result['arch'] = inherit_obj.fields_view_get(
result['view_id'])['arch']
view_id = inherit_view_id
@@ -164,9 +166,8 @@ class ModelView(Model):
raise_p = False
while True:
try:
sql_inherit.sort(lambda x, y: \
cmp(self._modules_list.index(x[2] or None),
self._modules_list.index(y[2] or None)))
sql_inherit.sort(key=lambda x:
self._modules_list.index(x[2] or None))
break
except ValueError:
if raise_p:
@@ -261,7 +262,8 @@ class ModelView(Model):
return value
def _view_look_dom_arch(self, tree, type, field_children=None):
field_access_obj = self.pool.get('ir.model.field.access')
pool = Pool()
field_access_obj = pool.get('ir.model.field.access')
fields_width = {}
tree_root = tree.getroottree().getroot()
@@ -278,7 +280,7 @@ class ModelView(Model):
# Find field inherited without read access
for inherit_name in self._inherits:
inherit_obj = self.pool.get(inherit_name)
inherit_obj = pool.get(inherit_name)
fread_accesses = field_access_obj.check(inherit_obj._name,
inherit_obj._columns.keys(), 'read', access=True)
fields_to_remove += list(x for x, y in fread_accesses.iteritems()
@@ -301,7 +303,7 @@ class ModelView(Model):
parent.remove(element)
if type == 'tree':
viewtreewidth_obj = self.pool.get('ir.ui.view_tree_width')
viewtreewidth_obj = pool.get('ir.ui.view_tree_width')
viewtreewidth_ids = viewtreewidth_obj.search([
('model', '=', self._name),
('user', '=', Transaction().user),
@@ -345,7 +347,8 @@ class ModelView(Model):
return arch, fields2
def __view_look_dom(self, element, type, fields_width=None):
translation_obj = self.pool.get('ir.translation')
pool = Pool()
translation_obj = pool.get('ir.translation')
if fields_width is None:
fields_width = {}
@@ -366,7 +369,7 @@ class ModelView(Model):
if hasattr(field, 'model_name'):
relation = field.model_name
else:
relation = field.get_target(self.pool)._name
relation = field.get_target()._name
except Exception:
relation = False
if relation and element.tag == 'field':
@@ -396,7 +399,7 @@ class ModelView(Model):
if Transaction().language != 'en_US':
_translate_field(field2)
relation_obj = self.pool.get(relation)
relation_obj = pool.get(relation)
if hasattr(relation_obj, '_view_look_dom_arch'):
xarch, xfields = \
relation_obj._view_look_dom_arch(
+8 -7
View File
@@ -1,8 +1,8 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
from trytond.model import ModelStorage
from trytond.transaction import Transaction
from trytond.pool import Pool
class ModelWorkflow(ModelStorage):
@@ -27,7 +27,7 @@ class ModelWorkflow(ModelStorage):
return res
def delete(self, ids):
instance_obj = self.pool.get('workflow.instance')
instance_obj = Pool().get('workflow.instance')
if isinstance(ids, (int, long)):
ids = [ids]
@@ -49,8 +49,9 @@ class ModelWorkflow(ModelStorage):
:param ids: a list of id or an id
'''
workflow_obj = self.pool.get('workflow')
instance_obj = self.pool.get('workflow.instance')
pool = Pool()
workflow_obj = pool.get('workflow')
instance_obj = pool.get('workflow.instance')
if isinstance(ids, (int, long)):
ids = [ids]
@@ -75,7 +76,7 @@ class ModelWorkflow(ModelStorage):
:param ids: a list of id or an id
'''
instance_obj = self.pool.get('workflow.instance')
instance_obj = Pool().get('workflow.instance')
if isinstance(ids, (int, long)):
ids = [ids]
@@ -96,7 +97,7 @@ class ModelWorkflow(ModelStorage):
:param ids: a list of id or an id
'''
instance_obj = self.pool.get('workflow.instance')
instance_obj = Pool().get('workflow.instance')
if isinstance(ids, (int, long)):
ids = [ids]
@@ -119,7 +120,7 @@ class ModelWorkflow(ModelStorage):
'''
if self._name == 'workflow.instance':
return
instance_obj = self.pool.get('workflow.instance')
instance_obj = Pool().get('workflow.instance')
if isinstance(ids, (int, long)):
ids = [ids]
+6 -4
View File
@@ -1,11 +1,13 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import os, sys, imp
import itertools
import traceback
import logging
import contextlib
from functools import reduce
import imp
import operator
from trytond.backend import Database
import trytond.tools as tools
from trytond.config import CONFIG
@@ -91,7 +93,7 @@ class Node(Singleton):
for attr in ('init', 'update'):
if hasattr(self, attr):
setattr(node, attr, True)
self.childs.sort(lambda x, y: cmp(x.name, y.name))
self.childs.sort(key=operator.attrgetter('name'))
def all_childs(self):
res = []
@@ -334,7 +336,7 @@ def register_classes(reload_p=False):
if i.startswith(module) \
and i != module:
del sys.modules[i]
reload(sys.modules[module])
imp.reload(sys.modules[module])
logger = logging.getLogger('modules')
@@ -352,7 +354,7 @@ def register_classes(reload_p=False):
and i != 'trytond.modules.' + module \
and getattr(sys.modules[i], '_TRYTON_RELOAD', True):
del sys.modules[i]
reload(sys.modules['trytond.modules.' + module])
imp.reload(sys.modules['trytond.modules.' + module])
continue
if os.path.isdir(OPJ(MODULES_PATH, module)):
+58 -60
View File
@@ -1,8 +1,10 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from trytond.modules import load_modules, register_classes
from threading import RLock
import logging
from trytond.modules import load_modules, register_classes
from trytond.transaction import Transaction
import __builtin__
class Pool(object):
@@ -15,32 +17,27 @@ class Pool(object):
_lock = RLock()
_locks = {}
_pool = {}
_pools = {}
test = False
_instances = {}
def __new__(cls, database_name):
cls._lock.acquire()
lock = cls._locks.setdefault(database_name, RLock())
cls._lock.release()
lock.acquire()
if database_name in cls._pools:
res = cls._pools[database_name]
lock.release()
return res
lock.release()
return object.__new__(cls)
def __new__(cls, database_name=None):
if database_name is None:
database_name = Transaction().cursor.database_name
result = cls._instances.get(database_name)
if result:
return result
lock = cls._locks.get(database_name)
if not lock:
with cls._lock:
lock = cls._locks.setdefault(database_name, RLock())
with lock:
return cls._instances.setdefault(database_name,
super(Pool, cls).__new__(cls))
def __init__(self, database_name):
def __init__(self, database_name=None):
if database_name is None:
database_name = Transaction().cursor.database_name
self.database_name = database_name
self._lock.acquire()
lock = self._locks.setdefault(database_name, RLock())
self._lock.release()
lock.acquire()
self._pool.setdefault(database_name, {})
for type in self.classes.keys():
self._pool[database_name].setdefault(type, {})
self._pools.setdefault(database_name, self)
lock.release()
@staticmethod
def register(klass, type='model'):
@@ -57,53 +54,47 @@ class Pool(object):
if module:
Pool.classes[type].setdefault(module, []).append(klass)
@staticmethod
def start():
@classmethod
def start(cls):
'''
Start/restart the Pool
'''
Pool._lock.acquire()
try:
with cls._lock:
reload_p = False
prev_classes = {}
for type in Pool.classes:
if Pool.classes[type]:
for type in cls.classes:
if cls.classes.get(type):
reload_p = True
prev_classes[type] = Pool.classes[type]
Pool.classes[type] = {}
prev_classes[type] = cls.classes.get(type)
cls.classes[type] = {}
try:
register_classes(reload_p=reload_p)
except Exception:
if not reload_p:
raise
for type in prev_classes:
Pool.classes[type] = prev_classes[type]
for db_name in Pool.database_list():
Pool(db_name).init()
finally:
Pool._lock.release()
cls.classes[type] = prev_classes[type]
for db_name in cls.database_list():
cls(db_name).init()
@staticmethod
def stop(database_name):
@classmethod
def stop(cls, database_name):
'''
Stop the Pool
'''
Pool._lock.acquire()
lock = Pool._locks.setdefault(database_name, RLock())
Pool._lock.release()
lock.acquire()
if database_name in Pool._pool:
del Pool._pool[database_name]
if database_name in Pool._pools:
del Pool._pools[database_name]
lock.release()
with cls._lock:
if database_name in cls._instances:
del cls._instances[database_name]
with cls._locks[database_name]:
if database_name in cls._pool:
del cls._pool[database_name]
@staticmethod
def database_list():
@classmethod
def database_list(cls):
'''
:return: database list
'''
return Pool._pool.keys()
return cls._pool.keys()
def init(self, update=False, lang=None):
'''
@@ -115,11 +106,8 @@ class Pool(object):
'''
logger = logging.getLogger('pool')
logger.info('init pool for "%s"' % self.database_name)
self._lock.acquire()
lock = self._locks.setdefault(self.database_name, RLock())
self._lock.release()
lock.acquire()
try:
with self._locks[self.database_name]:
self._pool.setdefault(self.database_name, {})
#Clean the _pool before loading modules
for type in self.classes.keys():
self._pool[self.database_name][type] = {}
@@ -127,8 +115,6 @@ class Pool(object):
lang=lang)
if restart:
self.init()
finally:
lock.release()
def get(self, name, type='model'):
'''
@@ -142,7 +128,19 @@ class Pool(object):
for type in self.classes.keys():
if name in self._pool[self.database_name][type]:
break
return self._pool[self.database_name][type][name]
try:
return self._pool[self.database_name][type][name]
except KeyError:
if type == 'report':
from trytond.report import Report
# Keyword argument 'type' conflicts with builtin function
cls = __builtin__.type(str(name), (Report,), {})
obj = object.__new__(cls)
obj._name = name
self.add(obj, type)
obj.__init__()
return obj
raise
def add(self, obj, type='model'):
'''
@@ -151,8 +149,8 @@ class Pool(object):
:param obj: the object
:param type: the type
'''
self._pool[self.database_name][type][obj._name] = obj
obj.pool = self
with self._locks[self.database_name]:
self._pool[self.database_name][type][obj._name] = obj
def object_name_list(self, type='model'):
'''
+3
View File
@@ -55,6 +55,9 @@ class Float(float):
return self.decimal.__eq__(other)
return super(Float, self).__eq__(other)
def __hash__(self):
return super(Float, self).__hash__()
def __floordiv__(self, other, context=None):
if isinstance(other, Decimal):
return self.decimal.__floordiv__(other, context=context)
-1
View File
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import traceback
import logging
import time
+1 -6
View File
@@ -22,10 +22,7 @@ import posixpath
import urllib
import datetime
from decimal import Decimal
if sys.version_info < (2, 6):
import simplejson as json
else:
import json
import json
def object_hook(dct):
if '__class__' in dct:
@@ -279,8 +276,6 @@ class SimpleThreadedJSONRPCServer(SocketServer.ThreadingMixIn,
timeout = 1
def server_bind(self):
# Python < 2.6 doesn't handle self.timeout
self.socket.settimeout(1)
self.socket.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
SimpleJSONRPCServer.server_bind(self)
-5
View File
@@ -81,11 +81,6 @@ class BaseThreadedHTTPServer(SocketServer.ThreadingMixIn,
max_children = CONFIG['max_thread']
def server_bind(self):
# Python < 2.6 doesn't handle self.timeout
if sys.version_info < (2, 6):
# breaks the socket under BSD, see http://bugs.python.org/issue7995
self.socket.settimeout(1)
self.socket.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
BaseHTTPServer.HTTPServer.server_bind(self)
-2
View File
@@ -204,8 +204,6 @@ class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn,
timeout = 1
def server_bind(self):
# Python < 2.6 doesn't handle self.timeout
self.socket.settimeout(1)
self.socket.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
SimpleXMLRPCServer.SimpleXMLRPCServer.server_bind(self)
+63 -29
View File
@@ -12,6 +12,12 @@ try:
except ImportError:
ssl = None
import gzip
try:
import hashlib
except ImportError:
hashlib = None
import sha
import os
DNS_CACHE = {}
MAX_SIZE = 999999999
@@ -32,7 +38,7 @@ def checkfunction(module, klass):
class PySocket:
def __init__(self, sock=None):
def __init__(self, sock=None, fingerprints=None, ca_certs=None):
self.sock = sock
self.host = None
self.hostname = None
@@ -41,6 +47,11 @@ class PySocket:
self.ssl_sock = None
self.connected = False
self.buffer = ''
self.fingerprints = fingerprints
if ca_certs and os.path.isfile(ca_certs):
self.ca_certs = ca_certs
else:
self.ca_certs = None
def connect(self, host, port=False):
if not port:
@@ -57,7 +68,7 @@ class PySocket:
socket.SOCK_STREAM)
self.sock.settimeout(CONNECT_TIMEOUT)
self.sock.connect((host, int(port)))
except Exception:
except socket.error:
self.sock = None
if self.sock is None:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -72,31 +83,54 @@ class PySocket:
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.settimeout(CONNECT_TIMEOUT)
sock.connect((host, int(port)))
except Exception:
except socket.error:
sock = None
if sock is None:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(CONNECT_TIMEOUT)
sock.connect((host, int(port)))
if ssl:
ssl.wrap_socket(sock)
ssl_sock = ssl.wrap_socket(sock)
self.ssl = True
elif hasattr(socket, 'ssl'):
socket.ssl(sock)
ssl_sock = socket.ssl(sock)
self.ssl = True
except Exception:
except socket.error:
pass
self.sock.settimeout(TIMEOUT)
fingerprint = None
if self.ssl:
if ssl:
self.ssl_sock = ssl.wrap_socket(self.sock)
self.ssl_sock = ssl.wrap_socket(self.sock,
ca_certs=self.ca_certs, cert_reqs=(self.ca_certs and
ssl.CERT_REQUIRED or ssl.CERT_NONE))
elif hasattr(socket, 'ssl'):
self.ssl_sock = socket.ssl(self.sock)
self.ssl_sock = socket.ssl(self.sock, certfile=self.ca_certs)
try:
peercert = self.ssl_sock.getpeercert(True)
except socket.error:
peercert = None
def format_hash(value):
return reduce(lambda x, y: x + y[1].upper() +
((y[0] % 2 and y[0] + 1 < len(value)) and ':' or ''),
enumerate(value), '')
if peercert and hashlib:
fingerprint = format_hash(hashlib.sha1(peercert).hexdigest())
elif peercert:
fingerprint = format_hash(sha1.new(peercert).hexdigest())
self.host = host
self.hostname = hostname
self.port = port
self.connected = True
self.buffer = ''
if self.fingerprints is not None:
key = (self.hostname, str(self.port))
if key in self.fingerprints:
if self.fingerprints[key] != fingerprint:
self.disconnect()
raise Exception('BadFingerprint')
elif fingerprint:
self.fingerprints[key] = fingerprint
def disconnect(self):
try:
@@ -111,10 +145,10 @@ class PySocket:
sock.sock_shutdown(shutdown_value)
else:
sock.shutdown(shutdown_value)
except Exception:
except socket.error:
pass
sock.close()
except Exception:
except socket.error:
pass
self.sock = None
self.ssl = False
@@ -123,20 +157,20 @@ class PySocket:
self.buffer = ''
def reconnect(self):
if self.host and self.port:
if self.hostname and self.port:
self.disconnect()
self.connect(self.host, self.port)
self.connect(self.hostname, self.port)
def send(self, msg, exception=False, traceback=None):
msg = cPickle.dumps([msg, traceback], protocol=2)
gzip_p = False
if len(msg) > GZIP_THRESHOLD:
buf = StringIO.StringIO()
output = gzip.GzipFile(mode='wb', fileobj=buf)
buffer = StringIO.StringIO()
output = gzip.GzipFile(mode='wb', fileobj=buffer)
output.write(msg)
output.close()
buf.seek(0)
msg = buf.getvalue()
buffer.seek(0)
msg = buffer.getvalue()
gzip_p = True
size = len(msg)
msg = str(size) + ' ' + (exception and "1" or "0") \
@@ -148,14 +182,14 @@ class PySocket:
while totalsent < size:
sent = self.ssl_sock.write(msg[totalsent:])
if sent == 0:
raise RuntimeError, "socket connection broken"
raise RuntimeError("socket connection broken")
totalsent = totalsent + sent
else:
self.sock.sendall(msg)
def receive(self):
buf = self.buffer
buf_list = []
L = []
size_remaining = MAX_LENGHT
while size_remaining:
chunk_size = min(size_remaining, 4096)
@@ -164,18 +198,18 @@ class PySocket:
else:
chunk = self.sock.recv(chunk_size)
if chunk == '':
raise RuntimeError, "socket connection broken"
buf_list.append(chunk)
raise RuntimeError("socket connection broken")
L.append(chunk)
size_remaining -= len(chunk)
if ' ' in chunk:
break
if size_remaining < 0:
raise RuntimeError, "socket connection broken"
buf += ''.join(buf_list)
raise RuntimeError("socket connection broken")
buf += ''.join(L)
size, msg = buf.split(' ', 1)
size = int(size)
if size > MAX_SIZE:
raise RuntimeError, "socket connection broken"
raise RuntimeError("socket connection broken")
while len(msg) < 2:
chunk_size = min(size + 2, 4096)
if self.ssl:
@@ -183,11 +217,11 @@ class PySocket:
else:
msg += self.sock.recv(chunk_size)
if msg == '':
raise RuntimeError, "socket connection broken"
raise RuntimeError("socket connection broken")
exception = msg[0] != "0"
gzip_p = msg[1] != "0"
buf_list = [msg[2:]]
size_remaining = size - len(buf_list[0])
L = [msg[2:]]
size_remaining = size - len(L[0])
while size_remaining:
chunk_size = min(size_remaining, 4096)
if self.ssl:
@@ -195,10 +229,10 @@ class PySocket:
else:
chunk = self.sock.recv(chunk_size)
if chunk == '':
raise RuntimeError, "socket connection broken"
buf_list.append(chunk)
raise RuntimeError("socket connection broken")
L.append(chunk)
size_remaining -= len(chunk)
msg = ''.join(buf_list)
msg = ''.join(L)
if len(msg) > size:
self.buffer = msg[size:]
msg = msg[:size]
+3 -5
View File
@@ -1,11 +1,9 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import sys
if sys.version_info < (2, 6):
import simplejson as json
else:
import json
import json
import datetime
from functools import reduce
class PYSON(object):
@@ -405,7 +403,7 @@ class Date(PYSON):
date = date.replace(year=year)
if dct['dM']:
month = date.month + dct['dM']
year = date.year + month / 12
year = date.year + month // 12
month = month % 12
date = date.replace(year=year, month=month)
if dct['dd']:
+9 -5
View File
@@ -104,7 +104,8 @@ class Report(object):
a boolean to direct print,
the report name
'''
action_report_obj = self.pool.get('ir.action.report')
pool = Pool()
action_report_obj = pool.get('ir.action.report')
action_report_ids = action_report_obj.search([
('report_name', '=', self._name)
])
@@ -119,7 +120,8 @@ class Report(object):
action_report.name)
def _get_objects(self, ids, model, datas):
model_obj = self.pool.get(model)
pool = Pool()
model_obj = pool.get(model)
return model_obj.browse(ids)
def parse(self, report, objects, datas, localcontext):
@@ -135,8 +137,9 @@ class Report(object):
report type
report
'''
pool = Pool()
localcontext['datas'] = datas
localcontext['user'] = self.pool.get('res.user'
localcontext['user'] = pool.get('res.user'
).browse(Transaction().user)
localcontext['formatLang'] = lambda *args, **kargs: \
self.format_lang(*args, **kargs)
@@ -147,7 +150,7 @@ class Report(object):
localcontext['context'] = Transaction().context
translate = TranslateFactory(self._name, Transaction().language,
self.pool.get('ir.translation'))
pool.get('ir.translation'))
localcontext['setLang'] = lambda language: translate.set_language(language)
if not report.report_content:
@@ -297,7 +300,8 @@ class Report(object):
def format_lang(self, value, lang, digits=2, grouping=True, monetary=False,
date=False, currency=None, symbol=True):
lang_obj = self.pool.get('ir.lang')
pool = Pool()
lang_obj = pool.get('ir.lang')
if date:
if lang:
+16 -12
View File
@@ -4,12 +4,13 @@
from itertools import chain
from trytond.model import ModelView, ModelSQL, fields
from trytond.transaction import Transaction
from trytond.pool import Pool
class MenuMany2Many(fields.Many2Many):
def get(self, ids, model, name, values=None):
menu_obj = self.get_target(model.pool)
menu_obj = self.get_target()
res = super(MenuMany2Many, self).get(ids, model, name,
values=values)
menu_ids = list(set(chain(*res.values())))
@@ -36,10 +37,10 @@ class Group(ModelSQL, ModelView):
field_access = fields.One2Many('ir.model.field.access', 'group',
'Access Field')
rule_groups = fields.Many2Many('ir.rule.group-res.group',
'group_id', 'rule_group_id', 'Rules',
'group', 'rule_group', 'Rules',
domain=[('global_p', '!=', True), ('default_p', '!=', True)])
menu_access = MenuMany2Many('ir.ui.menu-res.group',
'gid', 'menu_id', 'Access Menu')
'group', 'menu', 'Access Menu')
def __init__(self):
super(Group, self).__init__()
@@ -72,32 +73,35 @@ class Group(ModelSQL, ModelView):
def create(self, vals):
res = super(Group, self).create(vals)
pool = Pool()
# Restart the cache on the domain_get method
self.pool.get('ir.rule').domain_get.reset()
pool.get('ir.rule').domain_get.reset()
# Restart the cache for get_groups
self.pool.get('res.user').get_groups.reset()
pool.get('res.user').get_groups.reset()
# Restart the cache for get_preferences
self.pool.get('res.user').get_preferences.reset()
pool.get('res.user').get_preferences.reset()
return res
def write(self, ids, vals):
res = super(Group, self).write(ids, vals)
pool = Pool()
# Restart the cache on the domain_get method
self.pool.get('ir.rule').domain_get.reset()
pool.get('ir.rule').domain_get.reset()
# Restart the cache for get_groups
self.pool.get('res.user').get_groups.reset()
pool.get('res.user').get_groups.reset()
# Restart the cache for get_preferences
self.pool.get('res.user').get_preferences.reset()
pool.get('res.user').get_preferences.reset()
return res
def delete(self, ids):
res = super(Group, self).delete(ids)
pool = Pool()
# Restart the cache on the domain_get method
self.pool.get('ir.rule').domain_get.reset()
pool.get('ir.rule').domain_get.reset()
# Restart the cache for get_groups
self.pool.get('res.user').get_groups.reset()
pool.get('res.user').get_groups.reset()
# Restart the cache for get_preferences
self.pool.get('res.user').get_preferences.reset()
pool.get('res.user').get_preferences.reset()
return res
Group()
+6 -4
View File
@@ -16,15 +16,12 @@ this repository contains the full copyright notices and license terms. -->
<field name="name"/>
<notebook>
<page string="Members" col="2" id="members">
<separator name="users" colspan="2"/>
<field name="users" colspan="2"/>
</page>
<page string="Access Permissions" col="2" id="permissions">
<field name="model_access"/>
<field name="field_access"/>
<separator name="menu_access" colspan="2"/>
<field name="menu_access" colspan="2"/>
<separator name="rule_groups" colspan="2"/>
<field name="rule_groups" colspan="2"/>
</page>
</notebook>
@@ -60,8 +57,13 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="group_view_form"/>
<field name="act_window" ref="act_group_form"/>
</record>
<menuitem parent="res.menu_res" groups="group_admin"
<menuitem parent="res.menu_res"
action="act_group_form" id="menu_group_form"/>
<record model="ir.ui.menu-res.group" id="menu_group_form_admin">
<field name="menu" ref="menu_group_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.model.access" id="access_group">
<field name="model" search="[('model', '=', 'res.group')]"/>
<field name="perm_read" eval="True"/>
+47 -20
View File
@@ -3,15 +3,16 @@
from trytond.model import ModelView, ModelSQL, fields
from trytond.backend import TableHandler
from trytond.transaction import Transaction
from trytond.pool import Pool
class UIMenuGroup(ModelSQL):
"UI Menu - Group"
_name = 'ir.ui.menu-res.group'
_description = __doc__
menu_id = fields.Many2One('ir.ui.menu', 'Menu', ondelete='CASCADE',
menu = fields.Many2One('ir.ui.menu', 'Menu', ondelete='CASCADE',
select=1, required=True)
gid = fields.Many2One('res.group', 'Group', ondelete='CASCADE',
group = fields.Many2One('res.group', 'Group', ondelete='CASCADE',
select=1, required=True)
def init(self, module_name):
@@ -20,24 +21,28 @@ class UIMenuGroup(ModelSQL):
TableHandler.table_rename(cursor, 'ir_ui_menu_group_rel', self._table)
TableHandler.sequence_rename(cursor, 'ir_ui_menu_group_rel_id_seq',
self._table + '_id_seq')
# Migration from 2.0 menu_id and gid renamed into menu group
table = TableHandler(cursor, self, module_name)
table.column_rename('menu_id', 'menu')
table.column_rename('gid', 'group')
super(UIMenuGroup, self).init(module_name)
def create(self, vals):
res = super(UIMenuGroup, self).create(vals)
# Restart the cache on the domain_get method
self.pool.get('ir.rule').domain_get.reset()
Pool().get('ir.rule').domain_get.reset()
return res
def write(self, ids, vals):
res = super(UIMenuGroup, self).write(ids, vals)
# Restart the cache on the domain_get method
self.pool.get('ir.rule').domain_get.reset()
Pool().get('ir.rule').domain_get.reset()
return res
def delete(self, ids):
res = super(UIMenuGroup, self).delete(ids)
# Restart the cache on the domain_get method
self.pool.get('ir.rule').domain_get.reset()
Pool().get('ir.rule').domain_get.reset()
return res
UIMenuGroup()
@@ -47,9 +52,9 @@ class ActionGroup(ModelSQL):
"Action - Group"
_name = 'ir.action-res.group'
_description = __doc__
action_id = fields.Many2One('ir.action', 'Action', ondelete='CASCADE',
action = fields.Many2One('ir.action', 'Action', ondelete='CASCADE',
select=1, required=True)
gid = fields.Many2One('res.group', 'Group', ondelete='CASCADE',
group = fields.Many2One('res.group', 'Group', ondelete='CASCADE',
select=1, required=True)
def init(self, module_name):
@@ -58,24 +63,36 @@ class ActionGroup(ModelSQL):
TableHandler.table_rename(cursor, 'ir_action_group_rel', self._table)
TableHandler.sequence_rename(cursor, 'ir_action_group_rel_id_seq',
self._table + '_id_seq')
# Migration from 2.0 action_id and gid renamed into action and group
table = TableHandler(cursor, self, module_name)
table.column_rename('action_id', 'action')
table.column_rename('gid', 'group')
super(ActionGroup, self).init(module_name)
def create(self, vals):
action_obj = Pool().get('ir.action')
if vals.get('action'):
vals = vals.copy()
vals['action'] = action_obj.get_action_id(vals['action'])
res = super(ActionGroup, self).create(vals)
# Restart the cache on the domain_get method
self.pool.get('ir.rule').domain_get.reset()
Pool().get('ir.rule').domain_get.reset()
return res
def write(self, ids, vals):
action_obj = Pool().get('ir.action')
if vals.get('action'):
vals = vals.copy()
vals['action'] = action_obj.get_action_id(vals['action'])
res = super(ActionGroup, self).write(ids, vals)
# Restart the cache on the domain_get method
self.pool.get('ir.rule').domain_get.reset()
Pool().get('ir.rule').domain_get.reset()
return res
def delete(self, ids):
res = super(ActionGroup, self).delete(ids)
# Restart the cache on the domain_get method
self.pool.get('ir.rule').domain_get.reset()
Pool().get('ir.rule').domain_get.reset()
return res
ActionGroup()
@@ -105,9 +122,9 @@ class RuleGroupGroup(ModelSQL):
"Rule Group - Group"
_name = 'ir.rule.group-res.group'
_description = __doc__
rule_group_id = fields.Many2One('ir.rule.group', 'Rule Group',
rule_group = fields.Many2One('ir.rule.group', 'Rule Group',
ondelete='CASCADE', select=1, required=True)
group_id = fields.Many2One('res.group', 'Group', ondelete='CASCADE',
group = fields.Many2One('res.group', 'Group', ondelete='CASCADE',
select=1, required=True)
def init(self, module_name):
@@ -116,6 +133,11 @@ class RuleGroupGroup(ModelSQL):
TableHandler.table_rename(cursor, 'group_rule_group_rel', self._table)
TableHandler.sequence_rename(cursor, 'group_rule_group_rel_id_seq',
self._table + '_id_seq')
# Migration from 2.0 rule_group_id and group_id renamed into rule_group
# and group
table = TableHandler(cursor, self, module_name)
table.column_rename('rule_group_id', 'rule_group')
table.column_rename('group_id', 'group')
super(RuleGroupGroup, self).init(module_name)
RuleGroupGroup()
@@ -125,9 +147,9 @@ class RuleGroupUser(ModelSQL):
"Rule Group - User"
_name = 'ir.rule.group-res.user'
_description = __doc__
rule_group_id = fields.Many2One('ir.rule.group', 'Rule Group',
rule_group = fields.Many2One('ir.rule.group', 'Rule Group',
ondelete='CASCADE', select=1, required=True)
user_id = fields.Many2One('res.user', 'User', ondelete='CASCADE',
user = fields.Many2One('res.user', 'User', ondelete='CASCADE',
select=1, required=True)
def init(self, module_name):
@@ -136,6 +158,11 @@ class RuleGroupUser(ModelSQL):
TableHandler.table_rename(cursor, 'user_rule_group_rel', self._table)
TableHandler.sequence_rename(cursor, 'user_rule_group_rel_id_seq',
self._table + '_id_seq')
# Migration from 2.0 rule_group_id and user_id renamed into rule_group
# and user
table = TableHandler(cursor, self, module_name)
table.column_rename('rule_group_id', 'rule_group')
table.column_rename('user_id', 'user')
super(RuleGroupUser, self).init(module_name)
RuleGroupUser()
@@ -147,7 +174,7 @@ class Lang(ModelSQL, ModelView):
def write(self, ids, vals):
res = super(Lang, self).write(ids, vals)
# Restart the cache for get_preferences
self.pool.get('res.user').get_preferences.reset()
Pool().get('res.user').get_preferences.reset()
return res
Lang()
@@ -172,21 +199,21 @@ class SequenceTypeGroup(ModelSQL):
ondelete='CASCADE', select=1, required=True)
def delete(self, ids):
rule_obj = self.pool.get('ir.rule')
rule_obj = Pool().get('ir.rule')
res = super(SequenceTypeGroup, self).delete(ids)
# Restart the cache on the domain_get method of ir.rule
rule_obj.domain_get.reset()
return res
def create(self, vals):
rule_obj = self.pool.get('ir.rule')
rule_obj = Pool().get('ir.rule')
res = super(SequenceTypeGroup, self).create(vals)
# Restart the cache on the domain_get method of ir.rule
rule_obj.domain_get.reset()
return res
def write(self, ids, vals):
rule_obj = self.pool.get('ir.rule')
rule_obj = Pool().get('ir.rule')
res = super(SequenceTypeGroup, self).write(ids, vals)
# Restart the cache on the domain_get method
rule_obj.domain_get.reset()
@@ -201,7 +228,7 @@ class Sequence(ModelSQL, ModelView):
'User Groups'), 'get_groups', searcher='search_groups')
def get_groups(self, ids, name):
sequence_type_obj = self.pool.get('ir.sequence.type')
sequence_type_obj = Pool().get('ir.sequence.type')
sequences= self.browse(ids)
code2seq = {}
for sequence in sequences:
@@ -221,7 +248,7 @@ class Sequence(ModelSQL, ModelView):
return res
def search_groups(self, name, clause):
sequence_type_obj = self.pool.get('ir.sequence.type')
sequence_type_obj = Pool().get('ir.sequence.type')
ids = sequence_type_obj.search([clause], order=[])
seq_types = sequence_type_obj.browse(ids)
codes = set(st.code for st in seq_types)
+142 -94
View File
@@ -425,141 +425,186 @@ this repository contains the full copyright notices and license terms. -->
<field name="operand">False</field>
<field name="rule_group" ref="rule_group_action"/>
</record>
<record model="ir.action.wizard" id="ir.act_module_install_upgrade">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.action-res.group" id="act_module_install_upgrade_group_admin">
<field name="action" ref="ir.act_module_install_upgrade"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.action.wizard" id="ir.act_translation_update">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.action-res.group" id="act_translation_update_group_admin">
<field name="action" ref="ir.act_translation_update"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.action.wizard" id="ir.act_translation_export">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.action-res.group" id="act_translation_export_group_admin">
<field name="action" ref="ir.act_translation_export"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_administration">
<field name="groups" eval="[('add', ref('group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_administration_group_admin">
<field name="menu" ref="ir.menu_administration"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_ui">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_ui_group_admin">
<field name="menu" ref="ir.menu_ui"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_icon_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_icon_form_group_admin">
<field name="menu" ref="ir.menu_icon_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_menu_tree">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_menu_tree_group_admin">
<field name="menu" ref="ir.menu_menu_list"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_view">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_view_group_admin">
<field name="menu" ref="ir.menu_view"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_view_sc">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_view_sc_group_admin">
<field name="menu" ref="ir.menu_view_sc"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_view_tree_width">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_view_tree_width_group_admin">
<field name="menu" ref="ir.menu_view_tree_width"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_action">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_action_group_admin">
<field name="menu" ref="ir.menu_action"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_act_action">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_act_action_group_admin">
<field name="menu" ref="ir.menu_act_action"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_action_report_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_action_report_form_group_admin">
<field name="menu" ref="ir.menu_action_report_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_action_act_window">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_action_act_window_group_admin">
<field name="menu" ref="ir.menu_action_act_window"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_action_wizard">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_action_wizard_group_admin">
<field name="menu" ref="ir.menu_action_wizard"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_action_wizard_size">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_action_wizard_size_group_admin">
<field name="menu" ref="ir.menu_action_wizard_size"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_action_url">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_action_url_group_admin">
<field name="menu" ref="ir.menu_action_url"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_models">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_models_group_admin">
<field name="menu" ref="ir.menu_models"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_model_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_model_form_group_admin">
<field name="menu" ref="ir.menu_model_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.model_model_fields_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="model_model_fields_form_group_admin">
<field name="menu" ref="ir.model_model_fields_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_model_access_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_model_access_form_group_admin">
<field name="menu" ref="ir.menu_model_access_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_model_field_access_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_model_field_access_form_group_admin">
<field name="menu" ref="ir.menu_model_field_access_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_sequences">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_sequences_group_admin">
<field name="menu" ref="ir.menu_sequences"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_sequence_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_sequence_form_group_admin">
<field name="menu" ref="ir.menu_sequence_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_sequence_strict_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_sequence_strict_form_group_admin">
<field name="menu" ref="ir.menu_sequence_strict_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_ir_sequence_type">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_ir_sequence_type_group_admin">
<field name="menu" ref="ir.menu_ir_sequence_type"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_attachment_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_attachment_form_group_admin">
<field name="menu" ref="ir.menu_attachment_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_scheduler">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_scheduler_group_admin">
<field name="menu" ref="ir.menu_scheduler"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_cron_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_cron_form_group_admin">
<field name="menu" ref="ir.menu_cron_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_localization">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_localization_group_admin">
<field name="menu" ref="ir.menu_localization"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_lang_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_lang_form_group_admin">
<field name="menu" ref="ir.menu_lang_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_translation_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_translation_form_group_admin">
<field name="menu" ref="ir.menu_translation_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_translation_set_report">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_translation_set_report_group_admin">
<field name="menu" ref="ir.menu_translation_set_report"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_translation_clean">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_translation_clean_group_admin">
<field name="menu" ref="ir.menu_translation_clean"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_translation_update">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_translation_update_group_admin">
<field name="menu" ref="ir.menu_translation_update"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_translation_export">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_translation_export_group_admin">
<field name="menu" ref="ir.menu_translation_export"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_export_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_export_form_group_admin">
<field name="menu" ref="ir.menu_export_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_rule_group_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_rule_group_form_group_admin">
<field name="menu" ref="ir.menu_rule_group_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_property_form_default">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_property_form_default_group_admin">
<field name="menu" ref="ir.menu_property_form_default"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_property_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_property_form_group_admin">
<field name="menu" ref="ir.menu_property_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_modules">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_modules_group_admin">
<field name="menu" ref="ir.menu_modules"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_module_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_module_form_group_admin">
<field name="menu" ref="ir.menu_module_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_config_wizard_item_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_config_wizard_item_form_group_admin">
<field name="menu" ref="ir.menu_config_wizard_item_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_module_install_upgrade">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_module_install_upgrade_group_admin">
<field name="menu" ref="ir.menu_module_install_upgrade"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.menu" id="ir.menu_trigger_form">
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
<record model="ir.ui.menu-res.group" id="menu_trigger_form_group_admin">
<field name="menu" ref="ir.menu_trigger_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.view" id="module_view_form">
<field name="model">ir.module.module</field>
@@ -627,7 +672,6 @@ this repository contains the full copyright notices and license terms. -->
<xpath
expr="/form/field[@name=&quot;code&quot;]"
position="after">
<separator name="groups" colspan="4"/>
<field name="groups" colspan="4"/>
</xpath>
</data>
@@ -662,7 +706,11 @@ this repository contains the full copyright notices and license terms. -->
<record model="res.user" id="user_trigger">
<field name="login">user_cron_trigger</field>
<field name="name">Cron Trigger</field>
<field name="groups" eval="[('add', ref('group_admin'))]"/>
<field name="active" eval="False"/>
</record>
<record model="res.user-res.group" id="user_trigger_group_admin">
<field name="user" ref="user_trigger"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.cron" id="cron_trigger_time">
@@ -672,8 +720,8 @@ this repository contains the full copyright notices and license terms. -->
<field name="active" eval="True"/>
<field name="interval_number">5</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
<field name="number_calls">-1</field>
<field name="repeat_missed" eval="False"/>
<field name="model">ir.trigger</field>
<field name="function">trigger_time</field>
</record>
+7 -3
View File
@@ -5,6 +5,7 @@ import datetime
from trytond.model import ModelView, ModelSQL, fields
from trytond.pyson import Eval, In, If, Not, Equal
from trytond.transaction import Transaction
from trytond.pool import Pool
_STATES = [
('draft', 'Draft'),
@@ -101,7 +102,8 @@ class Request(ModelSQL, ModelView):
return res
def request_send(self, ids):
request_history_obj = self.pool.get('res.request.history')
pool = Pool()
request_history_obj = pool.get('res.request.history')
for request in self.browse(ids):
values = {
'request': request.id,
@@ -177,7 +179,8 @@ class RequestLink(ModelSQL, ModelView):
return 5
def models_get(self):
model_obj = self.pool.get('ir.model')
pool = Pool()
model_obj = pool.get('ir.model')
model_ids = model_obj.search([])
res = []
for model in model_obj.browse(model_ids):
@@ -239,7 +242,8 @@ class RequestReference(ModelSQL, ModelView):
required=True)
def links_get(self):
request_link_obj = self.pool.get('res.request.link')
pool = Pool()
request_link_obj = pool.get('res.request.link')
ids = request_link_obj.search([])
request_links = request_link_obj.browse(ids)
return [(x.model, x.name) for x in request_links]
+11 -2
View File
@@ -90,8 +90,13 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="request_view_form"/>
<field name="act_window" ref="act_request_form"/>
</record>
<menuitem parent="res.menu_res" groups="group_admin"
<menuitem parent="res.menu_res"
action="act_request_form" id="menu_request_form"/>
<record model="ir.ui.menu-res.group" id="menu_request_form_group_admin">
<field name="menu" ref="menu_request_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.view" id="request_link_view_form">
<field name="model">res.request.link</field>
<field name="type">form</field>
@@ -136,8 +141,12 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="request_link_view_form"/>
<field name="act_window" ref="act_request_link_form"/>
</record>
<menuitem parent="res.menu_res" groups="group_admin"
<menuitem parent="res.menu_res"
action="act_request_link_form" id="menu_request_link_form"/>
<record model="ir.ui.menu-res.group" id="menu_request_link_form_group_admin">
<field name="menu" ref="menu_request_link_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.view" id="request_history_view_tree">
<field name="model">res.request.history</field>
+27 -16
View File
@@ -1,7 +1,6 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
"User"
from __future__ import with_statement
import copy
import string
import random
@@ -18,6 +17,7 @@ from trytond.security import get_connections
from trytond.transaction import Transaction
from trytond.cache import Cache
from trytond.pyson import Eval, Greater
from trytond.pool import Pool
class User(ModelSQL, ModelView):
@@ -36,9 +36,9 @@ class User(ModelSQL, ModelView):
menu = fields.Many2One('ir.action', 'Menu Action',
domain=[('usage','=','menu')], required=True)
groups = fields.Many2Many('res.user-res.group',
'uid', 'gid', 'Groups')
'user', 'group', 'Groups')
rule_groups = fields.Many2Many('ir.rule.group-res.user',
'user_id', 'rule_group_id', 'Rules',
'user', 'rule_group', 'Rules',
domain=[('global_p', '!=', True), ('default_p', '!=', True)])
language = fields.Many2One('ir.lang', 'Language',
domain=['OR', ('translatable', '=', True), ('code', '=', 'en_US')])
@@ -112,7 +112,8 @@ class User(ModelSQL, ModelView):
return 1
def default_menu(self):
action_obj = self.pool.get('ir.action')
pool = Pool()
action_obj = pool.get('ir.action')
action_ids = action_obj.search([
('usage', '=', 'menu'),
], limit=1)
@@ -125,7 +126,8 @@ class User(ModelSQL, ModelView):
def get_language_direction(self, ids, name):
res = {}
lang_obj = self.pool.get('ir.lang')
pool = Pool()
lang_obj = pool.get('ir.lang')
default_direction = lang_obj.default_direction()
for user in self.browse(ids):
if user.language:
@@ -150,7 +152,8 @@ class User(ModelSQL, ModelView):
def _convert_vals(self, vals):
vals = vals.copy()
action_obj = self.pool.get('ir.action')
pool = Pool()
action_obj = pool.get('ir.action')
if 'action' in vals:
vals['action'] = action_obj.get_action_id(vals['action'])
if 'menu' in vals:
@@ -175,7 +178,8 @@ class User(ModelSQL, ModelView):
vals = self._convert_vals(vals)
res = super(User, self).write(ids, vals)
# Restart the cache for domain_get method
self.pool.get('ir.rule').domain_get.reset()
pool = Pool()
pool.get('ir.rule').domain_get.reset()
# Restart the cache for get_groups
self.get_groups.reset()
# Restart the cache for _get_login
@@ -183,9 +187,9 @@ class User(ModelSQL, ModelView):
# Restart the cache for get_preferences
self.get_preferences.reset()
# Restart the cache of check
self.pool.get('ir.model.access').check.reset()
pool.get('ir.model.access').check.reset()
# Restart the cache
for _, model in self.pool.iterobject():
for _, model in pool.iterobject():
try:
model.fields_view_get.reset()
except Exception:
@@ -290,7 +294,8 @@ class User(ModelSQL, ModelView):
:param values: a dictionary with values
:param old_password: the previous password if password is in values
'''
lang_obj = self.pool.get('ir.lang')
pool = Pool()
lang_obj = pool.get('ir.lang')
values_clean = values.copy()
fields = self._preferences_fields + self._context_fields
user_id = Transaction().user
@@ -314,8 +319,9 @@ class User(ModelSQL, ModelView):
self.write(user_id, values_clean)
def get_preferences_fields_view(self):
model_data_obj = self.pool.get('ir.model.data')
lang_obj = self.pool.get('ir.lang')
pool = Pool()
model_data_obj = pool.get('ir.model.data')
lang_obj = pool.get('ir.lang')
view_id = model_data_obj.get_id('res', 'user_view_form_preferences')
res = self.fields_view_get(view_id=view_id)
@@ -396,9 +402,9 @@ class UserGroup(ModelSQL):
'User - Group'
_name = 'res.user-res.group'
_description = __doc__
uid = fields.Many2One('res.user', 'User', ondelete='CASCADE', select=1,
user = fields.Many2One('res.user', 'User', ondelete='CASCADE', select=1,
required=True)
gid = fields.Many2One('res.group', 'Group', ondelete='CASCADE', select=1,
group = fields.Many2One('res.group', 'Group', ondelete='CASCADE', select=1,
required=True)
def init(self, module_name):
@@ -407,6 +413,10 @@ class UserGroup(ModelSQL):
TableHandler.table_rename(cursor, 'res_group_user_rel', self._table)
TableHandler.sequence_rename(cursor, 'res_group_user_rel_id_seq',
self._table + '_id_seq')
# Migration from 2.0 uid and gid rename into user and group
table = TableHandler(cursor, self, module_name)
table.column_rename('uid', 'user')
table.column_rename('gid', 'group')
super(UserGroup, self).init(module_name)
UserGroup()
@@ -415,7 +425,7 @@ UserGroup()
class Group(ModelSQL, ModelView):
"Group"
_name = "res.group"
users = fields.Many2Many('res.user-res.group', 'gid', 'uid', 'Users')
users = fields.Many2Many('res.user-res.group', 'group', 'user', 'Users')
Group()
@@ -492,7 +502,8 @@ class UserConfig(Wizard):
return {}
def _add(self, data):
res_obj = self.pool.get('res.user')
pool = Pool()
res_obj = pool.get('res.user')
res_obj.create(data['form'])
return {}
+9 -5
View File
@@ -9,7 +9,10 @@ this repository contains the full copyright notices and license terms. -->
<field name="signature">Administrator</field>
<field name="action" ref="ir.act_module_config_wizard"/>
<field name="menu" ref="ir.act_menu_tree"/>
<field name="groups" eval="[('add', ref('group_admin'))]"/>
</record>
<record model="res.user-res.group" id="user_admin_group_admin">
<field name="user" ref="user_admin"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.view" id="user_view_form">
<field name="model">res.user</field>
@@ -38,9 +41,7 @@ this repository contains the full copyright notices and license terms. -->
<field name="signature" colspan="4"/>
</page>
<page string="Access Permissions" col="1" id="permissions">
<separator name="groups"/>
<field name="groups"/>
<separator name="rule_groups"/>
<field name="rule_groups"/>
</page>
<page string="Preferences" col="2" id="preferences">
@@ -77,7 +78,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="signature" colspan="4"/>
</page>
<page string="Group Membership" col="1" id="membership">
<separator name="groups"/>
<field name="groups"/>
</page>
<page string="Preferences" col="2" id="preferences">
@@ -122,8 +122,12 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="user_view_form"/>
<field name="act_window" ref="act_user_form"/>
</record>
<menuitem parent="res.menu_res" groups="group_admin"
<menuitem parent="res.menu_res"
action="act_user_form" id="menu_user_form"/>
<record model="ir.ui.menu-res.group" id="menu_user_form_group_admin">
<field name="menu" ref="menu_user_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.model.access" id="access_user">
<field name="model" search="[('model', '=', 'res.user')]"/>
+3 -4
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
from trytond.backend import Database
from trytond.session import Session
from trytond.pool import Pool
@@ -41,7 +40,7 @@ def login(dbname, loginname, password, cache=True):
def logout(dbname, user, session):
name = ''
if _USER_CACHE.get(dbname, {}).has_key(user):
if user in _USER_CACHE.get(dbname, {}):
for i, real_session \
in enumerate(_USER_CACHE[dbname][user]):
if real_session.session == session:
@@ -62,7 +61,7 @@ def check(dbname, user, session):
result = None
now = time.time()
timeout = int(CONFIG['session_timeout'])
if _USER_CACHE.get(dbname, {}).has_key(user):
if user in _USER_CACHE.get(dbname, {}):
to_del = []
for i, real_session \
in enumerate(_USER_CACHE[dbname][user]):
@@ -81,7 +80,7 @@ def get_connections(dbname, user):
res = 0
now = time.time()
timeout = int(CONFIG['session_timeout'])
if _USER_CACHE.get(dbname, {}).has_key(int(user)):
if int(user) in _USER_CACHE.get(dbname, {}):
for _, session in enumerate(_USER_CACHE[dbname][int(user)]):
if abs(session.timestamp - now) < timeout:
res += 1
+15 -10
View File
@@ -3,7 +3,6 @@
"""
%prog [options]
"""
from __future__ import with_statement
import logging
import logging.handlers
import sys, os, signal
@@ -235,19 +234,25 @@ class TrytonServer(object):
import psyco
psyco.full()
threads = {}
while True:
if CONFIG['auto_reload'] and monitor():
try:
Pool.start()
except Exception:
pass
for dbname in Pool.database_list():
pool = Pool(dbname)
if 'ir.cron' not in pool.object_name_list():
continue
cron_obj = pool.get('ir.cron')
thread = threading.Thread(
target=cron_obj.pool_jobs,
args=(dbname,), kwargs={})
thread.start()
if CONFIG['cron']:
for dbname in Pool.database_list():
thread = threads.get(dbname)
if thread and thread.is_alive():
continue
pool = Pool(dbname)
if 'ir.cron' not in pool.object_name_list():
continue
cron_obj = pool.get('ir.cron')
thread = threading.Thread(
target=cron_obj.run,
args=(dbname,), kwargs={})
thread.start()
threads[dbname] = thread
time.sleep(60)
+5 -1
View File
@@ -7,7 +7,11 @@ this repository contains the full copyright notices and license terms. -->
<record model="ir.sequence.type" id="sequence_type_test">
<field name="name">Test</field>
<field name="code">test</field>
<field name="groups" eval="[('add', ref('res.group_admin'))]"/>
</record>
<record model="ir.sequence.type-res.group"
id="sequence_type_test_group_admin">
<field name="sequence_type" ref="sequence_type_test"/>
<field name="group" ref="res.group_admin"/>
</record>
</data>
-1
View File
@@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import unittest
from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
install_module
-1
View File
@@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import unittest
from decimal import Decimal
import datetime
-1
View File
@@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import unittest
import datetime
from decimal import Decimal
-1
View File
@@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import unittest
from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
install_module
-1
View File
@@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import unittest
from datetime import datetime
from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
+3 -5
View File
@@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import unittest
from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
install_module
@@ -23,8 +22,7 @@ class MPTTTestCase(unittest.TestCase):
('parent', '=', parent_id),
])
childs = self.mptt.read(child_ids, ['left', 'right'])
childs.sort(lambda x, y: cmp(child_ids.index(x['id']),
child_ids.index(y['id'])))
childs.sort(key=lambda x: child_ids.index(x['id']))
for child in childs:
assert child['left'] > left, \
'Record (%d): left %d <= parent left %d' % \
@@ -152,7 +150,7 @@ class MPTTTestCase(unittest.TestCase):
with Transaction().start(DB_NAME, USER, CONTEXT) as transaction:
record_ids = self.mptt.search([])
self.mptt.write(record_ids[:len(record_ids)/2], {
self.mptt.write(record_ids[:len(record_ids) // 2], {
'active': False
})
self.CheckTree()
@@ -186,7 +184,7 @@ class MPTTTestCase(unittest.TestCase):
with Transaction().start(DB_NAME, USER, CONTEXT) as transaction:
record_ids = self.mptt.search([])
self.mptt.delete(record_ids[:len(record_ids)/2])
self.mptt.delete(record_ids[:len(record_ids) // 2])
self.CheckTree()
transaction.cursor.rollback()
-1
View File
@@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import unittest
import datetime
from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
+2
View File
@@ -118,6 +118,8 @@ class ToolsTestCase(unittest.TestCase):
['OR', clause, ['AND', clause, ['OR', clause, clause]]]),
(['OR', [clause]], ['OR', ['AND', clause]]),
([], []),
(['OR', clause, []], ['OR', clause, []]),
(['AND', clause, []], ['AND', clause, []]),
)
for i, j in tests:
self.assertEqual(reduce_domain(i), j,
-1
View File
@@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import unittest
import sys
import time
-8
View File
@@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import logging
logging.basicConfig(level=logging.ERROR)
import sys, os
@@ -11,13 +10,6 @@ DIR = os.path.abspath(os.path.normpath(os.path.join(__file__,
if os.path.isdir(DIR):
sys.path.insert(0, os.path.dirname(DIR))
if sys.version_info[:2] <= (2, 5):
# ugly monkeypatch to make doctests work. For the reasons see
# http://mail.python.org/pipermail/python-dev/2008-July/081420.html
# It can go away once we drop Python 2.5
import decimal
decimal.Decimal.__repr__ = lambda s: "Decimal('%s')" % str(s)
import unittest
import doctest
from lxml import etree
+4
View File
@@ -2,3 +2,7 @@
#this repository contains the full copyright notices and license terms.
from misc import *
from datetime_strftime import *
try:
from collections import OrderedDict
except ImportError:
from ordereddict import OrderedDict
+2
View File
@@ -446,4 +446,6 @@ def reduce_domain(domain):
result.extend(sub_domain[1:])
else:
result.append(sub_domain)
else:
result.append(arg)
return result
+278
View File
@@ -0,0 +1,278 @@
# Copyright (C) 2009 by Raymond Hettinger
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
# Passes Python2.7's test suite and incorporates all the latest updates.
try:
from thread import get_ident as _get_ident
except ImportError:
from dummy_thread import get_ident as _get_ident
try:
from _abcoll import KeysView, ValuesView, ItemsView
except ImportError:
pass
class OrderedDict(dict):
'Dictionary that remembers insertion order'
# An inherited dict maps keys to values.
# The inherited dict provides __getitem__, __len__, __contains__, and get.
# The remaining methods are order-aware.
# Big-O running times for all methods are the same as for regular dictionaries.
# The internal self.__map dictionary maps keys to links in a doubly linked list.
# The circular doubly linked list starts and ends with a sentinel element.
# The sentinel element never gets deleted (this simplifies the algorithm).
# Each link is stored as a list of length three: [PREV, NEXT, KEY].
def __init__(self, *args, **kwds):
'''Initialize an ordered dictionary. Signature is the same as for
regular dictionaries, but keyword arguments are not recommended
because their insertion order is arbitrary.
'''
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
self.__root
except AttributeError:
self.__root = root = [] # sentinel node
root[:] = [root, root, None]
self.__map = {}
self.__update(*args, **kwds)
def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
'od.__setitem__(i, y) <==> od[i]=y'
# Setting a new item creates a new link which goes at the end of the linked
# list, and the inherited dictionary is updated with the new key/value pair.
if key not in self:
root = self.__root
last = root[0]
last[1] = root[0] = self.__map[key] = [last, root, key]
dict_setitem(self, key, value)
def __delitem__(self, key, dict_delitem=dict.__delitem__):
'od.__delitem__(y) <==> del od[y]'
# Deleting an existing item uses self.__map to find the link which is
# then removed by updating the links in the predecessor and successor nodes.
dict_delitem(self, key)
link_prev, link_next, key = self.__map.pop(key)
link_prev[1] = link_next
link_next[0] = link_prev
def __iter__(self):
'od.__iter__() <==> iter(od)'
root = self.__root
curr = root[1]
while curr is not root:
yield curr[2]
curr = curr[1]
def __reversed__(self):
'od.__reversed__() <==> reversed(od)'
root = self.__root
curr = root[0]
while curr is not root:
yield curr[2]
curr = curr[0]
def clear(self):
'od.clear() -> None. Remove all items from od.'
try:
for node in self.__map.itervalues():
del node[:]
root = self.__root
root[:] = [root, root, None]
self.__map.clear()
except AttributeError:
pass
dict.clear(self)
def popitem(self, last=True):
'''od.popitem() -> (k, v), return and remove a (key, value) pair.
Pairs are returned in LIFO order if last is true or FIFO order if false.
'''
if not self:
raise KeyError('dictionary is empty')
root = self.__root
if last:
link = root[0]
link_prev = link[0]
link_prev[1] = root
root[0] = link_prev
else:
link = root[1]
link_next = link[1]
root[1] = link_next
link_next[0] = root
key = link[2]
del self.__map[key]
value = dict.pop(self, key)
return key, value
# -- the following methods do not depend on the internal structure --
def keys(self):
'od.keys() -> list of keys in od'
return list(self)
def values(self):
'od.values() -> list of values in od'
return [self[key] for key in self]
def items(self):
'od.items() -> list of (key, value) pairs in od'
return [(key, self[key]) for key in self]
def iterkeys(self):
'od.iterkeys() -> an iterator over the keys in od'
return iter(self)
def itervalues(self):
'od.itervalues -> an iterator over the values in od'
for k in self:
yield self[k]
def iteritems(self):
'od.iteritems -> an iterator over the (key, value) items in od'
for k in self:
yield (k, self[k])
def update(*args, **kwds):
'''od.update(E, **F) -> None. Update od from dict/iterable E and F.
If E is a dict instance, does: for k in E: od[k] = E[k]
If E has a .keys() method, does: for k in E.keys(): od[k] = E[k]
Or if E is an iterable of items, does: for k, v in E: od[k] = v
In either case, this is followed by: for k, v in F.items(): od[k] = v
'''
if len(args) > 2:
raise TypeError('update() takes at most 2 positional '
'arguments (%d given)' % (len(args),))
elif not args:
raise TypeError('update() takes at least 1 argument (0 given)')
self = args[0]
# Make progressively weaker assumptions about "other"
other = ()
if len(args) == 2:
other = args[1]
if isinstance(other, dict):
for key in other:
self[key] = other[key]
elif hasattr(other, 'keys'):
for key in other.keys():
self[key] = other[key]
else:
for key, value in other:
self[key] = value
for key, value in kwds.items():
self[key] = value
__update = update # let subclasses override update without breaking __init__
__marker = object()
def pop(self, key, default=__marker):
'''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
If key is not found, d is returned if given, otherwise KeyError is raised.
'''
if key in self:
result = self[key]
del self[key]
return result
if default is self.__marker:
raise KeyError(key)
return default
def setdefault(self, key, default=None):
'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
if key in self:
return self[key]
self[key] = default
return default
def __repr__(self, _repr_running={}):
'od.__repr__() <==> repr(od)'
call_key = id(self), _get_ident()
if call_key in _repr_running:
return '...'
_repr_running[call_key] = 1
try:
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, self.items())
finally:
del _repr_running[call_key]
def __reduce__(self):
'Return state information for pickling'
items = [[k, self[k]] for k in self]
inst_dict = vars(self).copy()
for k in vars(OrderedDict()):
inst_dict.pop(k, None)
if inst_dict:
return (self.__class__, (items,), inst_dict)
return self.__class__, (items,)
def copy(self):
'od.copy() -> a shallow copy of od'
return self.__class__(self)
@classmethod
def fromkeys(cls, iterable, value=None):
'''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
and values equal to v (which defaults to None).
'''
d = cls()
for key in iterable:
d[key] = value
return d
def __eq__(self, other):
'''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
while comparison to a regular mapping is order-insensitive.
'''
if isinstance(other, OrderedDict):
return len(self)==len(other) and self.items() == other.items()
return dict.__eq__(self, other)
def __ne__(self, other):
return not self == other
# -- the following methods are only used in Python 2.7 --
def viewkeys(self):
"od.viewkeys() -> a set-like object providing a view on od's keys"
return KeysView(self)
def viewvalues(self):
"od.viewvalues() -> an object providing a view on od's values"
return ValuesView(self)
def viewitems(self):
"od.viewitems() -> a set-like object providing a view on od's items"
return ItemsView(self)
+27 -16
View File
@@ -7,6 +7,7 @@ from trytond.model import ModelView, ModelSQL, fields
from trytond.version import PACKAGE, VERSION, WEBSITE
from trytond.tools import reduce_ids, safe_eval
from trytond.transaction import Transaction
from trytond.pool import Pool
class Collection(ModelSQL, ModelView):
@@ -47,7 +48,8 @@ class Collection(ModelSQL, ModelView):
return '[]'
def check_attachment(self, ids):
attachment_obj = self.pool.get('ir.attachment')
pool = Pool()
attachment_obj = pool.get('ir.attachment')
for collection in self.browse(ids):
if collection.parent:
attachment_ids = attachment_obj.search([
@@ -60,8 +62,9 @@ class Collection(ModelSQL, ModelView):
return True
def _uri2object(self, uri, object_name=_name, object_id=False, cache=None):
attachment_obj = self.pool.get('ir.attachment')
report_obj = self.pool.get('ir.action.report')
pool = Pool()
attachment_obj = pool.get('ir.attachment')
report_obj = pool.get('ir.action.report')
cache_uri = uri
if cache is not None:
@@ -233,7 +236,8 @@ class Collection(ModelSQL, ModelView):
return object_name, object_id
def get_childs(self, uri, filter=None, cache=None):
report_obj = self.pool.get('ir.action.report')
pool = Pool()
report_obj = pool.get('ir.action.report')
res = []
if filter:
return []
@@ -253,7 +257,7 @@ class Collection(ModelSQL, ModelView):
if object_name == self._name and object_id:
collection = self.browse(object_id)
if collection.model:
model_obj = self.pool.get(collection.model.model)
model_obj = pool.get(collection.model.model)
if not model_obj:
return res
model_ids = model_obj.search(
@@ -289,7 +293,7 @@ class Collection(ModelSQL, ModelView):
cache.setdefault(report_obj._name, {})
cache[report_obj._name][report.id] = {}
attachment_obj = self.pool.get('ir.attachment')
attachment_obj = pool.get('ir.attachment')
attachment_ids = attachment_obj.search([
('resource', '=', '%s,%s' % (object_name, object_id)),
])
@@ -312,11 +316,12 @@ class Collection(ModelSQL, ModelView):
def get_displayname(self, uri, cache=None):
object_name, object_id = self._uri2object(uri, cache=cache)
model_obj = self.pool.get(object_name)
model_obj = Pool().get(object_name)
return model_obj.browse(object_id).rec_name
def get_contentlength(self, uri, cache=None):
attachment_obj = self.pool.get('ir.attachment')
pool = Pool()
attachment_obj = pool.get('ir.attachment')
object_name, object_id = self._uri2object(uri, cache=cache)
if object_name == 'ir.attachment':
@@ -360,9 +365,10 @@ class Collection(ModelSQL, ModelView):
return "application/octet-stream"
def get_creationdate(self, uri, cache=None):
pool = Pool()
object_name, object_id = self._uri2object(uri, cache=cache)
if object_name == 'ir.attachment':
model_obj = self.pool.get(object_name)
model_obj = pool.get(object_name)
if object_id:
if cache is not None:
cache.setdefault(model_obj._name, {})
@@ -394,9 +400,10 @@ class Collection(ModelSQL, ModelView):
return time.time()
def get_lastmodified(self, uri, cache=None):
pool = Pool()
object_name, object_id = self._uri2object(uri, cache=cache)
if object_name == 'ir.attachment':
model_obj = self.pool.get(object_name)
model_obj = pool.get(object_name)
if object_id:
if cache is not None:
cache.setdefault(model_obj._name, {})
@@ -430,8 +437,9 @@ class Collection(ModelSQL, ModelView):
def get_data(self, uri, cache=None):
from DAV.errors import DAV_NotFound
attachment_obj = self.pool.get('ir.attachment')
report_obj = self.pool.get('ir.action.report')
pool = Pool()
attachment_obj = pool.get('ir.attachment')
report_obj = pool.get('ir.action.report')
if uri:
object_name, object_id = self._uri2object(uri, cache=cache)
@@ -473,7 +481,7 @@ class Collection(ModelSQL, ModelView):
1)[-1].rsplit('.', 1)[0])
report = report_obj.browse(report_id)
if report.report_name:
report_obj = self.pool.get(report.report_name,
report_obj = pool.get(report.report_name,
type='report')
val = report_obj.execute([object_id],
{'id': object_id, 'ids': [object_id]})
@@ -489,7 +497,8 @@ class Collection(ModelSQL, ModelView):
or object_name in ('ir.attachment') \
or not object_id:
raise DAV_Forbidden
attachment_obj = self.pool.get('ir.attachment')
pool = Pool()
attachment_obj = pool.get('ir.attachment')
object_name2, object_id2 = self._uri2object(uri, cache=cache)
if not object_id2:
name = get_urifilename(uri)
@@ -550,7 +559,8 @@ class Collection(ModelSQL, ModelView):
if object_name != 'ir.attachment' \
or not object_id:
raise DAV_Forbidden
model_obj = self.pool.get(object_name)
pool = Pool()
model_obj = pool.get(object_name)
try:
model_obj.delete(object_id)
except Exception:
@@ -584,7 +594,8 @@ class Attachment(ModelSQL, ModelView):
})
def check_collection(self, ids):
collection_obj = self.pool.get('webdav.collection')
pool = Pool()
collection_obj = pool.get('webdav.collection')
for attachment in self.browse(ids):
if attachment.resource:
model_name, record_id = attachment.resource.split(',')
+16 -4
View File
@@ -3,8 +3,13 @@
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<menuitem name="WebDAV" id="menu_webdav" groups="res.group_admin"
<menuitem name="WebDAV" id="menu_webdav"
parent="ir.menu_administration"/>
<record model="ir.ui.menu-res.group" id="menu_webdav_group_admin">
<field name="menu" ref="menu_webdav"/>
<field name="group" ref="res.group_admin"/>
</record>
<record model="ir.ui.view" id="collection_view_tree">
<field name="model">webdav.collection</field>
<field name="type">tree</field>
@@ -57,8 +62,12 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="collection_view_form"/>
<field name="act_window" ref="act_collection_tree"/>
</record>
<menuitem parent="menu_webdav" groups="res.group_admin"
<menuitem parent="menu_webdav"
action="act_collection_tree" id="menu_collection_tree"/>
<record model="ir.ui.menu-res.group" id="menu_collection_tree_group_admin">
<field name="menu" ref="menu_collection_tree"/>
<field name="group" ref="res.group_admin"/>
</record>
<record model="ir.action.act_window" id="act_collection_form">
<field name="name">Collections</field>
@@ -77,7 +86,10 @@ this repository contains the full copyright notices and license terms. -->
<field name="act_window" ref="act_collection_form"/>
</record>
<menuitem name="New Collection" parent="menu_collection_tree"
action="act_collection_form" id="menu_collection_form"
groups="res.group_admin"/>
action="act_collection_form" id="menu_collection_form"/>
<record model="ir.ui.menu-res.group" id="menu_collection_form_group_admin">
<field name="menu" ref="menu_collection_form"/>
<field name="group" ref="res.group_admin"/>
</record>
</data>
</tryton>
+6 -5
View File
@@ -12,7 +12,6 @@ from trytond.error import WarningErrorMixin
class Wizard(WarningErrorMixin):
_name = ""
states = {}
pool = None
def __new__(cls):
Pool.register(cls, type='wizard')
@@ -29,7 +28,8 @@ class Wizard(WarningErrorMixin):
self._datas = {}
def init(self, module_name):
translation_obj = self.pool.get('ir.translation')
pool = Pool()
translation_obj = pool.get('ir.translation')
cursor = Transaction().cursor
for state in self.states.keys():
if self.states[state]['result']['type'] == 'form':
@@ -100,8 +100,9 @@ class Wizard(WarningErrorMixin):
self._lock.release()
def execute(self, wiz_id, data, state='init'):
translation_obj = self.pool.get('ir.translation')
wizard_size_obj = self.pool.get('ir.action.wizard_size')
pool = Pool()
translation_obj = pool.get('ir.translation')
wizard_size_obj = pool.get('ir.action.wizard_size')
res = {}
if self._datas.get(wiz_id, {}).get('user') != Transaction().user:
@@ -129,7 +130,7 @@ class Wizard(WarningErrorMixin):
if result_def['type'] == 'action':
res['action'] = getattr(self, result_def['action'])(data)
elif result_def['type'] == 'form':
obj = self.pool.get(result_def['object'])
obj = pool.get(result_def['object'])
view = obj.fields_view_get(view_type='form')
fields = view['fields']
+30 -20
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
import os
import expr
import base64
@@ -10,6 +9,7 @@ from trytond.tools import exec_command_pipe
from trytond.backend import TableHandler
from trytond.pyson import Eval, Equal, Not
from trytond.transaction import Transaction
from trytond.pool import Pool
class Workflow(ModelSQL, ModelView):
@@ -172,8 +172,9 @@ class WorkflowInstance(ModelSQL, ModelView):
return res
def create(self, values):
activity_obj = self.pool.get('workflow.activity')
workitem_obj = self.pool.get('workflow.workitem')
pool = Pool()
activity_obj = pool.get('workflow.activity')
workitem_obj = pool.get('workflow.workitem')
instance_id = super(WorkflowInstance, self).create(values)
@@ -196,7 +197,8 @@ class WorkflowInstance(ModelSQL, ModelView):
def update(self, instance):
'''
'''
workitem_obj = self.pool.get('workflow.workitem')
pool = Pool()
workitem_obj = pool.get('workflow.workitem')
for workitem in instance.workitems:
workitem_obj.process(workitem)
instance = self.browse(instance.id)
@@ -205,7 +207,8 @@ class WorkflowInstance(ModelSQL, ModelView):
def validate(self, instance, signal, force_running=False):
'''
'''
workitem_obj = self.pool.get('workflow.workitem')
pool = Pool()
workitem_obj = pool.get('workflow.workitem')
for workitem in instance.workitems:
workitem_obj.process(workitem, signal=signal,
force_running=force_running)
@@ -213,7 +216,8 @@ class WorkflowInstance(ModelSQL, ModelView):
return self._update_end(instance)
def _update_end(self, instance):
workitem_obj = self.pool.get('workflow.workitem')
pool = Pool()
workitem_obj = pool.get('workflow.workitem')
res = True
for workitem in instance.workitems:
if (workitem.state != 'complete') \
@@ -309,15 +313,14 @@ class WorkflowWorkitem(ModelSQL, ModelView):
:param signal: the signal
:param force_running: a boolean
'''
trigger_obj = self.pool.get('workflow.trigger')
pool = Pool()
trigger_obj = pool.get('workflow.trigger')
activity = workitem.activity
triggers = False
if workitem.state == 'active':
triggers = True
if not self._execute(workitem, activity):
return False
elif workitem.state == 'running':
pass
if workitem.state == 'complete' or force_running:
res = self._split_test(workitem, activity.split_mode, signal)
@@ -347,7 +350,8 @@ class WorkflowWorkitem(ModelSQL, ModelView):
workitem._data[workitem.id]['state'] = state
def _execute(self, workitem, activity):
instance_obj = self.pool.get('workflow.instance')
pool = Pool()
instance_obj = pool.get('workflow.instance')
#send a signal to overflow
if (workitem.state == 'active') and activity.signal_send:
for overflow in workitem.overflows:
@@ -409,7 +413,8 @@ class WorkflowWorkitem(ModelSQL, ModelView):
return True
def _split_test(self, workitem, split_mode, signal=None):
instance_obj = self.pool.get('workflow.instance')
pool = Pool()
instance_obj = pool.get('workflow.instance')
test = False
transitions = []
if split_mode == 'XOR' or split_mode == 'OR':
@@ -443,7 +448,8 @@ class WorkflowWorkitem(ModelSQL, ModelView):
return False
def _join_test(self, transition, instance):
instance_obj = self.pool.get('workflow.instance')
pool = Pool()
instance_obj = pool.get('workflow.instance')
activity = transition.act_to
if activity.join_mode == 'XOR':
self.create({
@@ -515,9 +521,10 @@ class InstanceGraph(Report):
def execute(self, ids, datas):
import pydot
lang_obj = self.pool.get('ir.lang')
workflow_obj = self.pool.get('workflow')
instance_obj = self.pool.get('workflow.instance')
pool = Pool()
lang_obj = pool.get('ir.lang')
workflow_obj = pool.get('workflow')
instance_obj = pool.get('workflow.instance')
lang_id = lang_obj.search([
('code', '=', Transaction().language),
@@ -562,14 +569,16 @@ class InstanceGraph(Report):
return ('png', base64.encodestring(data), False, workflow.name)
def graph_instance_get(self, graph, instance_id, nested=False):
instance_obj = self.pool.get('workflow.instance')
pool = Pool()
instance_obj = pool.get('workflow.instance')
instance = instance_obj.browse(instance_id)
self.graph_get(graph, instance.workflow.id, nested,
self.workitem_get(instance.id))
def workitem_get(self, instance_id):
res = {}
workitem_obj = self.pool.get('workflow.workitem')
pool = Pool()
workitem_obj = pool.get('workflow.workitem')
workitem_ids = workitem_obj.search([
('instance', '=', instance_id),
])
@@ -585,9 +594,10 @@ class InstanceGraph(Report):
import pydot
if workitem is None:
workitem = {}
activity_obj = self.pool.get('workflow.activity')
workflow_obj = self.pool.get('workflow')
transition_obj = self.pool.get('workflow.transition')
pool = Pool()
activity_obj = pool.get('workflow.activity')
workflow_obj = pool.get('workflow')
transition_obj = pool.get('workflow.transition')
activity_ids = activity_obj.search([
('workflow', '=', workflow_id),
])
+34 -8
View File
@@ -4,7 +4,12 @@ this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<menuitem name="Workflow" id="menu_workflow"
parent="ir.menu_administration" groups="res.group_admin"/>
parent="ir.menu_administration"/>
<record model="ir.ui.menu-res.group" id="menu_workflow_group_admin">
<field name="menu" ref="menu_workflow"/>
<field name="group" ref="res.group_admin"/>
</record>
<record model="ir.ui.view" id="workflow_view_form">
<field name="model">workflow</field>
<field name="type">form</field>
@@ -51,8 +56,13 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="workflow_view_form"/>
<field name="act_window" ref="act_workflow_form"/>
</record>
<menuitem parent="menu_workflow" groups="res.group_admin"
<menuitem parent="menu_workflow"
action="act_workflow_form" id="menu_workflow_form"/>
<record model="ir.ui.menu-res.group" id="menu_workflow_form_group_admin">
<field name="menu" ref="menu_workflow"/>
<field name="group" ref="res.group_admin"/>
</record>
<record model="ir.model.access" id="access_workflow">
<field name="model" search="[('model', '=', 'workflow')]"/>
<field name="perm_read" eval="True"/>
@@ -95,7 +105,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="join_mode"/>
<label name="split_mode"/>
<field name="split_mode"/>
<separator name="out_transitions" colspan="4"/>
<field name="out_transitions" colspan="4">
<tree string="Transitions">
<field name="act_to"/>
@@ -121,7 +130,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="trigger_expr_id"/>
</form>
</field>
<separator name="in_transitions" colspan="4"/>
<field name="in_transitions" colspan="4">
<tree string="Transitions">
<field name="act_from"/>
@@ -182,8 +190,13 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="activity_view_form"/>
<field name="act_window" ref="act_activity_form"/>
</record>
<menuitem parent="menu_workflow" groups="res.group_admin"
<menuitem parent="menu_workflow"
action="act_activity_form" id="menu_activity_form"/>
<record model="ir.ui.menu-res.group" id="menu_activity_form_group_admin">
<field name="menu" ref="menu_activity_form"/>
<field name="group" ref="res.group_admin"/>
</record>
<record model="ir.model.access" id="access_workflow_activity">
<field name="model" search="[('model', '=', 'workflow.activity')]"/>
<field name="perm_read" eval="True"/>
@@ -256,8 +269,13 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="transition_view_form"/>
<field name="act_window" ref="act_transition_form"/>
</record>
<menuitem parent="menu_workflow" groups="res.group_admin"
<menuitem parent="menu_workflow"
action="act_transition_form" id="menu_transition_form"/>
<record model="ir.ui.menu-res.group" id="menu_transition_form_group_admin">
<field name="menu" ref="menu_transition_form"/>
<field name="group" ref="res.group_admin"/>
</record>
<record model="ir.model.access" id="access_workflow_transition">
<field name="model" search="[('model', '=', 'workflow.transition')]"/>
<field name="perm_read" eval="True"/>
@@ -324,8 +342,12 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="instance_view_form"/>
<field name="act_window" ref="act_instance_form"/>
</record>
<menuitem parent="menu_workflow" groups="res.group_admin"
<menuitem parent="menu_workflow"
action="act_instance_form" id="menu_instance_form"/>
<record model="ir.ui.menu-res.group" id="menu_instance_form_group_admin">
<field name="menu" ref="menu_instance_form"/>
<field name="group" ref="res.group_admin"/>
</record>
<record model="ir.ui.view" id="workitem_view_form">
<field name="model">workflow.workitem</field>
@@ -375,7 +397,11 @@ this repository contains the full copyright notices and license terms. -->
<field name="view" ref="workitem_view_form"/>
<field name="act_window" ref="act_workitem_form"/>
</record>
<menuitem parent="menu_workflow" groups="res.group_admin"
<menuitem parent="menu_workflow"
action="act_workitem_form" id="menu_workitem_form"/>
<record model="ir.ui.menu-res.group" id="menu_workitem_form_group_admin">
<field name="menu" ref="menu_workitem_form"/>
<field name="group" ref="res.group_admin"/>
</record>
</data>
</tryton>