[MERGE] merged lp:~openerp/openobject-server/trunk/
bzr revid: hmo@tinyerp.com-20100531155256-5zcd5g9p910ffujy
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2010 OpenERP s.a. (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
@@ -716,14 +717,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs):
|
||||
for kind in ('init', 'update'):
|
||||
if package.state=='to upgrade':
|
||||
# upgrading the module information
|
||||
modobj.write(cr, 1, [mid], {
|
||||
'description': package.data.get('description', ''),
|
||||
'shortdesc': package.data.get('name', ''),
|
||||
'author': package.data.get('author', 'Unknown'),
|
||||
'website': package.data.get('website', ''),
|
||||
'license': package.data.get('license', 'GPL-2'),
|
||||
'certificate': package.data.get('certificate') or None,
|
||||
})
|
||||
modobj.write(cr, 1, [mid], modobj.get_values_from_terp(package.data))
|
||||
load_init_update_xml(cr, m, idref, mode, kind)
|
||||
load_data(cr, m, idref, mode)
|
||||
if hasattr(package, 'demo') or (package.dbdemo and package.state != 'installed'):
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2010 OpenERP s.a. (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
@@ -25,7 +26,8 @@
|
||||
'version': '1.2',
|
||||
'category': 'Generic Modules/Base',
|
||||
'description': """The kernel of OpenERP, needed for all installation.""",
|
||||
'author': 'Tiny',
|
||||
'author': 'OpenERP s.a.',
|
||||
'maintainer': 'OpenERP s.a.',
|
||||
'website': 'http://www.openerp.com',
|
||||
'depends': [],
|
||||
'init_xml': [
|
||||
@@ -67,7 +69,16 @@
|
||||
'security/ir.model.access.csv'
|
||||
|
||||
],
|
||||
'demo_xml': ['base_demo.xml', 'res/partner/partner_demo.xml', 'res/partner/crm_demo.xml','test/base_test.xml'],
|
||||
'demo_xml': [
|
||||
'base_demo.xml',
|
||||
'res/partner/partner_demo.xml',
|
||||
'res/partner/crm_demo.xml',
|
||||
],
|
||||
'test': [
|
||||
'test/base_test.xml',
|
||||
'test/test_context.xml',
|
||||
'bug_lp541545.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'active': True,
|
||||
'certificate': '0076807797149',
|
||||
|
||||
@@ -1293,7 +1293,18 @@
|
||||
<field name="currency_id" ref="INR"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="rateINR2001" model="res.currency.rate">
|
||||
<field name="rate">0.631</field>
|
||||
<field name="currency_id" ref="INR"/>
|
||||
<field name="name">2001-01-01</field>
|
||||
</record>
|
||||
<record id="rateINR2002" model="res.currency.rate">
|
||||
<field name="rate">0.632</field>
|
||||
<field name="currency_id" ref="INR"/>
|
||||
<field name="name">2002-01-01</field>
|
||||
</record>
|
||||
|
||||
<record id="AUD" model="res.currency">
|
||||
<field name="name">AUD</field>
|
||||
<field name="code">AUD</field>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-05-29 04:20+0000\n"
|
||||
"PO-Revision-Date: 2010-05-30 04:12+0000\n"
|
||||
"Last-Translator: goranc <goranc@gmail.com>\n"
|
||||
"Language-Team: openerp-translators\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-30 03:44+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-31 03:46+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
"Language: hr\n"
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@ msgstr ""
|
||||
"Project-Id-Version: openobject-server\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-05-29 04:21+0000\n"
|
||||
"PO-Revision-Date: 2010-05-30 04:11+0000\n"
|
||||
"Last-Translator: Harry (Open ERP) <hmo@tinyerp.com>\n"
|
||||
"Language-Team: Japanese <ja@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-05-30 03:43+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-31 03:46+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
||||
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.0\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-05-29 04:18+0000\n"
|
||||
"PO-Revision-Date: 2010-05-30 04:09+0000\n"
|
||||
"Last-Translator: Anders Wallenquist <anders.wallenquist@vertel.se>\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-05-30 03:44+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-31 03:46+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
||||
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.0\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-05-29 04:19+0000\n"
|
||||
"PO-Revision-Date: 2010-05-30 04:13+0000\n"
|
||||
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.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-05-30 03:44+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-31 03:46+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
||||
@@ -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: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-05-29 04:22+0000\n"
|
||||
"PO-Revision-Date: 2010-05-30 04:11+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-05-30 03:44+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-31 03:47+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
||||
@@ -77,14 +77,14 @@ class ir_ui_menu(osv.osv):
|
||||
ids = super(ir_ui_menu, self).search(cr, uid, args, super_offset,
|
||||
super_limit, order,
|
||||
context=context, count=super_count)
|
||||
if uid == 1 or count:
|
||||
if uid == 1:
|
||||
return ids
|
||||
|
||||
if not ids:
|
||||
if count:
|
||||
return 0
|
||||
return []
|
||||
|
||||
|
||||
|
||||
modelaccess = self.pool.get('ir.model.access')
|
||||
user_groups = set(self.pool.get('res.users').read(cr, 1, uid, ['groups_id'])['groups_id'])
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2010 OpenERP s.a. (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
@@ -23,6 +24,7 @@ import tarfile
|
||||
import re
|
||||
import urllib
|
||||
import os
|
||||
import imp
|
||||
import tools
|
||||
from osv import fields, osv, orm
|
||||
import zipfile
|
||||
@@ -122,6 +124,8 @@ class module(osv.osv):
|
||||
'shortdesc': fields.char('Short Description', size=256, readonly=True, translate=True),
|
||||
'description': fields.text("Description", readonly=True, translate=True),
|
||||
'author': fields.char("Author", size=128, readonly=True),
|
||||
'maintainer': fields.char('Maintainer', size=128, readonly=True),
|
||||
'contributors': fields.text('Contributors', readonly=True),
|
||||
'website': fields.char("Website", size=256, readonly=True),
|
||||
|
||||
# attention: Incorrect field names !!
|
||||
@@ -191,6 +195,27 @@ class module(osv.osv):
|
||||
|
||||
return super(module, self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
@staticmethod
|
||||
def _check_external_dependencies(terp):
|
||||
depends = terp.get('external_dependencies')
|
||||
if not depends:
|
||||
return
|
||||
for pydep in depends.get('python', []):
|
||||
parts = pydep.split('.')
|
||||
parts.reverse()
|
||||
path = None
|
||||
while parts:
|
||||
part = parts.pop()
|
||||
try:
|
||||
f, path, descr = imp.find_module(part, path and [path] or None)
|
||||
except ImportError:
|
||||
raise ImportError('No module named %s' % (pydep,))
|
||||
|
||||
for binary in depends.get('bin', []):
|
||||
if tools.find_in_path(binary) is None:
|
||||
raise Exception('Unable to find %r in path' % (binary,))
|
||||
|
||||
|
||||
def state_update(self, cr, uid, ids, newstate, states_to_update, context={}, level=100):
|
||||
if level<1:
|
||||
raise orm.except_orm(_('Error'), _('Recursion error in modules dependencies !'))
|
||||
@@ -206,6 +231,11 @@ class module(osv.osv):
|
||||
else:
|
||||
od = self.browse(cr, uid, ids2)[0]
|
||||
mdemo = od.demo or mdemo
|
||||
terp = self.get_module_info(module.name)
|
||||
try:
|
||||
self._check_external_dependencies(terp)
|
||||
except Exception, e:
|
||||
raise orm.except_orm(_('Error'), _('Unable %s the module "%s" because an external dependencie is not met: %s' % (newstate, module.name, e.args[0])))
|
||||
if not module.dependencies_id:
|
||||
mdemo = module.demo
|
||||
if module.state in states_to_update:
|
||||
@@ -279,6 +309,19 @@ class module(osv.osv):
|
||||
self.update_translations(cr, uid, ids)
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def get_values_from_terp(terp):
|
||||
return {
|
||||
'description': terp.get('description', ''),
|
||||
'shortdesc': terp.get('name', ''),
|
||||
'author': terp.get('author', 'Unknown'),
|
||||
'maintainer': terp.get('maintainer', False),
|
||||
'contributors': ', '.join(terp.get('contributors', [])) or False,
|
||||
'website': terp.get('website', ''),
|
||||
'license': terp.get('license', 'GPL-2'),
|
||||
'certificate': terp.get('certificate') or None,
|
||||
}
|
||||
|
||||
# update the list of available packages
|
||||
def update_list(self, cr, uid, context={}):
|
||||
res = [0, 0] # [update, add]
|
||||
@@ -286,46 +329,31 @@ class module(osv.osv):
|
||||
# iterate through installed modules and mark them as being so
|
||||
for mod_name in addons.get_modules():
|
||||
ids = self.search(cr, uid, [('name','=',mod_name)])
|
||||
|
||||
terp = self.get_module_info(mod_name)
|
||||
values = self.get_values_from_terp(terp)
|
||||
|
||||
if ids:
|
||||
id = ids[0]
|
||||
mod = self.browse(cr, uid, id)
|
||||
terp = self.get_module_info(mod_name)
|
||||
if terp.get('installable', True) and mod.state == 'uninstallable':
|
||||
self.write(cr, uid, id, {'state': 'uninstalled'})
|
||||
if parse_version(terp.get('version', '')) > parse_version(mod.latest_version or ''):
|
||||
self.write(cr, uid, id, { 'url': ''})
|
||||
res[0] += 1
|
||||
self.write(cr, uid, id, {
|
||||
'description': terp.get('description', ''),
|
||||
'shortdesc': terp.get('name', ''),
|
||||
'author': terp.get('author', 'Unknown'),
|
||||
'website': terp.get('website', ''),
|
||||
'license': terp.get('license', 'GPL-2'),
|
||||
'certificate': terp.get('certificate') or None,
|
||||
})
|
||||
self.write(cr, uid, id, values)
|
||||
cr.execute('DELETE FROM ir_module_module_dependency WHERE module_id = %s', (id,))
|
||||
self._update_dependencies(cr, uid, ids[0], terp.get('depends', []))
|
||||
self._update_category(cr, uid, ids[0], terp.get('category', 'Uncategorized'))
|
||||
continue
|
||||
mod_path = addons.get_module_path(mod_name)
|
||||
if mod_path:
|
||||
terp = self.get_module_info(mod_name)
|
||||
else:
|
||||
mod_path = addons.get_module_path(mod_name)
|
||||
if not mod_path:
|
||||
continue
|
||||
if not terp or not terp.get('installable', True):
|
||||
continue
|
||||
|
||||
id = self.create(cr, uid, {
|
||||
'name': mod_name,
|
||||
'state': 'uninstalled',
|
||||
'description': terp.get('description', ''),
|
||||
'shortdesc': terp.get('name', ''),
|
||||
'author': terp.get('author', 'Unknown'),
|
||||
'website': terp.get('website', ''),
|
||||
'license': terp.get('license', 'GPL-2'),
|
||||
'certificate': terp.get('certificate') or None,
|
||||
})
|
||||
id = self.create(cr, uid, dict(name=mod_name, state='uninstalled', **values))
|
||||
res[1] += 1
|
||||
self._update_dependencies(cr, uid, id, terp.get('depends', []))
|
||||
self._update_category(cr, uid, id, terp.get('category', 'Uncategorized'))
|
||||
self._update_dependencies(cr, uid, id, terp.get('depends', []))
|
||||
self._update_category(cr, uid, id, terp.get('category', 'Uncategorized'))
|
||||
|
||||
return res
|
||||
|
||||
@@ -352,14 +380,7 @@ class module(osv.osv):
|
||||
except Exception, e:
|
||||
raise orm.except_orm(_('Error'), _('Can not create the module file:\n %s') % (fname,))
|
||||
terp = self.get_module_info(mod.name)
|
||||
self.write(cr, uid, mod.id, {
|
||||
'description': terp.get('description', ''),
|
||||
'shortdesc': terp.get('name', ''),
|
||||
'author': terp.get('author', 'Unknown'),
|
||||
'website': terp.get('website', ''),
|
||||
'license': terp.get('license', 'GPL-2'),
|
||||
'certificate': terp.get('certificate') or None,
|
||||
})
|
||||
self.write(cr, uid, mod.id, self.get_values_from_terp(terp))
|
||||
cr.execute('DELETE FROM ir_module_module_dependency ' \
|
||||
'WHERE module_id = %s', (mod.id,))
|
||||
self._update_dependencies(cr, uid, mod.id, terp.get('depends',
|
||||
|
||||
@@ -97,7 +97,9 @@
|
||||
<field name="latest_version"/>
|
||||
<field name="author" select="2"/>
|
||||
<field name="website" select="2" widget="url"/>
|
||||
<field name="maintainer" attrs="{'invisible': [('maintainer', '=', False)]}"/>
|
||||
<field name="url" widget="url"/>
|
||||
<field name="contributors" widget="char" attrs="{'invisible': [('contributors', '=', False)]}"/>
|
||||
<field name="published_version"/>
|
||||
<field name="license"/>
|
||||
<field name="demo" readonly="1"/>
|
||||
@@ -141,6 +143,8 @@
|
||||
<field name="name"/>
|
||||
<field name="shortdesc"/>
|
||||
<field name="author"/>
|
||||
<field name='maintainer'/>
|
||||
<field name='contributors'/>
|
||||
<field name="installed_version"/>
|
||||
<field name="latest_version"/>
|
||||
<field name="published_version"/>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2010 OpenERP s.a. (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
@@ -56,7 +57,7 @@ class wizard_install_module(wizard.interface):
|
||||
terp = mod_obj.get_module_info(module)
|
||||
if not terp.get('installable', True):
|
||||
continue
|
||||
|
||||
|
||||
# XXX check if this code is correct...
|
||||
fm = imp.find_module(module)
|
||||
try:
|
||||
@@ -65,12 +66,8 @@ class wizard_install_module(wizard.interface):
|
||||
if fm[0]:
|
||||
fm[0].close()
|
||||
|
||||
mod_id = mod_obj.create(cr, uid, {
|
||||
'name': module,
|
||||
'state': 'uninstalled',
|
||||
'description': terp.get('description', ''),
|
||||
'shortdesc': terp.get('name', ''),
|
||||
'author': terp.get('author', 'Unknown')})
|
||||
values = mod_obj.get_values_from_terp(terp)
|
||||
mod_id = mod_obj.create(cr, uid, dict(name=module, state='uninstalled', **values))
|
||||
dependencies = terp.get('depends', [])
|
||||
for d in dependencies:
|
||||
cr.execute('insert into ir_module_module_dependency (module_id,name) values (%s, %s)', (mod_id, d))
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<!-- Test count attribute for assertions -->
|
||||
<data>
|
||||
<assert
|
||||
model="res.currency.rate"
|
||||
search="[('currency_id', '=', ref('INR'))]"
|
||||
count="3"
|
||||
string="Rate entries for Indian rupee">
|
||||
<test expr="True"/>
|
||||
</assert>
|
||||
</data>
|
||||
|
||||
</openerp>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<!-- Test context attribute for unit tests -->
|
||||
<data context="{'date': '2001-06-01'}">
|
||||
<assert
|
||||
model="res.currency"
|
||||
id="INR"
|
||||
string="Indian rupee rate in 2001">
|
||||
<!-- date specified in data element's context -->
|
||||
<test expr="str(rate)">0.631</test>
|
||||
</assert>
|
||||
<assert
|
||||
model="res.currency"
|
||||
id="INR"
|
||||
string="Indian rupee rate in 2002"
|
||||
context="{'date': '2002-06-01'}">
|
||||
<test expr="str(rate)">0.632</test>
|
||||
</assert>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -32,6 +32,7 @@
|
||||
<rng:attribute name="name" />
|
||||
<rng:optional><rng:attribute name="id" /></rng:optional>
|
||||
<rng:optional><rng:attribute name="eval" /></rng:optional>
|
||||
<rng:optional><rng:attribute name="context" /></rng:optional>
|
||||
<rng:choice>
|
||||
<rng:empty />
|
||||
<rng:oneOrMore>
|
||||
@@ -51,6 +52,7 @@
|
||||
<rng:optional><rng:attribute name="count" /></rng:optional>
|
||||
<rng:optional><rng:attribute name="string" /></rng:optional>
|
||||
<rng:optional><rng:attribute name="id" /></rng:optional>
|
||||
<rng:optional><rng:attribute name="context" /></rng:optional>
|
||||
<rng:optional><rng:attribute name="severity" /></rng:optional>
|
||||
<rng:zeroOrMore>
|
||||
<rng:element name="test">
|
||||
@@ -70,6 +72,7 @@
|
||||
<rng:optional><rng:attribute name="ref" /></rng:optional>
|
||||
<rng:attribute name="action"/>
|
||||
<rng:optional><rng:attribute name="uid"/></rng:optional>
|
||||
<rng:optional><rng:attribute name="context" /></rng:optional>
|
||||
<rng:choice>
|
||||
<rng:empty/>
|
||||
<rng:ref name="value"/>
|
||||
@@ -205,6 +208,7 @@
|
||||
<rng:define name="data">
|
||||
<rng:element name="data">
|
||||
<rng:optional><rng:attribute name="noupdate" /></rng:optional>
|
||||
<rng:optional><rng:attribute name="context" /></rng:optional>
|
||||
<rng:zeroOrMore>
|
||||
<rng:choice>
|
||||
<rng:text/>
|
||||
|
||||
+10
-10
@@ -71,7 +71,8 @@ class expression(object):
|
||||
if not reduce(lambda acc, val: acc and (self._is_operator(val) or self._is_leaf(val)), exp, True):
|
||||
raise ValueError('Bad domain expression: %r' % (exp,))
|
||||
self.__exp = exp
|
||||
self.__tables = {} # used to store the table to use for the sql generation. key = index of the leaf
|
||||
self.__field_tables = {} # used to store the table to use for the sql generation. key = index of the leaf
|
||||
self.__all_tables = set()
|
||||
self.__joins = []
|
||||
self.__main_table = None # 'root' table. set by parse()
|
||||
self.__DUMMY_LEAF = (1, '=', 1) # a dummy leaf that must not be parsed or sql generated
|
||||
@@ -103,6 +104,7 @@ class expression(object):
|
||||
return [(left, 'in', rg(ids, table, parent or table._parent_name))]
|
||||
|
||||
self.__main_table = table
|
||||
self.__all_tables.add(table)
|
||||
|
||||
i = -1
|
||||
while i + 1<len(self.__exp):
|
||||
@@ -114,19 +116,17 @@ class expression(object):
|
||||
working_table = table
|
||||
main_table = table
|
||||
fargs = left.split('.', 1)
|
||||
index = i
|
||||
if fargs[0] in table._inherit_fields:
|
||||
while True:
|
||||
field = main_table._columns.get(fargs[0], False)
|
||||
if field:
|
||||
working_table = main_table
|
||||
self.__tables[i] = working_table
|
||||
self.__field_tables[i] = working_table
|
||||
break
|
||||
working_table = main_table.pool.get(main_table._inherit_fields[fargs[0]][0])
|
||||
if working_table not in self.__tables.values():
|
||||
self.__joins.append(('%s.%s=%s.%s' % (working_table._table, 'id', main_table._table, main_table._inherits[working_table._name]), working_table._table))
|
||||
self.__tables[index] = working_table
|
||||
index += 1
|
||||
if working_table not in self.__all_tables:
|
||||
self.__joins.append('%s.%s=%s.%s' % (working_table._table, 'id', main_table._table, main_table._inherits[working_table._name]))
|
||||
self.__all_tables.add(working_table)
|
||||
main_table = working_table
|
||||
|
||||
field = working_table._columns.get(fargs[0], False)
|
||||
@@ -433,7 +433,7 @@ class expression(object):
|
||||
params = []
|
||||
for i, e in reverse_enumerate(self.__exp):
|
||||
if self._is_leaf(e, internal=True):
|
||||
table = self.__tables.get(i, self.__main_table)
|
||||
table = self.__field_tables.get(i, self.__main_table)
|
||||
q, p = self.__leaf_to_sql(e, table)
|
||||
params.insert(0, p)
|
||||
stack.append(q)
|
||||
@@ -447,13 +447,13 @@ class expression(object):
|
||||
stack.append('(%s %s %s)' % (q1, ops[e], q2,))
|
||||
|
||||
query = ' AND '.join(reversed(stack))
|
||||
joins = ' AND '.join(map(lambda j: j[0], self.__joins))
|
||||
joins = ' AND '.join(self.__joins)
|
||||
if joins:
|
||||
query = '(%s) AND (%s)' % (joins, query)
|
||||
return (query, flatten(params))
|
||||
|
||||
def get_tables(self):
|
||||
return ['"%s"' % t._table for t in set(self.__tables.values()+[self.__main_table])]
|
||||
return ['"%s"' % t._table for t in self.__all_tables]
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
||||
+12
-14
@@ -3,6 +3,7 @@
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2010 OpenERP s.a. (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
@@ -34,6 +35,7 @@ import socket
|
||||
import re
|
||||
from itertools import islice
|
||||
import threading
|
||||
from which import which
|
||||
|
||||
|
||||
if sys.version_info[:2] < (2, 4):
|
||||
@@ -112,23 +114,19 @@ def init_db(cr):
|
||||
cr.commit()
|
||||
|
||||
def find_in_path(name):
|
||||
if os.name == "nt":
|
||||
sep = ';'
|
||||
else:
|
||||
sep = ':'
|
||||
path = [dir for dir in os.environ['PATH'].split(sep)
|
||||
if os.path.isdir(dir)]
|
||||
for dir in path:
|
||||
val = os.path.join(dir, name)
|
||||
if os.path.isfile(val) or os.path.islink(val):
|
||||
return val
|
||||
return None
|
||||
try:
|
||||
return which(name)
|
||||
except IOError:
|
||||
return None
|
||||
|
||||
def find_pg_tool(name):
|
||||
path = None
|
||||
if config['pg_path'] and config['pg_path'] != 'None':
|
||||
return os.path.join(config['pg_path'], name)
|
||||
else:
|
||||
return find_in_path(name)
|
||||
path = config['pg_path']
|
||||
try:
|
||||
return which(name, path=path)
|
||||
except IOError:
|
||||
return None
|
||||
|
||||
def exec_pg_command(name, *args):
|
||||
prog = find_pg_tool(name)
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env python
|
||||
""" Which - locate a command
|
||||
|
||||
* adapted from Brian Curtin's http://bugs.python.org/file15381/shutil_which.patch
|
||||
* see http://bugs.python.org/issue444582
|
||||
* uses ``PATHEXT`` on Windows
|
||||
* searches current directory before ``PATH`` on Windows,
|
||||
but not before an explicitly passed path
|
||||
* accepts both string or iterable for an explicitly passed path, or pathext
|
||||
* accepts an explicitly passed empty path, or pathext (either '' or [])
|
||||
* does not search ``PATH`` for files that have a path specified in their name already
|
||||
* moved defpath and defpathext lists initialization to module level,
|
||||
instead of initializing them on each function call
|
||||
* changed interface: which_files() returns generator, which() returns first match,
|
||||
or raises IOError(errno.ENOENT)
|
||||
|
||||
.. function:: which_files(file [, mode=os.F_OK | os.X_OK[, path=None[, pathext=None]]])
|
||||
|
||||
Return a generator which yields full paths in which the *file* name exists
|
||||
in a directory that is part of the file name, or on *path*,
|
||||
and has the given *mode*.
|
||||
By default, *mode* matches an inclusive OR of os.F_OK and os.X_OK
|
||||
- an existing executable file.
|
||||
The *path* is, by default, the ``PATH`` variable on the platform,
|
||||
or the string/iterable passed in as *path*.
|
||||
In the event that a ``PATH`` variable is not found, :const:`os.defpath` is used.
|
||||
On Windows, a current directory is searched before using the ``PATH`` variable,
|
||||
but not before an explicitly passed *path*.
|
||||
The *pathext* is only used on Windows to match files with given extensions appended as well.
|
||||
It defaults to the ``PATHEXT`` variable, or the string/iterable passed in as *pathext*.
|
||||
In the event that a ``PATHEXT`` variable is not found,
|
||||
default value for Windows XP/Vista is used.
|
||||
The command is always searched without extension first,
|
||||
even when *pathext* is explicitly passed.
|
||||
|
||||
.. function:: which(file [, mode=os.F_OK | os.X_OK[, path=None[, pathext=None]]])
|
||||
Return first match generated by which_files(file, mode, path, pathext),
|
||||
or raise IOError(errno.ENOENT).
|
||||
|
||||
"""
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__all__ = 'which which_files pathsep defpath defpathext F_OK R_OK W_OK X_OK'.split()
|
||||
|
||||
import sys
|
||||
from os import access, defpath, pathsep, environ, F_OK, R_OK, W_OK, X_OK
|
||||
from os.path import exists, dirname, split, join
|
||||
|
||||
windows = sys.platform.startswith('win')
|
||||
|
||||
defpath = environ.get('PATH', defpath).split(pathsep)
|
||||
|
||||
if windows:
|
||||
defpath.insert(0, '.') # can insert without checking, when duplicates are removed
|
||||
# given the quite usual mess in PATH on Windows, let's rather remove duplicates
|
||||
seen = set()
|
||||
defpath = [dir for dir in defpath if dir.lower() not in seen and not seen.add(dir.lower())]
|
||||
del seen
|
||||
|
||||
defpathext = [''] + environ.get('PATHEXT',
|
||||
'.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC').lower().split(pathsep)
|
||||
else:
|
||||
defpathext = ['']
|
||||
|
||||
def which_files(file, mode=F_OK | X_OK, path=None, pathext=None):
|
||||
""" Locate a file in a path supplied as a part of the file name,
|
||||
or the user's path, or a supplied path.
|
||||
The function yields full paths (not necessarily absolute paths),
|
||||
in which the given file name matches an existing file in a directory on the path.
|
||||
|
||||
>>> def test_which(expected, *args, **argd):
|
||||
... result = list(which_files(*args, **argd))
|
||||
... assert result == expected, 'which_files: %s != %s' % (result, expected)
|
||||
...
|
||||
... try:
|
||||
... result = [ which(*args, **argd) ]
|
||||
... except IOError:
|
||||
... result = []
|
||||
... assert result[:1] == expected[:1], 'which: %s != %s' % (result[:1], expected[:1])
|
||||
|
||||
>>> if windows: cmd = environ['COMSPEC']
|
||||
>>> if windows: test_which([cmd], 'cmd')
|
||||
>>> if windows: test_which([cmd], 'cmd.exe')
|
||||
>>> if windows: test_which([cmd], 'cmd', path=dirname(cmd))
|
||||
>>> if windows: test_which([cmd], 'cmd', pathext='.exe')
|
||||
>>> if windows: test_which([cmd], cmd)
|
||||
>>> if windows: test_which([cmd], cmd, path='<nonexistent>')
|
||||
>>> if windows: test_which([cmd], cmd, pathext='<nonexistent>')
|
||||
>>> if windows: test_which([cmd], cmd[:-4])
|
||||
>>> if windows: test_which([cmd], cmd[:-4], path='<nonexistent>')
|
||||
|
||||
>>> if windows: test_which([], 'cmd', path='<nonexistent>')
|
||||
>>> if windows: test_which([], 'cmd', pathext='<nonexistent>')
|
||||
>>> if windows: test_which([], '<nonexistent>/cmd')
|
||||
>>> if windows: test_which([], cmd[:-4], pathext='<nonexistent>')
|
||||
|
||||
>>> if not windows: sh = '/bin/sh'
|
||||
>>> if not windows: test_which([sh], 'sh')
|
||||
>>> if not windows: test_which([sh], 'sh', path=dirname(sh))
|
||||
>>> if not windows: test_which([sh], 'sh', pathext='<nonexistent>')
|
||||
>>> if not windows: test_which([sh], sh)
|
||||
>>> if not windows: test_which([sh], sh, path='<nonexistent>')
|
||||
>>> if not windows: test_which([sh], sh, pathext='<nonexistent>')
|
||||
|
||||
>>> if not windows: test_which([], 'sh', mode=W_OK) # not running as root, are you?
|
||||
>>> if not windows: test_which([], 'sh', path='<nonexistent>')
|
||||
>>> if not windows: test_which([], '<nonexistent>/sh')
|
||||
"""
|
||||
filepath, file = split(file)
|
||||
|
||||
if filepath:
|
||||
path = (filepath,)
|
||||
elif path is None:
|
||||
path = defpath
|
||||
elif isinstance(path, str):
|
||||
path = path.split(pathsep)
|
||||
|
||||
if pathext is None:
|
||||
pathext = defpathext
|
||||
elif isinstance(pathext, str):
|
||||
pathext = pathext.split(pathsep)
|
||||
|
||||
if not '' in pathext:
|
||||
pathext.insert(0, '') # always check command without extension, even for custom pathext
|
||||
|
||||
for dir in path:
|
||||
basepath = join(dir, file)
|
||||
for ext in pathext:
|
||||
fullpath = basepath + ext
|
||||
if exists(fullpath) and access(fullpath, mode):
|
||||
yield fullpath
|
||||
|
||||
def which(file, mode=F_OK | X_OK, path=None, pathext=None):
|
||||
""" Locate a file in a path supplied as a part of the file name,
|
||||
or the user's path, or a supplied path.
|
||||
The function returns full path (not necessarily absolute path),
|
||||
in which the given file name matches an existing file in a directory on the path,
|
||||
or raises IOError(errno.ENOENT).
|
||||
|
||||
>>> # for doctest see which_files()
|
||||
"""
|
||||
try:
|
||||
return iter(which_files(file, mode, path, pathext)).next()
|
||||
except StopIteration:
|
||||
try:
|
||||
from errno import ENOENT
|
||||
except ImportError:
|
||||
ENOENT = 2
|
||||
raise IOError(ENOENT, '%s not found' % (mode & X_OK and 'command' or 'file'), file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
Reference in New Issue
Block a user