diff options
| author | Vo Minh Thu <vmt@openerp.com> | 2011-02-07 13:57:23 +0100 |
|---|---|---|
| committer | Vo Minh Thu <vmt@openerp.com> | 2011-02-07 13:57:23 +0100 |
| commit | f8572e5c602798f37c2a94d54ab5e3ac79ff0185 (patch) | |
| tree | 35687977b932ac91bd31fece229ab78cc70926f5 /bin/addons/base/module/module.py | |
| parent | 9c287abc143a7b187635c75751a29baeefa58c15 (diff) | |
[IMP] openerp python module.
- Some logging code moved from netsvc.py to loglevels.py
- Changed imports to use the new openerp module
- config and netsvc initialization calls move to openerp-server.py
- Moved openerp-server.py outside the old bin directory
- Some imports in tools moved inside the methods to break mutual-dependencies
bzr revid: vmt@openerp.com-20110207125723-ooee7d7ng5elmkso
Diffstat (limited to 'bin/addons/base/module/module.py')
| -rw-r--r-- | bin/addons/base/module/module.py | 673 |
1 files changed, 0 insertions, 673 deletions
diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py deleted file mode 100644 index 2e276433e63..00000000000 --- a/bin/addons/base/module/module.py +++ /dev/null @@ -1,673 +0,0 @@ -# -*- 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 -# 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 base64 -import cStringIO -import imp -import logging -import os -import re -import StringIO -import urllib -import zipfile -import zipimport - -import addons -import pooler -import release -import tools - -from tools.parse_version import parse_version -from tools.translate import _ - -from osv import fields, osv, orm - -class module_category(osv.osv): - _name = "ir.module.category" - _description = "Module Category" - - def _module_nbr(self,cr,uid, ids, prop, unknow_none, context): - cr.execute('SELECT category_id, COUNT(*) \ - FROM ir_module_module \ - WHERE category_id IN %(ids)s \ - OR category_id IN (SELECT id \ - FROM ir_module_category \ - WHERE parent_id IN %(ids)s) \ - GROUP BY category_id', {'ids': tuple(ids)} - ) - result = dict(cr.fetchall()) - for id in ids: - cr.execute('select id from ir_module_category where parent_id=%s', (id,)) - result[id] = sum([result.get(c, 0) for (c,) in cr.fetchall()], - result.get(id, 0)) - return result - - _columns = { - 'name': fields.char("Name", size=128, required=True, select=True), - 'parent_id': fields.many2one('ir.module.category', 'Parent Category', select=True), - 'child_ids': fields.one2many('ir.module.category', 'parent_id', 'Child Categories'), - 'module_nr': fields.function(_module_nbr, method=True, string='Number of Modules', type='integer') - } - _order = 'name' -module_category() - -class module(osv.osv): - _name = "ir.module.module" - _description = "Module" - __logger = logging.getLogger('base.' + _name) - - @classmethod - def get_module_info(cls, name): - info = {} - try: - info = addons.load_information_from_description_file(name) - if 'version' in info: - info['version'] = release.major_version + '.' + info['version'] - except Exception: - cls.__logger.debug('Error when trying to fetch informations for ' - 'module %s', name, exc_info=True) - return info - - def _get_latest_version(self, cr, uid, ids, field_name=None, arg=None, context=None): - res = dict.fromkeys(ids, '') - for m in self.browse(cr, uid, ids): - res[m.id] = self.get_module_info(m.name).get('version', '') - return res - - def _get_views(self, cr, uid, ids, field_name=None, arg=None, context=None): - res = {} - model_data_obj = self.pool.get('ir.model.data') - view_obj = self.pool.get('ir.ui.view') - report_obj = self.pool.get('ir.actions.report.xml') - menu_obj = self.pool.get('ir.ui.menu') - mlist = self.browse(cr, uid, ids, context=context) - mnames = {} - for m in mlist: - # skip uninstalled modules below, - # no data to find anyway - if m.state in ('installed', 'to upgrade', 'to remove'): - mnames[m.name] = m.id - res[m.id] = { - 'menus_by_module':[], - 'reports_by_module':[], - 'views_by_module': [] - } - - if not mnames: - return res - - view_id = model_data_obj.search(cr,uid,[('module','in', mnames.keys()), - ('model','in',('ir.ui.view','ir.actions.report.xml','ir.ui.menu'))]) - for data_id in model_data_obj.browse(cr,uid,view_id,context): - # We use try except, because views or menus may not exist - try: - key = data_id.model - res_mod_dic = res[mnames[data_id.module]] - if key=='ir.ui.view': - v = view_obj.browse(cr,uid,data_id.res_id) - aa = v.inherit_id and '* INHERIT ' or '' - res_mod_dic['views_by_module'].append(aa + v.name + '('+v.type+')') - elif key=='ir.actions.report.xml': - res_mod_dic['reports_by_module'].append(report_obj.browse(cr,uid,data_id.res_id).name) - elif key=='ir.ui.menu': - res_mod_dic['menus_by_module'].append(menu_obj.browse(cr,uid,data_id.res_id).complete_name) - except KeyError, e: - self.__logger.warning( - 'Data not found for reference %s[%s:%s.%s]', data_id.model, - data_id.res_id, data_id.model, data_id.name, exc_info=True) - pass - except Exception, e: - self.__logger.warning('Unknown error while browsing %s[%s]', - data_id.model, data_id.res_id, exc_info=True) - pass - for key, value in res.iteritems(): - for k, v in res[key].iteritems() : - res[key][k] = "\n".join(sorted(v)) - return res - - _columns = { - 'name': fields.char("Name", size=128, readonly=True, required=True, select=True), - 'category_id': fields.many2one('ir.module.category', 'Category', readonly=True, select=True), - '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 !! - # installed_version refer the latest version (the one on disk) - # latest_version refer the installed version (the one in database) - # published_version refer the version available on the repository - 'installed_version': fields.function(_get_latest_version, method=True, - string='Latest version', type='char'), - 'latest_version': fields.char('Installed version', size=64, readonly=True), - 'published_version': fields.char('Published Version', size=64, readonly=True), - - 'url': fields.char('URL', size=128, readonly=True), - 'dependencies_id': fields.one2many('ir.module.module.dependency', - 'module_id', 'Dependencies', readonly=True), - 'state': fields.selection([ - ('uninstallable','Not Installable'), - ('uninstalled','Not Installed'), - ('installed','Installed'), - ('to upgrade','To be upgraded'), - ('to remove','To be removed'), - ('to install','To be installed') - ], string='State', readonly=True, select=True), - 'demo': fields.boolean('Demo data'), - 'license': fields.selection([ - ('GPL-2', 'GPL Version 2'), - ('GPL-2 or any later version', 'GPL-2 or later version'), - ('GPL-3', 'GPL Version 3'), - ('GPL-3 or any later version', 'GPL-3 or later version'), - ('AGPL-3', 'Affero GPL-3'), - ('Other OSI approved licence', 'Other OSI Approved Licence'), - ('Other proprietary', 'Other Proprietary') - ], string='License', readonly=True), - 'menus_by_module': fields.function(_get_views, method=True, string='Menus', type='text', multi="meta", store=True), - 'reports_by_module': fields.function(_get_views, method=True, string='Reports', type='text', multi="meta", store=True), - 'views_by_module': fields.function(_get_views, method=True, string='Views', type='text', multi="meta", store=True), - 'certificate' : fields.char('Quality Certificate', size=64, readonly=True), - 'web': fields.boolean('Has a web component', readonly=True), - } - - _defaults = { - 'state': 'uninstalled', - 'demo': False, - 'license': 'AGPL-3', - 'web': False, - } - _order = 'name' - - def _name_uniq_msg(self, cr, uid, ids, context=None): - return _('The name of the module must be unique !') - def _certificate_uniq_msg(self, cr, uid, ids, context=None): - return _('The certificate ID of the module must be unique !') - - _sql_constraints = [ - ('name_uniq', 'UNIQUE (name)',_name_uniq_msg ), - ('certificate_uniq', 'UNIQUE (certificate)',_certificate_uniq_msg ) - ] - - def unlink(self, cr, uid, ids, context=None): - if not ids: - return True - if isinstance(ids, (int, long)): - ids = [ids] - mod_names = [] - for mod in self.read(cr, uid, ids, ['state','name'], context): - if mod['state'] in ('installed', 'to upgrade', 'to remove', 'to install'): - raise orm.except_orm(_('Error'), - _('You try to remove a module that is installed or will be installed')) - mod_names.append(mod['name']) - #Removing the entry from ir_model_data - ids_meta = self.pool.get('ir.model.data').search(cr, uid, [('name', '=', 'module_meta_information'), ('module', 'in', mod_names)]) - - if ids_meta: - self.pool.get('ir.model.data').unlink(cr, uid, ids_meta, context) - - 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,)) - - @classmethod - def check_external_dependencies(cls, module_name, newstate='to install'): - terp = cls.get_module_info(module_name) - try: - cls._check_external_dependencies(terp) - except Exception, e: - if newstate == 'to install': - msg = _('Unable to install module "%s" because an external dependency is not met: %s') - elif newstate == 'to upgrade': - msg = _('Unable to upgrade module "%s" because an external dependency is not met: %s') - else: - msg = _('Unable to process module "%s" because an external dependency is not met: %s') - raise orm.except_orm(_('Error'), msg % (module_name, e.args[0])) - - def state_update(self, cr, uid, ids, newstate, states_to_update, context=None, level=100): - if level<1: - raise orm.except_orm(_('Error'), _('Recursion error in modules dependencies !')) - demo = False - for module in self.browse(cr, uid, ids): - mdemo = False - for dep in module.dependencies_id: - if dep.state == 'unknown': - raise orm.except_orm(_('Error'), _("You try to install module '%s' that depends on module '%s'.\nBut the latter module is not available in your system.") % (module.name, dep.name,)) - ids2 = self.search(cr, uid, [('name','=',dep.name)]) - if dep.state != newstate: - mdemo = self.state_update(cr, uid, ids2, newstate, states_to_update, context, level-1,) or mdemo - else: - od = self.browse(cr, uid, ids2)[0] - mdemo = od.demo or mdemo - - self.check_external_dependencies(module.name, newstate) - if not module.dependencies_id: - mdemo = module.demo - if module.state in states_to_update: - self.write(cr, uid, [module.id], {'state': newstate, 'demo':mdemo}) - demo = demo or mdemo - return demo - - def button_install(self, cr, uid, ids, context=None): - return self.state_update(cr, uid, ids, 'to install', ['uninstalled'], context) - - def button_install_cancel(self, cr, uid, ids, context=None): - self.write(cr, uid, ids, {'state': 'uninstalled', 'demo':False}) - return True - - def button_uninstall(self, cr, uid, ids, context=None): - for module in self.browse(cr, uid, ids): - cr.execute('''select m.state,m.name - from - ir_module_module_dependency d - join - ir_module_module m on (d.module_id=m.id) - where - d.name=%s and - m.state not in ('uninstalled','uninstallable','to remove')''', (module.name,)) - res = cr.fetchall() - if res: - raise orm.except_orm(_('Error'), _('Some installed modules depend on the module you plan to Uninstall :\n %s') % '\n'.join(map(lambda x: '\t%s: %s' % (x[0], x[1]), res))) - self.write(cr, uid, ids, {'state': 'to remove'}) - return True - - def button_uninstall_cancel(self, cr, uid, ids, context=None): - self.write(cr, uid, ids, {'state': 'installed'}) - return True - - def button_upgrade(self, cr, uid, ids, context=None): - depobj = self.pool.get('ir.module.module.dependency') - todo = self.browse(cr, uid, ids, context=context) - self.update_list(cr, uid) - - i = 0 - while i<len(todo): - mod = todo[i] - i += 1 - if mod.state not in ('installed','to upgrade'): - raise orm.except_orm(_('Error'), - _("Can not upgrade module '%s'. It is not installed.") % (mod.name,)) - self.check_external_dependencies(mod.name, 'to upgrade') - iids = depobj.search(cr, uid, [('name', '=', mod.name)], context=context) - for dep in depobj.browse(cr, uid, iids, context=context): - if dep.module_id.state=='installed' and dep.module_id not in todo: - todo.append(dep.module_id) - - ids = map(lambda x: x.id, todo) - self.write(cr, uid, ids, {'state':'to upgrade'}, context=context) - - to_install = [] - for mod in todo: - for dep in mod.dependencies_id: - if dep.state == 'unknown': - raise orm.except_orm(_('Error'), _('You try to upgrade a module that depends on the module: %s.\nBut this module is not available in your system.') % (dep.name,)) - if dep.state == 'uninstalled': - ids2 = self.search(cr, uid, [('name','=',dep.name)]) - to_install.extend(ids2) - - self.button_install(cr, uid, to_install, context=context) - return True - - def button_upgrade_cancel(self, cr, uid, ids, context=None): - self.write(cr, uid, ids, {'state': 'installed'}) - return True - def button_update_translations(self, cr, uid, ids, context=None): - 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', 'AGPL-3'), - 'certificate': terp.get('certificate') or False, - 'web': terp.get('web') or False, - } - - # update the list of available packages - def update_list(self, cr, uid, context={}): - res = [0, 0] # [update, add] - - known_mods = self.browse(cr, uid, self.search(cr, uid, [])) - known_mods_names = dict([(m.name, m) for m in known_mods]) - - # iterate through detected modules and update/create them in db - for mod_name in addons.get_modules(): - mod = known_mods_names.get(mod_name) - terp = self.get_module_info(mod_name) - values = self.get_values_from_terp(terp) - - if mod: - updated_values = {} - for key in values: - old = getattr(mod, key) - updated = isinstance(values[key], basestring) and tools.ustr(values[key]) or values[key] - if not old == updated: - updated_values[key] = values[key] - if terp.get('installable', True) and mod.state == 'uninstallable': - updated_values['state'] = 'uninstalled' - if parse_version(terp.get('version', '')) > parse_version(mod.latest_version or ''): - res[0] += 1 - if updated_values: - self.write(cr, uid, mod.id, updated_values) - 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, dict(name=mod_name, state='uninstalled', **values)) - mod = self.browse(cr, uid, id) - res[1] += 1 - - self._update_dependencies(cr, uid, mod, terp.get('depends', [])) - self._update_category(cr, uid, mod, terp.get('category', 'Uncategorized')) - - return res - - def download(self, cr, uid, ids, download=True, context=None): - res = [] - for mod in self.browse(cr, uid, ids, context=context): - if not mod.url: - continue - match = re.search('-([a-zA-Z0-9\._-]+)(\.zip)', mod.url, re.I) - version = '0' - if match: - version = match.group(1) - if parse_version(mod.installed_version or '0') >= parse_version(version): - continue - res.append(mod.url) - if not download: - continue - zipfile = urllib.urlopen(mod.url).read() - fname = addons.get_module_path(str(mod.name)+'.zip', downloaded=True) - try: - fp = file(fname, 'wb') - fp.write(zipfile) - fp.close() - except Exception: - self.__logger.exception('Error when trying to create module ' - 'file %s', fname) - 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, 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, terp.get('depends', - [])) - self._update_category(cr, uid, mod, terp.get('category', - 'Uncategorized')) - # Import module - zimp = zipimport.zipimporter(fname) - zimp.load_module(mod.name) - return res - - def _update_dependencies(self, cr, uid, mod_browse, depends=None): - if depends is None: - depends = [] - existing = set(x.name for x in mod_browse.dependencies_id) - needed = set(depends) - for dep in (needed - existing): - cr.execute('INSERT INTO ir_module_module_dependency (module_id, name) values (%s, %s)', (mod_browse.id, dep)) - for dep in (existing - needed): - cr.execute('DELETE FROM ir_module_module_dependency WHERE module_id = %s and name = %s', (mod_browse.id, dep)) - - def _update_category(self, cr, uid, mod_browse, category='Uncategorized'): - current_category = mod_browse.category_id - current_category_path = [] - while current_category: - current_category_path.insert(0, current_category.name) - current_category = current_category.parent_id - - categs = category.split('/') - if categs != current_category_path: - p_id = None - while categs: - if p_id is not None: - cr.execute('SELECT id FROM ir_module_category WHERE name=%s AND parent_id=%s', (categs[0], p_id)) - else: - cr.execute('SELECT id FROM ir_module_category WHERE name=%s AND parent_id is NULL', (categs[0],)) - c_id = cr.fetchone() - if not c_id: - cr.execute('INSERT INTO ir_module_category (name, parent_id) VALUES (%s, %s) RETURNING id', (categs[0], p_id)) - c_id = cr.fetchone()[0] - else: - c_id = c_id[0] - p_id = c_id - categs = categs[1:] - self.write(cr, uid, [mod_browse.id], {'category_id': p_id}) - - def update_translations(self, cr, uid, ids, filter_lang=None, context={}): - logger = logging.getLogger('i18n') - if not filter_lang: - pool = pooler.get_pool(cr.dbname) - lang_obj = pool.get('res.lang') - lang_ids = lang_obj.search(cr, uid, [('translatable', '=', True)]) - filter_lang = [lang.code for lang in lang_obj.browse(cr, uid, lang_ids)] - elif not isinstance(filter_lang, (list, tuple)): - filter_lang = [filter_lang] - - for mod in self.browse(cr, uid, ids): - if mod.state != 'installed': - continue - modpath = addons.get_module_path(mod.name) - if not modpath: - # unable to find the module. we skip - continue - for lang in filter_lang: - iso_lang = tools.get_iso_codes(lang) - f = addons.get_module_resource(mod.name, 'i18n', iso_lang + '.po') - context2 = context and context.copy() or {} - if f and '_' in iso_lang: - iso_lang2 = iso_lang.split('_')[0] - f2 = addons.get_module_resource(mod.name, 'i18n', iso_lang2 + '.po') - if f2: - logger.info('module %s: loading base translation file %s for language %s', mod.name, iso_lang2, lang) - tools.trans_load(cr, f2, lang, verbose=False, context=context) - context2['overwrite'] = True - # Implementation notice: we must first search for the full name of - # the language derivative, like "en_UK", and then the generic, - # like "en". - if (not f) and '_' in iso_lang: - iso_lang = iso_lang.split('_')[0] - f = addons.get_module_resource(mod.name, 'i18n', iso_lang + '.po') - if f: - logger.info('module %s: loading translation file (%s) for language %s', mod.name, iso_lang, lang) - tools.trans_load(cr, f, lang, verbose=False, context=context2) - elif iso_lang != 'en': - logger.warning('module %s: no translation for language %s', mod.name, iso_lang) - tools.trans_update_res_ids(cr) - - def check(self, cr, uid, ids, context=None): - logger = logging.getLogger('init') - for mod in self.browse(cr, uid, ids, context=context): - if not mod.description: - logger.warn('module %s: description is empty !', mod.name) - - if not mod.certificate or not mod.certificate.isdigit(): - logger.info('module %s: no quality certificate', mod.name) - else: - val = long(mod.certificate[2:]) % 97 == 29 - if not val: - logger.critical('module %s: invalid quality certificate: %s', mod.name, mod.certificate) - raise osv.except_osv(_('Error'), _('Module %s: Invalid Quality Certificate') % (mod.name,)) - - def list_web(self, cr, uid, context=None): - """ list_web(cr, uid, context) -> [(module_name, module_version)] - Lists all the currently installed modules with a web component. - - Returns a list of a tuple of addon names and addon versions. - """ - return [ - (module['name'], module['installed_version']) - for module in self.browse(cr, uid, - self.search(cr, uid, - [('web', '=', True), - ('state', 'in', ['installed','to upgrade','to remove'])], - context=context), - context=context)] - def _web_dependencies(self, cr, uid, module, context=None): - for dependency in module.dependencies_id: - (parent,) = self.browse(cr, uid, self.search(cr, uid, - [('name', '=', dependency.name)], context=context), - context=context) - if parent.web: - yield parent.name - else: - self._web_dependencies( - cr, uid, parent, context=context) - - def _translations_subdir(self, module): - """ Returns the path to the subdirectory holding translations for the - module files, or None if it can't find one - - :param module: a module object - :type module: browse(ir.module.module) - """ - subdir = addons.get_module_resource(module.name, 'po') - if subdir: return subdir - # old naming convention - subdir = addons.get_module_resource(module.name, 'i18n') - if subdir: return subdir - return None - - def _add_translations(self, module, web_data): - """ Adds translation data to a zipped web module - - :param module: a module descriptor - :type module: browse(ir.module.module) - :param web_data: zipped data of a web module - :type web_data: bytes - """ - # cStringIO.StringIO is either read or write, not r/w - web_zip = StringIO.StringIO(web_data) - web_archive = zipfile.ZipFile(web_zip, 'a') - - # get the contents of the i18n or po folder and move them to the - # po/messages subdirectory of the web module. - # The POT file will be incorrectly named, but that should not - # matter since the web client is not going to use it, only the PO - # files. - translations_file = cStringIO.StringIO( - addons.zip_directory(self._translations_subdir(module), False)) - translations_archive = zipfile.ZipFile(translations_file) - - for path in translations_archive.namelist(): - web_path = os.path.join( - 'web', 'po', 'messages', os.path.basename(path)) - web_archive.writestr( - web_path, - translations_archive.read(path)) - - translations_archive.close() - translations_file.close() - - web_archive.close() - try: - return web_zip.getvalue() - finally: - web_zip.close() - - def get_web(self, cr, uid, names, context=None): - """ get_web(cr, uid, [module_name], context) -> [{name, depends, content}] - - Returns the web content of all the named addons. - - The toplevel directory of the zipped content is called 'web', - its final naming has to be managed by the client - """ - modules = self.browse(cr, uid, - self.search(cr, uid, [('name', 'in', names)], context=context), - context=context) - if not modules: return [] - self.__logger.info('Sending web content of modules %s ' - 'to web client', names) - - modules_data = [] - for module in modules: - web_data = addons.zip_directory( - addons.get_module_resource(module.name, 'web'), False) - if self._translations_subdir(module): - web_data = self._add_translations(module, web_data) - modules_data.append({ - 'name': module.name, - 'version': module.installed_version, - 'depends': list(self._web_dependencies( - cr, uid, module, context=context)), - 'content': base64.encodestring(web_data) - }) - return modules_data - -module() - -class module_dependency(osv.osv): - _name = "ir.module.module.dependency" - _description = "Module dependency" - - def _state(self, cr, uid, ids, name, args, context=None): - result = {} - mod_obj = self.pool.get('ir.module.module') - for md in self.browse(cr, uid, ids): - ids = mod_obj.search(cr, uid, [('name', '=', md.name)]) - if ids: - result[md.id] = mod_obj.read(cr, uid, [ids[0]], ['state'])[0]['state'] - else: - result[md.id] = 'unknown' - return result - - _columns = { - 'name': fields.char('Name', size=128, select=True), - 'module_id': fields.many2one('ir.module.module', 'Module', select=True, ondelete='cascade'), - 'state': fields.function(_state, method=True, type='selection', selection=[ - ('uninstallable','Uninstallable'), - ('uninstalled','Not Installed'), - ('installed','Installed'), - ('to upgrade','To be upgraded'), - ('to remove','To be removed'), - ('to install','To be installed'), - ('unknown', 'Unknown'), - ], string='State', readonly=True, select=True), - } -module_dependency() |
