bzr revid: nicolas.vanhoren@openerp.com-20101119081721-tf8qbh9gpm0mjw38
This commit is contained in:
nvi-openerp
2010-11-19 09:17:21 +01:00
44 changed files with 15642 additions and 9315 deletions
+2 -2
View File
@@ -30,7 +30,7 @@ import tools
import tools.osutil
from tools.safe_eval import safe_eval as eval
import pooler
from tools.translate import _
import netsvc
@@ -806,7 +806,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
graph = create_graph(cr, ['base'], force)
if not graph:
logger.notifyChannel('init', netsvc.LOG_CRITICAL, 'module base cannot be loaded! (hint: verify addons-path)')
raise osv.osv.except_osv('Could not load base module', 'module base cannot be loaded! (hint: verify addons-path)')
raise osv.osv.except_osv(_('Could not load base module'), _('module base cannot be loaded! (hint: verify addons-path)'))
has_updates = load_module_graph(cr, graph, status, perform_checks=(not update_module), report=report)
if update_module:
+15 -1
View File
@@ -915,7 +915,7 @@
</record>
<record id="uk" model="res.country">
<field name="name">United Kingdom</field>
<field name="code">uk</field>
<field name="code">gb</field>
</record>
<record id="um" model="res.country">
<field name="name">USA Minor Outlying Islands</field>
@@ -1378,5 +1378,19 @@
<field name="name">Reserve</field>
<field name="code">RSV</field>
</record>
<record id="CRC" model="res.currency">
<field name="name">CRC</field>
<field name="code">CRC</field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
<field name="symbol">¢</field>
</record>
<record id="rateCRC" model="res.currency.rate">
<field name="rate">691.3153</field>
<field name="currency_id" ref="CRC"/>
<field eval="time.strftime('%Y-01-01')" name="name"/>
</record>
</data>
</openerp>
File diff suppressed because it is too large Load Diff
+3695 -1956
View File
File diff suppressed because it is too large Load Diff
+36 -33
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2010-10-18 17:46+0000\n"
"PO-Revision-Date: 2010-10-20 07:13+0000\n"
"Last-Translator: Quentin THEURET <quentin@theuret.net>\n"
"PO-Revision-Date: 2010-11-17 07:14+0000\n"
"Last-Translator: OpenERP Administrators <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-10-21 05:01+0000\n"
"X-Launchpad-Export-Date: 2010-11-18 04:45+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -38,12 +38,12 @@ msgstr "Autre configuration"
#. module: base
#: view:res.lang:0
msgid "%j - Day of the year as a decimal number [001,366]."
msgstr "%j - Jour de l'année comme un nombre décimal [001,366]."
msgstr "%j - Numéro du Jour dans l'année [001,366]."
#. module: base
#: selection:ir.property,type:0
msgid "DateTime"
msgstr ""
msgstr "Horodatage"
#. module: base
#: view:ir.values:0
@@ -106,7 +106,7 @@ msgstr "Vues créées"
#. module: base
#: selection:ir.ui.menu,icon:0
msgid "terp-emblem-important"
msgstr ""
msgstr "terp-emblem-important"
#. module: base
#: field:res.partner,ref:0
@@ -148,7 +148,7 @@ msgstr "STOCK_CANCEL"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_woodsuppliers0
msgid "Wood Suppliers"
msgstr ""
msgstr "Fournisseurs de bois"
#. module: base
#: field:ir.sequence,number_increment:0
@@ -198,7 +198,7 @@ msgstr "Nombre de modules"
#. module: base
#: help:multi_company.default,company_dest_id:0
msgid "Company to store the current record"
msgstr "Société physique ou sera stocké cet enregistrement"
msgstr "Société pour laquelle est fait cet enregistrement"
#. module: base
#: field:res.partner.bank.type.field,size:0
@@ -238,7 +238,7 @@ msgstr "Nom de l'assistant"
#. module: base
#: view:res.lang:0
msgid "%y - Year without century as a decimal number [00,99]."
msgstr "%y - Année dans le siècle comme un nombre décimal [00,99]."
msgstr "%y - Année dans le siècle [00,99]."
#. module: base
#: selection:maintenance.contract.wizard,state:0
@@ -360,7 +360,7 @@ msgstr "Serbe / Serbie"
#. module: base
#: help:res.lang,iso_code:0
msgid "This ISO code is the name of po files to use for translations"
msgstr "Ce code ISO est le nom des fichiers po utiliser pour les traductions"
msgstr "Ce code ISO est le nom des fichiers po utilisés pour les traductions"
#. module: base
#: selection:ir.ui.menu,icon:0
@@ -399,7 +399,7 @@ msgid ""
"The ISO country code in two chars.\n"
"You can use this field for quick search."
msgstr ""
"Le code ISO du pays en deux caractères.\n"
"Le code ISO du pays, sur deux caractères.\n"
"Vous pouvez utiliser ce champ pour effectuer une recherche rapide."
#. module: base
@@ -445,7 +445,7 @@ msgstr "Assistants"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_miscellaneoussuppliers0
msgid "Miscellaneous Suppliers"
msgstr ""
msgstr "Fournisseurs divers"
#. module: base
#: code:addons/base/ir/ir_model.py:0
@@ -462,7 +462,7 @@ msgstr ""
#. module: base
#: selection:ir.ui.menu,icon:0
msgid "terp-gtk-jump-to-ltr"
msgstr ""
msgstr "terp-gtk-jump-to-ltr"
#. module: base
#: view:base.language.export:0
@@ -513,7 +513,7 @@ msgstr "Bulgare / български"
#. module: base
#: model:ir.ui.menu,name:base.menu_base_action_rule
msgid "Automated Actions"
msgstr ""
msgstr "Actions automatisées"
#. module: base
#: model:ir.model,name:base.model_ir_actions_actions
@@ -579,17 +579,17 @@ msgstr "Séquences"
#. module: base
#: model:ir.model,name:base.model_base_language_import
msgid "Language Import"
msgstr ""
msgstr "Importation de langue"
#. module: base
#: model:ir.model,name:base.model_res_config_users
msgid "res.config.users"
msgstr ""
msgstr "res.config.users"
#. module: base
#: model:ir.model,name:base.model_base_language_export
msgid "base.language.export"
msgstr ""
msgstr "base.language.export"
#. module: base
#: selection:ir.ui.menu,icon:0
@@ -609,7 +609,7 @@ msgstr ""
#. module: base
#: selection:ir.ui.menu,icon:0
msgid "terp-folder-yellow"
msgstr ""
msgstr "terp-folder-yellow"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_4
@@ -629,7 +629,7 @@ msgstr "Mes partenaires"
#. module: base
#: view:ir.actions.report.xml:0
msgid "XML Report"
msgstr ""
msgstr "Rapport XML"
#. module: base
#: model:res.country,name:base.es
@@ -651,7 +651,7 @@ msgstr ""
#: model:ir.actions.act_window,name:base.action_view_base_module_upgrade
#: model:ir.model,name:base.model_base_module_upgrade
msgid "Module Upgrade"
msgstr ""
msgstr "Mise à jour de module"
#. module: base
#: view:res.config.users:0
@@ -685,6 +685,9 @@ msgid ""
"\n"
"This addon is already installed on your system"
msgstr ""
"\n"
"\n"
"Ce module est déjà installé sur votre système"
#. module: base
#: model:res.country,name:base.nu
@@ -729,7 +732,7 @@ msgstr "Modules du contrat de maintenance"
#: model:ir.actions.act_window,name:base.res_request_link-act
#: model:ir.ui.menu,name:base.menu_res_request_link_act
msgid "Request Reference Types"
msgstr ""
msgstr "Types de référence des requêtes"
#. module: base
#: view:ir.values:0
@@ -791,7 +794,7 @@ msgstr "STOCK_EDIT"
#. module: base
#: model:ir.ui.menu,name:base.menu_hr_project
msgid "Human Resources Dashboard"
msgstr ""
msgstr "Tableau de bord ressources humaines"
#. module: base
#: selection:ir.ui.menu,icon:0
@@ -822,7 +825,7 @@ msgstr "Îles Caïmans"
#. module: base
#: field:ir.module.module,contributors:0
msgid "Contributors"
msgstr ""
msgstr "Contributeurs"
#. module: base
#: selection:ir.property,type:0
@@ -852,7 +855,7 @@ msgstr "Niger"
#. module: base
#: selection:base.language.install,lang:0
msgid "Chinese (HK)"
msgstr ""
msgstr "Chinois (Hong Kong)"
#. module: base
#: model:res.country,name:base.ba
@@ -934,17 +937,17 @@ msgstr "Pour exporter une langue, ne sélectionnez aucune langue."
#. module: base
#: view:res.request:0
msgid "Request Date"
msgstr ""
msgstr "Date de la requête"
#. module: base
#: model:ir.ui.menu,name:base.menu_hr_dasboard
msgid "Dashboard"
msgstr ""
msgstr "Tableau de bord"
#. module: base
#: model:ir.ui.menu,name:base.menu_purchase_root
msgid "Purchases"
msgstr ""
msgstr "Achats"
#. module: base
#: model:res.country,name:base.md
@@ -1330,7 +1333,7 @@ msgstr "Malawi"
#: code:addons/base/res/res_user.py:0
#, python-format
msgid "%s (copy)"
msgstr ""
msgstr "%s (copie)"
#. module: base
#: field:res.partner.address,type:0
@@ -1419,7 +1422,7 @@ msgstr ""
#. module: base
#: view:base.language.export:0
msgid "https://help.launchpad.net/Translations"
msgstr ""
msgstr "https://help.launchpad.net/Translations"
#. module: base
#: field:ir.actions.act_window,view_mode:0
@@ -1522,7 +1525,7 @@ msgstr ""
#. module: base
#: selection:ir.ui.menu,icon:0
msgid "terp-stock_align_left_24"
msgstr ""
msgstr "terp-stock_align_left_24"
#. module: base
#: field:ir.actions.act_window,groups_id:0
@@ -1679,7 +1682,7 @@ msgstr "Vue originale"
#. module: base
#: selection:ir.ui.menu,icon:0
msgid "terp-camera_test"
msgstr ""
msgstr "terp-camera_test"
#. module: base
#: code:addons/base/res/res_user.py:0
@@ -1840,12 +1843,12 @@ msgstr "Slovénie"
#. module: base
#: selection:ir.ui.menu,icon:0
msgid "terp-stock_format-default"
msgstr ""
msgstr "terp-stock_format-default"
#. module: base
#: view:res.lang:0
msgid "%p - Equivalent of either AM or PM."
msgstr "%p - Soit AM soit à PM."
msgstr "%p - AM ou PM"
#. module: base
#: view:ir.actions.server:0
+3862 -2892
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2010-10-18 17:46+0000\n"
"PO-Revision-Date: 2010-11-06 06:53+0000\n"
"Last-Translator: OpenERP Administrators <Unknown>\n"
"PO-Revision-Date: 2010-11-11 14:09+0000\n"
"Last-Translator: Leonardo Pistone <Unknown>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-11-07 04:48+0000\n"
"X-Launchpad-Export-Date: 2010-11-12 04:45+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -1062,7 +1062,7 @@ msgstr "Percorso del report file principale"
#: field:ir.module.module,reports_by_module:0
#: model:ir.ui.menu,name:base.menu_ir_action_report_xml
msgid "Reports"
msgstr "Resoconti"
msgstr "Reports"
#. module: base
#: field:workflow,on_create:0
+3 -3
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2010-10-18 17:46+0000\n"
"PO-Revision-Date: 2010-11-01 08:31+0000\n"
"PO-Revision-Date: 2010-11-14 07:36+0000\n"
"Last-Translator: Chertykov Denis <chertykov@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-11-02 04:49+0000\n"
"X-Launchpad-Export-Date: 2010-11-15 04:59+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -96,7 +96,7 @@ msgstr "Рабочий процесс включен"
#. module: base
#: field:ir.actions.act_window,display_menu_tip:0
msgid "Display Menu Tips"
msgstr ""
msgstr "Выводить советы"
#. module: base
#: view:ir.module.module:0
+3891 -2013
View File
File diff suppressed because it is too large Load Diff
+2982 -1785
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -35,6 +35,7 @@ import workflow
import ir_rule
import wizard
import ir_config_parameter
import osv_memory_autovacuum
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+20
View File
@@ -705,6 +705,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.company</field>
<field name="view_type">form</field>
<field name="help">Create and manage the companies that will be managed by OpenERP from here. Shops or subsidiaries can be created and maintained from here.</field>
</record>
<menuitem action="action_res_company_form" id="menu_action_res_company_form" parent="base.menu_res_company_global"/>
@@ -716,6 +717,7 @@
<field name="view_type">form</field>
<field name="view_id" ref="view_users_tree"/>
<field name="search_view_id" ref="view_users_search"/>
<field name="help">Create and manage users that will connect to the system. Users can be deactivated should there be a period of time during which they will/should not connect to the system. You can assign them groups in order to give them specific access to the applications they need to use in the system.</field>
</record>
<record id="action_res_users_view1" model="ir.actions.act_window.view">
<field eval="10" name="sequence"/>
@@ -757,6 +759,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.groups</field>
<field name="view_type">form</field>
<field name="help">A group is a set of functional areas that will be assigned to the user in order to give them access and rights to specific applications and tasks in the system. You can create custom groups or edit the ones existing by default in order to customize the view of the menu that users will be able to see. Whether they can have a read, write, create and delete access right can be managed from here.</field>
</record>
<menuitem action="action_res_groups" id="menu_action_res_groups" parent="base.menu_users"
groups="base.group_extended"/>
@@ -844,6 +847,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.ui.view</field>
<field name="view_id" ref="view_view_tree"/>
<field name="help">Views allows you to personalize each view of OpenERP. You can add new fields, move fields, rename them or delete the ones that you do not need.</field>
</record>
<menuitem action="action_ui_view" id="menu_action_ui_view" parent="base.next_id_2"/>
@@ -1403,6 +1407,7 @@
<field name="view_type">form</field>
<field name="view_id" ref="edit_menu"/>
<field name="search_view_id" ref="edit_menu_access_search"/>
<field name="help">Manage and customize the items available and displayed in your OpenERP system menu. You can delete an item by clicking on the box at the beginning of each line and then delete it through the button that appeared. Items can be assigned to specific groups in order to make them accessible to some users within the system.</field>
</record>
<menuitem action="grant_menu_access" id="menu_grant_menu_access" parent="base.next_id_2" sequence="1"/>
@@ -1868,5 +1873,20 @@
<menuitem action="act_ir_actions_todo_form" id="menu_ir_actions_todo_form"
parent="next_id_11" groups="base.group_extended" sequence="20"/>
<record model="ir.cron" id="cronjob_osv_memory_autovacuum">
<field name='name'>AutoVacuum osv_memory objects</field>
<field name='interval_number'>30</field>
<field name='interval_type'>minutes</field>
<field name="numbercall">-1</field>
<field name="active">True</field>
<field name="doall" eval="False" />
<field name="model">osv_memory.autovacuum</field>
<field name="function">power_on</field>
<field name="args">()</field>
</record>
</data>
</openerp>
+2 -3
View File
@@ -485,7 +485,7 @@ class actions_server(osv.osv):
for field in fields:
try:
obj = getattr(obj, field)
except Exception,e :
except Exception:
logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (field))
return obj
@@ -506,7 +506,7 @@ class actions_server(osv.osv):
for field in fields:
try:
obj = getattr(obj, field)
except Exception,e :
except Exception:
logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (field))
return obj
@@ -514,7 +514,6 @@ class actions_server(osv.osv):
def merge_message(self, cr, uid, keystr, action, context=None):
if context is None:
context = {}
logger = netsvc.Logger()
def merge(match):
obj_pool = self.pool.get(action.model_id.model)
id = context.get('active_id')
+1 -1
View File
@@ -26,7 +26,7 @@ class ir_exports(osv.osv):
_name = "ir.exports"
_columns = {
'name': fields.char('Export Name', size=128),
'resource': fields.char('Resource', size=128),
'resource': fields.char('Resource', size=128, select=True),
'export_fields': fields.one2many('ir.exports.line', 'export_id',
'Export ID'),
}
+1 -1
View File
@@ -57,7 +57,7 @@ class ir_model(osv.osv):
return []
field, operator, value = domain[0]
if operator not in ['=', '!=']:
raise osv.except_osv('Invalid search criterions','The osv_memory field can only be compared with = and != operator.')
raise osv.except_osv(_('Invalid search criterions'), _('The osv_memory field can only be compared with = and != operator.'))
value = bool(value) if operator == '=' else not bool(value)
all_model_ids = self.search(cr, uid, [], context=context)
is_osv_mem = self._is_osv_memory(cr, uid, all_model_ids, 'osv_memory', arg=None, context=context)
+44 -57
View File
@@ -24,6 +24,11 @@ from osv.orm import except_orm
import pickle
from tools.translate import _
EXCLUDED_FIELDS = set((
'report_sxw_content', 'report_rml_content', 'report_sxw', 'report_rml',
'report_sxw_content_data', 'report_rml_content_data', 'search_view',
'search_view_id'))
class ir_values(osv.osv):
_name = 'ir.values'
@@ -96,7 +101,7 @@ class ir_values(osv.osv):
cr.execute('CREATE INDEX ir_values_key_model_key2_index ON ir_values (key, model, key2)')
def set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=False, preserve_user=False, company=False):
if type(value)==type(u''):
if isinstance(value, unicode):
value = value.encode('utf8')
if not isobject:
value = pickle.dumps(value)
@@ -104,30 +109,24 @@ class ir_values(osv.osv):
meta = pickle.dumps(meta)
ids_res = []
for model in models:
if type(model)==type([]) or type(model)==type(()):
if isinstance(model, (list, tuple)):
model,res_id = model
else:
res_id=False
if replace:
search_criteria = [
('key', '=', key),
('key2', '=', key2),
('model', '=', model),
('res_id', '=', res_id),
('user_id', '=', preserve_user and uid)
]
if key in ('meta', 'default'):
ids = self.search(cr, uid, [
('key', '=', key),
('key2', '=', key2),
('name', '=', name),
('model', '=', model),
('res_id', '=', res_id),
('user_id', '=', preserve_user and uid)
])
search_criteria.append(('name', '=', name))
else:
ids = self.search(cr, uid, [
('key', '=', key),
('key2', '=', key2),
('value', '=', value),
('model', '=', model),
('res_id', '=', res_id),
('user_id', '=', preserve_user and uid)
])
self.unlink(cr, uid, ids)
search_criteria.append(('value', '=', value))
self.unlink(cr, uid, self.search(cr, uid, search_criteria))
vals = {
'name': name,
'value': value,
@@ -149,8 +148,8 @@ class ir_values(osv.osv):
def get(self, cr, uid, key, key2, models, meta=False, context={}, res_id_req=False, without_user=True, key2_req=True):
result = []
for m in models:
if type(m)==type([]) or type(m)==type(()):
m,res_id = m
if isinstance(m, (list, tuple)):
m, res_id = m
else:
res_id=False
@@ -159,9 +158,8 @@ class ir_values(osv.osv):
if key2:
where.append('key2=%s')
params.append(key2[:200])
else:
if key2_req and not meta:
where.append('key2 is null')
elif key2_req and not meta:
where.append('key2 is null')
if res_id_req and (models[-1][0]==m):
if res_id:
where.append('res_id=%s')
@@ -193,48 +191,37 @@ class ir_values(osv.osv):
keys.append(x[1])
if x[3]:
model,id = x[2].split(',')
id = int(id)
fields = self.pool.get(model).fields_get_keys(cr, uid)
pos = 0
while pos<len(fields):
if fields[pos] in ('report_sxw_content', 'report_rml_content',
'report_sxw', 'report_rml', 'report_sxw_content_data',
'report_rml_content_data'):
del fields[pos]
else:
pos+=1
# FIXME: It might be a good idea to opt-in that kind of stuff
# FIXME: instead of arbitrarily removing random fields
fields = [
field
for field in self.pool.get(model).fields_get_keys(cr, uid)
if field not in EXCLUDED_FIELDS]
try:
datas = self.pool.get(model).read(cr, uid, [id], fields, context)
datas = self.pool.get(model).read(cr, uid, [int(id)], fields, context)
except except_orm, e:
return False
datas= datas and datas[0] or None
datas = datas and datas[0]
if not datas:
#ir_del(cr, uid, x[0])
return False
else:
datas = pickle.loads(str(x[2].encode('utf-8')))
datas = pickle.loads(x[2].encode('utf-8'))
if meta:
meta2 = pickle.loads(x[4])
return (x[0],x[1],datas,meta2)
return (x[0],x[1],datas)
return (x[0], x[1], datas, pickle.loads(x[4]))
return (x[0], x[1], datas)
keys = []
res = filter(bool, map(lambda x: _result_get(x, keys), list(result)))
res = filter(None, map(lambda x: _result_get(x, keys), result))
res2 = res[:]
for r in res:
if type(r[2])==type({}) and 'type' in r[2]:
if r[2]['type'] in ('ir.actions.report.xml','ir.actions.act_window','ir.actions.wizard'):
groups = r[2].get('groups_id')
if groups:
cr.execute('SELECT COUNT(1) FROM res_groups_users_rel WHERE gid IN %s AND uid=%s',(tuple(groups), uid))
cnt = cr.fetchone()[0]
if not cnt:
res2.remove(r)
if r[1] == 'Menuitem' and not res2:
raise osv.except_osv('Error !','You do not have the permission to perform this operation !!!')
if isinstance(r[2], dict) and r[2].get('type') in ('ir.actions.report.xml','ir.actions.act_window','ir.actions.wizard'):
groups = r[2].get('groups_id')
if groups:
cr.execute('SELECT COUNT(1) FROM res_groups_users_rel WHERE gid IN %s AND uid=%s',(tuple(groups), uid))
cnt = cr.fetchone()[0]
if not cnt:
res2.remove(r)
if r[1] == 'Menuitem' and not res2:
raise osv.except_osv('Error !','You do not have the permission to perform this operation !!!')
return res2
ir_values()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2010 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv
from osv.orm import orm_memory
class osv_memory_autovacuum(osv.osv_memory):
_name = 'osv_memory.autovacuum'
def power_on(self, cr, uid, context=None):
for model in self.pool.obj_list():
obj = self.pool.get(model)
if isinstance(obj, orm_memory):
obj.vaccum(cr, uid)
return True
osv_memory_autovacuum()
+2 -2
View File
@@ -53,8 +53,8 @@ class module_category(osv.osv):
result = dict(cr.fetchall())
for id in ids:
cr.execute('select id from ir_module_category where parent_id=%s', (id,))
childs = [c for c, in cr.fetchall()]
result[id] = reduce(lambda x,y:x+y, [result.get(c, 0) for c in childs], result.get(id, 0))
result[id] = sum([result.get(c, 0) for (c,) in cr.fetchall()],
result.get(id, 0))
return result
_columns = {
+2 -2
View File
@@ -68,7 +68,6 @@
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('category_id','=',active_id)]</field>
</record>
<record id="ir_action_module_category" model="ir.values">
<field eval="'tree_but_open'" name="key2"/>
@@ -169,7 +168,8 @@
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain"/>
<field name="search_view_id" ref="view_module_filter"/>
<field name="search_view_id" ref="view_module_filter"/>
<field name="help">List all certified modules available to configure your OpenERP. Modules that are installed are flagged as such. You can search for a specific module using the name or the description of the module. You do not need to install modules one by one, you can install many at the same time by clicking on the schedule button in this list. Then, apply the schedule upgrade from Action menu once for all the ones you have scheduled for installation.</field>
</record>
<menuitem action="open_module_tree" id="menu_module_tree" parent="base.menu_management"/>
@@ -22,6 +22,8 @@
<separator orientation="vertical" rowspan="15"/>
<group colspan="4" col="4">
<separator string="Import Translation" colspan="4"/>
<label colspan="4" nolabel="1" string="If you need another language than the official ones available, you can import a language pack from here. Other OpenERP languages than the official ones can be found on launchpad."/>
<newline/>
<field name="name" width="200"/>
<field name="code"/>
<field name="data" colspan="4"/>
@@ -93,7 +93,7 @@ class base_module_upgrade(osv.osv_memory):
if dep_mod.state in ('unknown','uninstalled'):
unmet_packages.append(dep_mod.name)
if len(unmet_packages):
raise osv.except_osv('Unmet dependency !', 'Following modules are uninstalled or unknown. \n\n'+'\n'.join(unmet_packages))
raise osv.except_osv(_('Unmet dependency !'), _('Following modules are not installed or unknown: %s') % ('\n\n' + '\n'.join(unmet_packages)))
mod_obj.download(cr, uid, ids, context=context)
cr.commit()
_, pool = pooler.restart_pool(cr.dbname, update_module=True)
-1
View File
@@ -23,7 +23,6 @@ import math
from osv import fields,osv
import tools
import ir
import pooler
from tools.translate import _
+16 -38
View File
@@ -18,7 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import logging
from operator import attrgetter
from osv import osv, fields
@@ -37,6 +37,7 @@ class res_config_configurable(osv.osv_memory):
_name = 'res.config'
_inherit = 'ir.wizard.screen'
logger = netsvc.Logger()
__logger = logging.getLogger(_name)
def get_current_progress(self, cr, uid, context=None):
'''Return a description the current progress of configuration:
@@ -63,14 +64,13 @@ class res_config_configurable(osv.osv_memory):
def _next_action(self, cr, uid, context=None):
todos = self.pool.get('ir.actions.todo')
self.logger.notifyChannel('actions', netsvc.LOG_INFO,
'getting next %s' % todos)
self.__logger.info('getting next %s', todos)
active_todos = todos.search(cr, uid, [('state','=','open')],
limit=1)
dont_skip_todo = True
if active_todos:
todo_obj = todos.browse(cr, uid, active_todos[0], context=None)
todo_groups = map(lambda x:x.id, todo_obj.groups_id)
dont_skip_todo = True
if todo_groups:
cr.execute("select 1 from res_groups_users_rel where uid=%s and gid IN %s",(uid, tuple(todo_groups),))
dont_skip_todo = bool(cr.fetchone())
@@ -84,30 +84,20 @@ class res_config_configurable(osv.osv_memory):
def _set_previous_todo(self, cr, uid, state, context=None):
""" lookup the previous (which is still the next at this point)
ir.actions.todo, set it to whatever state was provided.
Raises
`LookupError`: if we couldn't find *any* previous todo
`ValueError`: if no state is provided
anything ir_actions_todo.write can throw
"""
if context is None:
context = {}
# this is ultra brittle, but apart from storing the todo id
# into the res.config view, I'm not sure how to get the
# "previous" todo
previous_todo = self._next_action(cr, uid, context=context)
if not previous_todo:
raise LookupError(_("Couldn't find previous ir.actions.todo"))
if not state:
raise ValueError(_("Can't set an ir.actions.todo's state to an empty value."))
self.__logger.warn(_("Couldn't find previous ir.actions.todo"))
return
previous_todo.write({'state':state})
def _next(self, cr, uid, context=None):
self.logger.notifyChannel('actions', netsvc.LOG_INFO,
'getting next operation')
self.__logger.info('getting next operation')
next = self._next_action(cr, uid)
self.logger.notifyChannel('actions', netsvc.LOG_INFO,
'next action is %s' % next)
self.__logger.info('next action is %s', next)
if next:
action = next.action_id
return {
@@ -118,9 +108,7 @@ class res_config_configurable(osv.osv_memory):
'type': action.type,
'target': action.target,
}
self.logger.notifyChannel(
'actions', netsvc.LOG_INFO,
'all configuration actions have been executed')
self.__logger.info('all configuration actions have been executed')
current_user_menu = self.pool.get('res.users')\
.browse(cr, uid, uid).menu_id
@@ -174,10 +162,7 @@ class res_config_configurable(osv.osv_memory):
an action dictionary -- executes the action provided by calling
``next``.
"""
try:
self._set_previous_todo(cr, uid, state='done', context=context)
except Exception, e:
raise osv.except_osv(_('Error'), e.message)
self._set_previous_todo(cr, uid, state='done', context=context)
next = self.execute(cr, uid, ids, context=None)
if next: return next
return self.next(cr, uid, ids, context=context)
@@ -190,10 +175,7 @@ class res_config_configurable(osv.osv_memory):
an action dictionary -- executes the action provided by calling
``next``.
"""
try:
self._set_previous_todo(cr, uid, state='skip', context=context)
except Exception, e:
raise osv.except_osv(_('Error'), e.message)
self._set_previous_todo(cr, uid, state='skip', context=context)
next = self.cancel(cr, uid, ids, context=None)
if next: return next
return self.next(cr, uid, ids, context=context)
@@ -209,10 +191,7 @@ class res_config_configurable(osv.osv_memory):
an action dictionary -- executes the action provided by calling
``next``.
"""
try:
self._set_previous_todo(cr, uid, state='cancel', context=context)
except Exception, e:
raise osv.except_osv(_('Error'), e.message)
self._set_previous_todo(cr, uid, state='cancel', context=context)
next = self.cancel(cr, uid, ids, context=None)
if next: return next
return self.next(cr, uid, ids, context=context)
@@ -313,6 +292,7 @@ class res_config_installer(osv.osv_memory):
"""
_name = 'res.config.installer'
_inherit = 'res.config'
__logger = logging.getLogger(_name)
_install_if = {}
@@ -408,9 +388,7 @@ class res_config_installer(osv.osv_memory):
modules = self.pool.get('ir.module.module')
to_install = list(self.modules_to_install(
cr, uid, ids, context=context))
self.logger.notifyChannel(
'installer', netsvc.LOG_INFO,
'Selecting addons %s to install'%to_install)
self.__logger.info('Selecting addons %s to install', to_install)
modules.state_update(
cr, uid,
modules.search(cr, uid, [('name','in',to_install)]),
@@ -432,6 +410,7 @@ class ir_actions_configuration_wizard(osv.osv_memory):
'''
_name='ir.actions.configuration.wizard'
_inherit = 'res.config'
__logger = logging.getLogger(_name)
def _next_action_note(self, cr, uid, ids, context=None):
next = self._next_action(cr, uid)
@@ -451,8 +430,7 @@ class ir_actions_configuration_wizard(osv.osv_memory):
}
def execute(self, cr, uid, ids, context=None):
self.logger.notifyChannel(
'configuration', netsvc.LOG_WARNING, DEPRECATION_MESSAGE)
self.__logger.warn(DEPRECATION_MESSAGE)
ir_actions_configuration_wizard()
+2 -1
View File
@@ -33,6 +33,7 @@ import time
class groups(osv.osv):
_name = "res.groups"
_order = 'name'
_description = "Access Groups"
_columns = {
'name': fields.char('Group Name', size=64, required=True),
'model_access': fields.one2many('ir.model.access', 'group_id', 'Access Controls'),
@@ -264,7 +265,7 @@ class users(osv.osv):
]
_sql_constraints = [
('login_key', 'UNIQUE (login)', _('You can not have two users with the same login !'))
('login_key', 'UNIQUE (login)', 'You can not have two users with the same login !')
]
def _get_email_from(self, cr, uid, ids, context=None):
+1 -1
View File
@@ -31,7 +31,7 @@ def ir_del(cr, uid, id):
obj = pooler.get_pool(cr.dbname).get('ir.values')
return obj.unlink(cr, uid, [id])
def ir_get(cr, uid, key, key2, models, meta=False, context={}, res_id_req=False):
def ir_get(cr, uid, key, key2, models, meta=False, context=None, res_id_req=False):
obj = pooler.get_pool(cr.dbname).get('ir.values')
res = obj.get(cr, uid, key, key2, models, meta=meta, context=context, res_id_req=res_id_req)
return res
+11 -9
View File
@@ -63,8 +63,10 @@ class _column(object):
_symbol_set = (_symbol_c, _symbol_f)
_symbol_get = None
def __init__(self, string='unknown', required=False, readonly=False, domain=None, context={}, states=None, priority=0, change_default=False, size=None, ondelete="set null", translate=False, select=False, **args):
if not context:
def __init__(self, string='unknown', required=False, readonly=False, domain=None, context=None, states=None, priority=0, change_default=False, size=None, ondelete="set null", translate=False, select=False, **args):
if domain is None:
domain = []
if context is None:
context = {}
self.states = states or {}
self.string = string
@@ -76,7 +78,7 @@ class _column(object):
self.change_default = change_default
self.ondelete = ondelete
self.translate = translate
self._domain = domain or []
self._domain = domain
self._context = context
self.write = False
self.read = False
@@ -403,7 +405,7 @@ class one2many(_column):
assert(self.change_default != True)
def get_memory(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
if not context:
if context is None:
context = {}
if self._context:
context = context.copy()
@@ -786,7 +788,7 @@ class function(_column):
class related(function):
def _fnct_search(self, tobj, cr, uid, obj=None, name=None, domain=None, context={}):
def _fnct_search(self, tobj, cr, uid, obj=None, name=None, domain=None, context=None):
self._field_get2(cr, uid, obj, context)
i = len(self._arg)-1
sarg = name
@@ -803,7 +805,7 @@ class related(function):
return [(self._arg[0], 'in', sarg)]
def _fnct_write(self,obj,cr, uid, ids, field_name, values, args, context=None):
self._field_get2(cr, uid, obj, context)
self._field_get2(cr, uid, obj, context=context)
if type(ids) != type([]):
ids=[ids]
objlst = obj.browse(cr, uid, ids)
@@ -884,7 +886,7 @@ class related(function):
# TODO: improve here to change self.store = {...} according to related objects
pass
def _field_get2(self, cr, uid, obj, context={}):
def _field_get2(self, cr, uid, obj, context=None):
if self._relations:
return
obj_name = obj._name
@@ -904,10 +906,10 @@ class related(function):
# ---------------------------------------------------------
class dummy(function):
def _fnct_search(self, tobj, cr, uid, obj=None, name=None, domain=None, context={}):
def _fnct_search(self, tobj, cr, uid, obj=None, name=None, domain=None, context=None):
return []
def _fnct_write(self,obj,cr, uid, ids, field_name, values, args, context=None):
def _fnct_write(self, obj, cr, uid, ids, field_name, values, args, context=None):
return False
def _fnct_read(self, obj, cr, uid, ids, field_name, args, context=None):
+28 -24
View File
@@ -126,12 +126,14 @@ class browse_record_list(list):
class browse_record(object):
logger = netsvc.Logger()
def __init__(self, cr, uid, id, table, cache, context=None, list_class = None, fields_process={}):
def __init__(self, cr, uid, id, table, cache, context=None, list_class=None, fields_process=None):
'''
table : the object (inherited from orm)
context : dictionary with an optional context
'''
if not context:
if fields_process is None:
fields_process = {}
if context is None:
context = {}
self._list_class = list_class or browse_record_list
self._cr = cr
@@ -404,7 +406,9 @@ class orm_template(object):
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None):
raise NotImplementedError(_('The read_group method is not implemented on this object !'))
def _field_create(self, cr, context={}):
def _field_create(self, cr, context=None):
if context is None:
context = {}
cr.execute("SELECT id FROM ir_model WHERE model=%s", (self._name,))
if not cr.rowcount:
cr.execute('SELECT nextval(%s)', ('ir_model_id_seq',))
@@ -489,8 +493,8 @@ class orm_template(object):
break
cr.commit()
def _auto_init(self, cr, context={}):
self._field_create(cr, context)
def _auto_init(self, cr, context=None):
self._field_create(cr, context=context)
def __init__(self, cr):
if not self._name and not hasattr(self, '_inherit'):
@@ -506,7 +510,7 @@ class orm_template(object):
if not self._table:
self._table = self._name.replace('.', '_')
def browse(self, cr, uid, select, context=None, list_class=None, fields_process={}):
def browse(self, cr, uid, select, context=None, list_class=None, fields_process=None):
"""
Fetch records as objects allowing to use dot notation to browse fields and relations
@@ -517,8 +521,6 @@ class orm_template(object):
:rtype: object or list of objects requested
"""
if not context:
context = {}
self._list_class = list_class or browse_record_list
cache = {}
# need to accepts ints and longs because ids coming from a method
@@ -526,7 +528,7 @@ class orm_template(object):
if isinstance(select, (int, long)):
return browse_record(cr, uid, select, self, cache, context=context, list_class=self._list_class, fields_process=fields_process)
elif isinstance(select, list):
return self._list_class([browse_record(cr, uid, id, self, cache, context=context, list_class=self._list_class, fields_process=fields_process) for id in select], context)
return self._list_class([browse_record(cr, uid, id, self, cache, context=context, list_class=self._list_class, fields_process=fields_process) for id in select], context=context)
else:
return browse_null()
@@ -554,8 +556,8 @@ class orm_template(object):
lines = []
data = map(lambda x: '', range(len(fields)))
done = []
for fpos in range(len(fields)):
done = []
f = fields[fpos]
if f:
r = row
@@ -600,7 +602,8 @@ class orm_template(object):
fields2 = map(lambda x: (x[:i+1]==f[:i+1] and x[i+1:]) \
or [], fields)
if fields2 in done:
break
if [x for x in fields2 if x]:
break
done.append(fields2)
for row2 in r:
lines2 = self.__export_row(cr, uid, row2, fields2,
@@ -1274,7 +1277,7 @@ class orm_template(object):
context = {}
result = False
fields = {}
childs = True
children = True
def encode(s):
if isinstance(s, unicode):
@@ -1328,7 +1331,7 @@ class orm_template(object):
if column:
relation = self.pool.get(column._obj)
childs = False
children = False
views = {}
for f in node:
if f.tag in ('form', 'tree', 'graph'):
@@ -1390,7 +1393,7 @@ class orm_template(object):
node.set('sum', trans)
for f in node:
if childs or (node.tag == 'field' and f.tag in ('filter','separator')):
if children or (node.tag == 'field' and f.tag in ('filter','separator')):
fields.update(self.__view_look_dom(cr, user, f, view_id, context))
return fields
@@ -1437,7 +1440,7 @@ class orm_template(object):
fields = self.fields_get(cr, user, fields_def.keys(), context)
for field in fields_def:
if field == 'id':
# sometime, the view may containt the (invisible) field 'id' needed for a domain (when 2 objects have cross references)
# sometime, the view may contain the (invisible) field 'id' needed for a domain (when 2 objects have cross references)
fields['id'] = {'readonly': True, 'type': 'integer', 'string': 'ID'}
elif field in fields:
fields[field].update(fields_def[field])
@@ -1447,7 +1450,7 @@ class orm_template(object):
model = res[0][1]
res.insert(0, ("Can't find field '%s' in the following view parts composing the view of object model '%s':" % (field, model), None))
msg = "\n * ".join([r[0] for r in res])
msg += "\n\nEither you wrongly customised this view, or some modules bringing those views are not compatible with your current data model"
msg += "\n\nEither you wrongly customized this view, or some modules bringing those views are not compatible with your current data model"
netsvc.Logger().notifyChannel('orm', netsvc.LOG_ERROR, msg)
raise except_orm('View error', msg)
return arch, fields
@@ -1498,14 +1501,14 @@ class orm_template(object):
return arch
def __get_default_search_view(self, cr, uid, context={}):
def __get_default_search_view(self, cr, uid, context=None):
def encode(s):
if isinstance(s, unicode):
return s.encode('utf8')
return s
view = self.fields_view_get(cr, uid, False, 'form', context)
view = self.fields_view_get(cr, uid, False, 'form', context=context)
root = etree.fromstring(encode(view['arch']))
res = etree.XML("""<search string="%s"></search>""" % root.get("string", ""))
@@ -2355,8 +2358,7 @@ class orm(orm_template):
where += ' order by '+self._parent_order
cr.execute('SELECT id FROM '+self._table+' WHERE '+where)
pos2 = pos + 1
childs = cr.fetchall()
for id in childs:
for id in cr.fetchall():
pos2 = browse_rec(id[0], pos2)
cr.execute('update '+self._table+' set parent_left=%s, parent_right=%s where id=%s', (pos, pos2, root))
return pos2 + 1
@@ -2411,7 +2413,9 @@ class orm(orm_template):
self.__schema.debug("Table '%s': column '%s': dropped NOT NULL constraint",
self._table, column['attname'])
def _auto_init(self, cr, context={}):
def _auto_init(self, cr, context=None):
if context is None:
context = {}
store_compute = False
create = False
todo_end = []
@@ -4154,9 +4158,9 @@ class orm(orm_template):
old_record, new_record = self.read(cr, uid, [old_id, new_id], [field_name], context=context)
# here we rely on the order of the ids to match the translations
# as foreseen in copy_data()
old_childs = sorted(old_record[field_name])
new_childs = sorted(new_record[field_name])
for (old_child, new_child) in zip(old_childs, new_childs):
old_children = sorted(old_record[field_name])
new_children = sorted(new_record[field_name])
for (old_child, new_child) in zip(old_children, new_children):
# recursive copy of translations here
target_obj.copy_translations(cr, uid, old_child, new_child, context=context)
# and for translatable fields we keep them for copy
+1 -1
View File
@@ -254,7 +254,7 @@ class document(object):
for el_cld in node:
self.parse_node(el_cld, el, v)
else:
# if there is no "type" attribute in the node, copy it to the xml data and parse its childs
# if there is no "type" attribute in the node, copy it to the xml data and parse its children
if not node.tag == etree.Comment:
if node.tag == parent.tag:
el = parent
-1
View File
@@ -139,7 +139,6 @@ class report_printscreen_list(report_int):
_append_node('header-date', str(rml_obj.formatLang(time.strftime("%Y-%m-%d"),date=True))+' ' + str(time.strftime("%H:%M")))
l = []
t = 0
rowcount = 0;
strmax = (pageSize[0]-40) * 2.8346
temp = []
tsum = []
+3 -3
View File
@@ -552,8 +552,8 @@ class _rml_flowable(object):
return rc1
def _table(self, node):
childs = utils._child_get(node,self,'tr')
if not childs:
children = utils._child_get(node,self,'tr')
if not children:
return None
length = 0
colwidths = None
@@ -561,7 +561,7 @@ class _rml_flowable(object):
data = []
styles = []
posy = 0
for tr in childs:
for tr in children:
paraStyle = None
if tr.get('style'):
st = copy.deepcopy(self.styles.table_styles[tr.get('style')])
+14 -14
View File
@@ -36,15 +36,14 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import re
import reportlab
from lxml import etree
import copy
import locale
import traceback, sys
import logging
import re
import reportlab
import tools
from tools.safe_eval import safe_eval as eval
import logging
_regex = re.compile('\[\[(.+?)\]\]')
@@ -117,18 +116,19 @@ def _process_text(self, txt):
sps = _regex.split(txt)
while sps:
# This is a simple text to translate
result += unicode(self.localcontext.get('translate', lambda x:x)(sps.pop(0)))
to_translate = tools.ustr(sps.pop(0))
result += tools.ustr(self.localcontext.get('translate', lambda x:x)(to_translate))
if sps:
try:
txt = None
expr = sps.pop(0)
txt = eval(expr,self.localcontext)
if txt and (isinstance(txt, unicode) or isinstance(txt, str)):
txt = unicode(txt)
except Exception,e:
tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
if type(txt)==type('') or type(txt)==type(u''):
txt2 = str2xml(txt)
result += unicode(txt2)
txt = eval(expr, self.localcontext)
if txt and isinstance(txt, basestring):
txt = tools.ustr(txt)
except Exception:
pass
if isinstance(txt, basestring):
result += str2xml(txt)
elif (txt is not None) and (txt is not False):
result += unicode(txt)
return result
+1 -5
View File
@@ -204,13 +204,10 @@ class rml_parse(object):
return res['datas']
else :
return ''
except Exception,e:
except Exception:
return ''
def setLang(self, lang):
if not lang or self.default_lang.has_key(lang):
if not lang:
key = 'en_US'
self.localcontext['lang'] = lang
self.lang_dict_called = False
for obj in self.objects:
@@ -519,7 +516,6 @@ class report_sxw(report_rml, preprocess.report):
xml_declaration=True)
rml_dom = etree.XML(rml)
body = rml_dom[-1]
elements = []
key1 = rml_parser.localcontext['name_space']["text"]+"p"
key2 = rml_parser.localcontext['name_space']["text"]+"drop-down"
+1
View File
@@ -20,3 +20,4 @@
##############################################################################
from test_osv import *
from test_translate import *
+48
View File
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2010 OpenERP S.A. http://www.openerp.com
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import unittest
from tools.translate import quote, unquote
class TranslationToolsTestCase(unittest.TestCase):
def test_quote_unquote(self):
def test_string(str):
quoted = quote(str)
#print "\n1:", repr(str)
#print "2:", repr(quoted)
unquoted = unquote("".join(quoted.split('"\n"')))
#print "3:", repr(unquoted)
self.assertEquals(str, unquoted)
test_string("""test \nall kinds\n \n o\r
\\\\ nope\n\n"
""")
# The ones with 1+ backslashes directly followed by
# a newline or literal N can fail... we would need a
# state-machine parser to handle these, but this would
# be much slower so it's better to avoid them at the moment
self.assertRaises(AssertionError, quote, """test \nall kinds\n\no\r
\\\\nope\n\n"
""")
+4 -2
View File
@@ -463,11 +463,13 @@ class configmanager(object):
# try to create the directories and write the file
try:
if not os.path.exists(os.path.dirname(self.rcfile)):
rc_exists = os.path.exists(self.rcfile)
if not rc_exists and not os.path.exists(os.path.dirname(self.rcfile)):
os.makedirs(os.path.dirname(self.rcfile))
try:
p.write(file(self.rcfile, 'w'))
os.chmod(self.rcfile, 0600)
if not rc_exists:
os.chmod(self.rcfile, 0600)
except IOError:
sys.stderr.write("ERROR: couldn't write the config file\n")
+79 -69
View File
@@ -68,6 +68,18 @@ def _obj(pool, cr, uid, model_str, context=None):
model = pool.get(model_str)
return lambda x: model.browse(cr, uid, x, context=context)
def _get_idref(self, cr, uid, model_str, context, idref):
idref2 = dict(idref,
time=time,
DateTime=datetime,
timedelta=timedelta,
version=release.major_version,
ref=_ref(self, cr),
pytz=pytz)
if len(model_str):
idref2['obj'] = _obj(self.pool, cr, uid, model_str, context=context)
return idref2
def _fix_multiple_roots(node):
"""
Surround the children of the ``node`` element of an XML field with a
@@ -90,72 +102,68 @@ def _eval_xml(self, node, pool, cr, uid, idref, context=None):
if context is None:
context = {}
if node.tag in ('field','value'):
t = node.get('type','char')
f_model = node.get('model', '').encode('utf-8')
if node.get('search'):
f_search = node.get("search",'').encode('utf-8')
f_use = node.get("use",'id').encode('utf-8')
f_name = node.get("name",'').encode('utf-8')
q = unsafe_eval(f_search, idref)
ids = pool.get(f_model).search(cr, uid, q)
if f_use != 'id':
ids = map(lambda x: x[f_use], pool.get(f_model).read(cr, uid, ids, [f_use]))
_cols = pool.get(f_model)._columns
if (f_name in _cols) and _cols[f_name]._type=='many2many':
return ids
f_val = False
if len(ids):
f_val = ids[0]
if isinstance(f_val, tuple):
f_val = f_val[0]
return f_val
a_eval = node.get('eval','')
if a_eval:
idref2 = dict(idref,
time=time,
DateTime=datetime,
timedelta=timedelta,
version=release.major_version,
ref=lambda x: self.id_get(cr, False, x),
pytz=pytz)
if len(f_model):
idref2['obj'] = _obj(self.pool, cr, uid, f_model, context=context)
try:
return unsafe_eval(a_eval, idref2)
except Exception:
logger = logging.getLogger('init')
logger.warning('could not eval(%s) for %s in %s' % (a_eval, node.get('name'), context), exc_info=True)
return ""
if t == 'xml':
def _process(s, idref):
m = re.findall('[^%]%\((.*?)\)[ds]', s)
for id in m:
if not id in idref:
idref[id]=self.id_get(cr, False, id)
return s % idref
_fix_multiple_roots(node)
return '<?xml version="1.0"?>\n'\
+_process("".join([etree.tostring(n, encoding='utf-8')
for n in node]),
idref)
if t in ('char', 'int', 'float'):
d = node.text
if t == 'int':
d = d.strip()
if d == 'None':
return None
else:
return int(d.strip())
elif t == 'float':
return float(d.strip())
return d
elif t in ('list','tuple'):
res=[]
for n in node.findall('./value'):
res.append(_eval_xml(self,n,pool,cr,uid,idref))
if t=='tuple':
return tuple(res)
return res
t = node.get('type','char')
f_model = node.get('model', '').encode('utf-8')
if node.get('search'):
f_search = node.get("search",'').encode('utf-8')
f_use = node.get("use",'id').encode('utf-8')
f_name = node.get("name",'').encode('utf-8')
idref2 = {}
if f_search:
idref2 = _get_idref(self, cr, uid, f_model, context, idref)
q = unsafe_eval(f_search, idref2)
ids = pool.get(f_model).search(cr, uid, q)
if f_use != 'id':
ids = map(lambda x: x[f_use], pool.get(f_model).read(cr, uid, ids, [f_use]))
_cols = pool.get(f_model)._columns
if (f_name in _cols) and _cols[f_name]._type=='many2many':
return ids
f_val = False
if len(ids):
f_val = ids[0]
if isinstance(f_val, tuple):
f_val = f_val[0]
return f_val
a_eval = node.get('eval','')
idref2 = {}
if a_eval:
idref2 = _get_idref(self, cr, uid, f_model, context, idref)
try:
return unsafe_eval(a_eval, idref2)
except Exception:
logger = logging.getLogger('init')
logger.warning('could not eval(%s) for %s in %s' % (a_eval, node.get('name'), context), exc_info=True)
return ""
if t == 'xml':
def _process(s, idref):
m = re.findall('[^%]%\((.*?)\)[ds]', s)
for id in m:
if not id in idref:
idref[id]=self.id_get(cr, False, id)
return s % idref
_fix_multiple_roots(node)
return '<?xml version="1.0"?>\n'\
+_process("".join([etree.tostring(n, encoding='utf-8')
for n in node]),
idref)
if t in ('char', 'int', 'float'):
d = node.text
if t == 'int':
d = d.strip()
if d == 'None':
return None
else:
return int(d.strip())
elif t == 'float':
return float(d.strip())
return d
elif t in ('list','tuple'):
res=[]
for n in node.findall('./value'):
res.append(_eval_xml(self,n,pool,cr,uid,idref))
if t=='tuple':
return tuple(res)
return res
elif node.tag == "getitem":
for n in node:
res=_eval_xml(self,n,pool,cr,uid,idref)
@@ -273,11 +281,13 @@ form: module.record_id""" % (xml_id,)
def _tag_delete(self, cr, rec, data_node=None):
d_model = rec.get("model",'')
d_search = rec.get("search",'')
d_search = rec.get("search",'').encode('utf-8')
d_id = rec.get("id",'')
ids = []
if d_search:
ids = self.pool.get(d_model).search(cr, self.uid, unsafe_eval(d_search))
idref = _get_idref(self, cr, self.uid, d_model, context={}, idref={})
ids = self.pool.get(d_model).search(cr, self.uid, unsafe_eval(d_search, idref))
if d_id:
try:
ids.append(self.id_get(cr, d_model, d_id))
@@ -655,7 +665,7 @@ form: module.record_id""" % (xml_id,)
self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(pid))], action, True, True, xml_id=rec_id)
return ('ir.ui.menu', pid)
def _assert_equals(self, f1, f2, prec = 4):
def _assert_equals(self, f1, f2, prec=4):
return not round(f1 - f2, prec)
def _tag_assert(self, cr, rec, data_node=None):
+3 -1
View File
@@ -164,7 +164,7 @@ d[types.InstanceType] = _copy_inst
del d
def deepcopy(x, memo=None, _nil=[]):
def deepcopy(x, memo=None, _nil=None):
"""Deep copy operation on arbitrary Python objects.
See the module's __doc__ string for more info.
@@ -172,6 +172,8 @@ def deepcopy(x, memo=None, _nil=[]):
if memo is None:
memo = {}
if _nil is None:
_nil = {}
d = id(x)
y = memo.get(d, _nil)
+21 -4
View File
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -15,17 +16,17 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
__all__ = ['partial', 'wraps', 'update_wrapper']
__all__ = ['partial', 'wraps', 'update_wrapper', 'synchronized']
try:
from functools import partial, wraps, update_wrapper
except ImportError:
# The functools module doesn't exist in python < 2.5
# Code taken from python 2.5
# Code taken from python 2.5
# http://svn.python.org/view/python/tags/r254/Lib/functools.py?view=markup
def partial(fun, *args, **kwargs):
@@ -76,3 +77,19 @@ except ImportError:
return partial(update_wrapper, wrapped=wrapped,
assigned=assigned, updated=updated)
def synchronized(lock_attr='_lock'):
def decorator(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
lock = getattr(self, lock_attr)
try:
lock.acquire()
return func(self, *args, **kwargs)
finally:
lock.release()
return wrapper
return decorator
+115
View File
@@ -0,0 +1,115 @@
# -*- coding: utf-8 -*-
# taken from http://code.activestate.com/recipes/252524-length-limited-o1-lru-cache-implementation/
import threading
from func import synchronized
__all__ = ['LRU']
class LRUNode(object):
__slots__ = ['prev', 'next', 'me']
def __init__(self, prev, me):
self.prev = prev
self.me = me
self.next = None
class LRU:
"""
Implementation of a length-limited O(1) LRU queue.
Built for and used by PyPE:
http://pype.sourceforge.net
Copyright 2003 Josiah Carlson.
"""
def __init__(self, count, pairs=[]):
self._lock = threading.RLock()
self.count = max(count, 1)
self.d = {}
self.first = None
self.last = None
for key, value in pairs:
self[key] = value
@synchronized()
def __contains__(self, obj):
return obj in self.d
@synchronized()
def __getitem__(self, obj):
a = self.d[obj].me
self[a[0]] = a[1]
return a[1]
@synchronized()
def __setitem__(self, obj, val):
if obj in self.d:
del self[obj]
nobj = LRUNode(self.last, (obj, val))
if self.first is None:
self.first = nobj
if self.last:
self.last.next = nobj
self.last = nobj
self.d[obj] = nobj
if len(self.d) > self.count:
if self.first == self.last:
self.first = None
self.last = None
return
a = self.first
a.next.prev = None
self.first = a.next
a.next = None
del self.d[a.me[0]]
del a
@synchronized()
def __delitem__(self, obj):
nobj = self.d[obj]
if nobj.prev:
nobj.prev.next = nobj.next
else:
self.first = nobj.next
if nobj.next:
nobj.next.prev = nobj.prev
else:
self.last = nobj.prev
del self.d[obj]
@synchronized()
def __iter__(self):
cur = self.first
while cur != None:
cur2 = cur.next
yield cur.me[1]
cur = cur2
@synchronized()
def __len__(self):
return len(self.d)
@synchronized()
def iteritems(self):
cur = self.first
while cur != None:
cur2 = cur.next
yield cur.me
cur = cur2
@synchronized()
def iterkeys(self):
return iter(self.d)
@synchronized()
def itervalues(self):
for i,j in self.iteritems():
yield j
@synchronized()
def keys(self):
return self.d.keys()
@synchronized()
def pop(self,key):
v=self[key]
del self[key]
return v
+7 -7
View File
@@ -40,7 +40,6 @@ from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.Header import Header
from email.Utils import formatdate, COMMASPACE
from email.Utils import formatdate, COMMASPACE
from email import Encoders
from itertools import islice, izip
from which import which
@@ -51,6 +50,7 @@ else:
import netsvc
from config import config
from lru import LRU
_logger = logging.getLogger('tools')
@@ -432,7 +432,7 @@ def _email_send(smtp_from, smtp_to_list, message, openobject_id=None, ssl=False,
from mailbox import Maildir
maildir_path = smtp_server[8:]
mdir = Maildir(maildir_path,factory=None, create = True)
mdir.add(msg.as_string(True))
mdir.add(message.as_string(True))
return True
oldstderr = smtplib.stderr
@@ -697,7 +697,7 @@ class cache(object):
__caches = []
def __init__(self, timeout=None, skiparg=2, multi=None):
def __init__(self, timeout=None, skiparg=2, multi=None, size=8192):
assert skiparg >= 2 # at least self and cr
if timeout is None:
self.timeout = config['cache_timeout']
@@ -706,7 +706,7 @@ class cache(object):
self.skiparg = skiparg
self.multi = multi
self.lasttime = time.time()
self.cache = {}
self.cache = LRU(size) # TODO take size from config
self.fun = None
cache.__caches.append(self)
@@ -864,14 +864,14 @@ def ustr(value, hint_encoding='utf-8'):
try:
return unicode(value)
except Exception:
raise UnicodeError('unable de to convert %r' % (value,))
raise UnicodeError('unable to convert %r' % (value,))
for ln in get_encodings(hint_encoding):
try:
return unicode(value, ln)
except Exception:
pass
raise UnicodeError('unable de to convert %r' % (value,))
raise UnicodeError('unable to convert %r' % (value,))
def exception_to_unicode(e):
@@ -1408,7 +1408,7 @@ def upload_data(email, data, type='SURVEY'):
return True
# port of python 2.6's attrgetter with support for dotted notation
# port of python 2.6's attrgetter with support for dotted notation
def resolve_attr(obj, attr):
for name in attr.split("."):
obj = getattr(obj, name)
+5 -3
View File
@@ -33,6 +33,8 @@ without flatten, one could further edit the resulting form.
with flatten, everything is turned into text.
"""
from __future__ import with_statement
import os
import tempfile
@@ -58,7 +60,7 @@ trailer
%%EOF
"""
def output_field( f ):
def output_field(f):
return "\xfe\xff" + "".join( [ "\x00"+c for c in f ] )
def extract_keys(lines):
@@ -99,7 +101,7 @@ def extract_keys_from_pdf(filename):
finally:
try:
os.remove(tmp_file)
except:
except Exception:
pass # nothing to do
return extract_keys(lines)
@@ -113,7 +115,7 @@ def fill_pdf(infile, outfile, fields):
finally:
try:
os.remove(tmp_file)
except:
except Exception:
pass # nothing to do
def testfill_pdf(infile, outfile):
+6 -3
View File
@@ -54,9 +54,12 @@ _EXPR_OPCODES = _CONST_OPCODES.union(set(opmap[x] for x in [
_SAFE_OPCODES = _EXPR_OPCODES.union(set(opmap[x] for x in [
'STORE_MAP', 'LOAD_NAME', 'CALL_FUNCTION', 'COMPARE_OP', 'LOAD_ATTR',
'STORE_NAME', 'GET_ITER', 'FOR_ITER', 'LIST_APPEND', 'JUMP_ABSOLUTE',
'DELETE_NAME', 'JUMP_IF_TRUE', 'JUMP_IF_FALSE','MAKE_FUNCTION','JUMP_FORWARD',
'SLICE+0', 'SLICE+1', 'SLICE+2', 'SLICE+3'
'STORE_NAME', 'GET_ITER', 'FOR_ITER', 'LIST_APPEND', 'DELETE_NAME',
'JUMP_FORWARD', 'JUMP_IF_TRUE', 'JUMP_IF_FALSE', 'JUMP_ABSOLUTE',
'MAKE_FUNCTION', 'SLICE+0', 'SLICE+1', 'SLICE+2', 'SLICE+3',
# New in Python 2.7 - http://bugs.python.org/issue4715 :
'JUMP_IF_FALSE_OR_POP', 'JUMP_IF_TRUE_OR_POP', 'POP_JUMP_IF_FALSE',
'POP_JUMP_IF_TRUE'
] if x in opmap))
_logger = logging.getLogger('safe_eval')
+69 -40
View File
@@ -200,6 +200,23 @@ class GettextAlias(object):
_ = GettextAlias()
def quote(s):
"""Returns quoted PO term string, with special PO characters escaped"""
assert r"\n" not in s, "Translation terms may not include escaped newlines ('\\n'), please use only literal newlines! (in '%s')" % s
return '"%s"' % s.replace('\\','\\\\') \
.replace('"','\\"') \
.replace('\n', '\\n"\n"')
re_escaped_char = re.compile(r"(\\.)")
re_escaped_replacements = {'n': '\n', }
def _sub_replacement(match_obj):
return re_escaped_replacements.get(match_obj.group(1)[1], match_obj.group(1)[1])
def unquote(str):
"""Returns unquoted PO term string, with special PO characters unescaped"""
return re_escaped_char.sub(_sub_replacement, str[1:-1])
# class to handle po files
class TinyPoFile(object):
def __init__(self, buffer):
@@ -231,11 +248,6 @@ class TinyPoFile(object):
return (self.lines_count - len(self.lines))
def next(self):
def unquote(str):
return str[1:-1].replace("\\n", "\n") \
.replace("\\\\ ", "\\ ") \
.replace('\\"', '"')
type = name = res_id = source = trad = None
if self.tnrs:
@@ -337,11 +349,6 @@ class TinyPoFile(object):
)
def write(self, modules, tnrs, source, trad):
def quote(s):
return '"%s"' % s.replace('"','\\"') \
.replace('\n', '\\n"\n"') \
.replace(' \\ ',' \\\\ ')
plurial = len(modules) > 1 and 's' or ''
self.buffer.write("#. module%s: %s\n" % (plurial, ', '.join(modules)))
@@ -654,29 +661,21 @@ def trans_generate(lang, modules, dbname=None):
# parse source code for _() calls
def get_module_from_path(path, mod_paths=None):
# if not mod_paths:
## First, construct a list of possible paths
# def_path = os.path.abspath(os.path.join(tools.config['root_path'], 'addons')) # default addons path (base)
# ad_paths= map(lambda m: os.path.abspath(m.strip()),tools.config['addons_path'].split(','))
# mod_paths=[def_path]
# for adp in ad_paths:
# mod_paths.append(adp)
# if not adp.startswith('/'):
# mod_paths.append(os.path.join(def_path,adp))
# elif adp.startswith(def_path):
# mod_paths.append(adp[len(def_path)+1:])
# for mp in mod_paths:
# if path.startswith(mp) and (os.path.dirname(path) != mp):
# path = path[len(mp)+1:]
# return path.split(os.path.sep)[0]
path_dir = os.path.dirname(path[1:])
if path_dir:
if os.path.exists(os.path.join(tools.config['addons_path'],path[1:])):
return path.split(os.path.sep)[1]
else:
root_addons = os.path.join(tools.config['root_path'], 'addons')
if os.path.exists(os.path.join(root_addons,path[1:])):
return path.split(os.path.sep)[1]
if not mod_paths:
# First, construct a list of possible paths
def_path = os.path.abspath(os.path.join(tools.config['root_path'], 'addons')) # default addons path (base)
ad_paths= map(lambda m: os.path.abspath(m.strip()),tools.config['addons_path'].split(','))
mod_paths=[def_path]
for adp in ad_paths:
mod_paths.append(adp)
if not os.path.isabs(adp):
mod_paths.append(adp)
elif adp.startswith(def_path):
mod_paths.append(adp[len(def_path)+1:])
for mp in mod_paths:
if path.startswith(mp) and (os.path.dirname(path) != mp):
path = path[len(mp)+1:]
return path.split(os.path.sep)[0]
return 'base' # files that are not in a module are considered as being in 'base' module
modobj = pool.get('ir.module.module')
@@ -685,25 +684,55 @@ def trans_generate(lang, modules, dbname=None):
root_path = os.path.join(tools.config['root_path'], 'addons')
if root_path in tools.config['addons_path'] :
path_list = [root_path]
apaths = map(os.path.abspath, map(str.strip, tools.config['addons_path'].split(',')))
if root_path in apaths:
path_list = apaths
else :
path_list = [root_path,tools.config['addons_path']]
path_list = [root_path,] + apaths
logger.notifyChannel("i18n", netsvc.LOG_DEBUG, "Scanning modules at paths: %s" % (' '.join(path_list),))
mod_paths = []
join_dquotes = re.compile(r'([^\\])"[\s\\]*"', re.DOTALL)
join_quotes = re.compile(r'([^\\])\'[\s\\]*\'', re.DOTALL)
re_dquotes = re.compile(r'[^a-zA-Z0-9_]_\([\s]*"(.+?)"[\s]*?\)', re.DOTALL)
re_quotes = re.compile(r'[^a-zA-Z0-9_]_\([\s]*\'(.+?)\'[\s]*?\)', re.DOTALL)
def export_code_terms_from_file(fname, path, root, terms_type):
fabsolutepath = join(root, fname)
frelativepath = fabsolutepath[len(path):]
module = get_module_from_path(frelativepath)
module = get_module_from_path(fabsolutepath, mod_paths=mod_paths)
is_mod_installed = module in installed_modules
if (('all' in modules) or (module in modules)) and is_mod_installed:
logger.notifyChannel("i18n", netsvc.LOG_DEBUG, "Scanning code of %s at module: %s" % (frelativepath, module))
code_string = tools.file_open(fabsolutepath, subdir='').read()
iter = re.finditer('[^a-zA-Z0-9_]_\([\s]*["\'](.+?)["\'][\s]*\)', code_string, re.S)
if module in installed_modules:
frelativepath = str("addons" + frelativepath)
for i in iter:
push_translation(module, terms_type, frelativepath, 0, encode(i.group(1)))
ite = re_dquotes.finditer(code_string)
for i in ite:
src = i.group(1)
if src.startswith('""'):
assert src.endswith('""'), "Incorrect usage of _(..) function (should contain only literal strings!) in file %s near: %s" % (frelativepath, src[:30])
src = src[2:-2]
else:
src = join_dquotes.sub(r'\1', src)
# now, since we did a binary read of a python source file, we
# have to expand pythonic escapes like the interpreter does.
src = src.decode('string_escape')
push_translation(module, terms_type, frelativepath, 0, encode(src))
ite = re_quotes.finditer(code_string)
for i in ite:
src = i.group(1)
if src.startswith("''"):
assert src.endswith("''"), "Incorrect usage of _(..) function (should contain only literal strings!) in file %s near: %s" % (frelativepath, src[:30])
src = src[2:-2]
else:
src = join_quotes.sub(r'\1', src)
src = src.decode('string_escape')
push_translation(module, terms_type, frelativepath, 0, encode(src))
for path in path_list:
logger.notifyChannel("i18n", netsvc.LOG_DEBUG, "Scanning files of modules at %s" % path)
for root, dummy, files in tools.osutil.walksymlinks(path):
for fname in itertools.chain(fnmatch.filter(files, '*.py')):
export_code_terms_from_file(fname, path, root, 'code')
+7 -5
View File
@@ -8,20 +8,20 @@ msgstr ""
"Project-Id-Version: openobject-server\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2009-08-24 22:41+0300\n"
"PO-Revision-Date: 2010-07-21 07:32+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"PO-Revision-Date: 2010-11-15 08:27+0000\n"
"Last-Translator: OpenERP Administrators <Unknown>\n"
"Language-Team: Serbian <sr@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-09-29 04:47+0000\n"
"X-Launchpad-Export-Date: 2010-11-16 05:05+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. Type: string
#. Description
#: ../openerp-server.templates:1001
msgid "Dedicated system account for the Open ERP server:"
msgstr ""
msgstr "Namenski sistem naloga za OpenERP Server:"
#. Type: string
#. Description
@@ -31,9 +31,11 @@ msgid ""
"the system's security is not compromised by running it with superuser "
"privileges."
msgstr ""
"OpenERP server mora koristiti namenski nalog ya svoje operacije tako da "
"sigurnosni sistem nije kompromitovan pri radu sa superUser privilegijama."
#. Type: string
#. Description
#: ../openerp-server.templates:1001
msgid "Please choose that account's username."
msgstr ""
msgstr "Molim vas izaberite korisničko ime naloga."