From: Olivier Dony Date: Thu, 22 Dec 2011 10:25:55 +0000 (+0100) Subject: [MERGE] sync with trunk X-Git-Tag: 6.1.0-rc1-addons~357^2~3 X-Git-Url: http://git.inspyration.org/?a=commitdiff_plain;h=d925235e6233995fd643af6318bf318256cfd11f;p=odoo%2Fodoo.git [MERGE] sync with trunk bzr revid: odo@openerp.com-20111222102555-bydsozbdu6urkj31 --- d925235e6233995fd643af6318bf318256cfd11f diff --cc openerp/osv/fields.py index 222dd4a,42bc9b7..6fef850 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@@ -1177,96 -1177,9 +1178,97 @@@ class related(function) }) if f.get('relation',False): obj_name = f['relation'] - self._relations[-1]['relation'] = f['relation'] + result[-1]['relation'] = f['relation'] + self._relations = result + +class sparse(function): + + def convert_value(self, obj, cr, uid, record, value, read_value, context=None): + """ + + For a many2many field, a list of tuples is expected. + Here is the list of tuple that are accepted, with the corresponding semantics :: + + (0, 0, { values }) link to a new record that needs to be created with the given values dictionary + (1, ID, { values }) update the linked record with id = ID (write *values* on it) + (2, ID) remove and delete the linked record with id = ID (calls unlink on ID, that will delete the object completely, and the link to it as well) + (3, ID) cut the link to the linked record with id = ID (delete the relationship between the two objects but does not delete the target object itself) + (4, ID) link to existing record with id = ID (adds a relationship) + (5) unlink all (like using (3,ID) for all linked records) + (6, 0, [IDs]) replace the list of linked IDs (like using (5) then (4,ID) for each ID in the list of IDs) + + Example: + [(6, 0, [8, 5, 6, 4])] sets the many2many to ids [8, 5, 6, 4] + + + For a one2many field, a lits of tuples is expected. + Here is the list of tuple that are accepted, with the corresponding semantics :: + + (0, 0, { values }) link to a new record that needs to be created with the given values dictionary + (1, ID, { values }) update the linked record with id = ID (write *values* on it) + (2, ID) remove and delete the linked record with id = ID (calls unlink on ID, that will delete the object completely, and the link to it as well) + + Example: + [(0, 0, {'field_name':field_value_record1, ...}), (0, 0, {'field_name':field_value_record2, ...})] + """ + + if self._type == 'many2many': + assert value[0][0] == 6, 'Unsupported m2m value for sparse field: %s' % value + return value[0][2] + + elif self._type == 'one2many': + if not read_value: + read_value = [] + relation_obj = obj.pool.get(self.relation) + for vals in value: + assert vals[0] in (0,1,2), 'Unsupported o2m value for sparse field: %s' % vals + if vals[0] == 0: + read_value.append(relation_obj.create(cr, uid, vals[2], context=context)) + elif vals[0] == 1: + relation_obj.write(cr, uid, vals[1], vals[2], context=context) + elif vals[0] == 2: + relation_obj.unlink(cr, uid, vals[1], context=context) + read_value.remove(vals[1]) + return read_value + return value + + + def _fnct_write(self,obj,cr, uid, ids, field_name, value, args, context=None): + if not type(ids) == list: + ids = [ids] + records = obj.browse(cr, uid, ids, context=context) + for record in records: + # grab serialized value as object - already deserialized + serialized = getattr(record, self.serialization_field) + if value is None: + # simply delete the key to unset it. + serialized.pop(field_name, None) + else: + serialized[field_name] = self.convert_value(obj, cr, uid, record, value, serialized.get(field_name), context=context) + obj.write(cr, uid, ids, {self.serialization_field: serialized}, context=context) + return True + + def _fnct_read(self, obj, cr, uid, ids, field_names, args, context=None): + results = {} + records = obj.browse(cr, uid, ids, context=context) + for record in records: + # grab serialized value as object - already deserialized + serialized = getattr(record, self.serialization_field) + results[record.id] = {} + for field_name in field_names: + if obj._columns[field_name]._type in ['one2many']: + value = serialized.get(field_name, []) + else: + results[record.id].update(field_name=value) + return results + + def __init__(self, serialization_field, **kwargs): + self.serialization_field = serialization_field + return super(sparse, self).__init__(self._fnct_read, fnct_inv=self._fnct_write, multi='__sparse_multi', method=True, **kwargs) + + + + + # --------------------------------------------------------- # Dummy fields # --------------------------------------------------------- diff --cc setup.py index 3f10868,a239b6f..10c98d7 mode 100644,100644..100755 --- a/setup.py +++ b/setup.py @@@ -1,73 -1,73 +1,120 @@@ ++#!/usr/bin/env python ++# -*- coding: utf-8 -*- ++############################################################################## ++# ++# OpenERP, Open Source Management Solution ++# Copyright (C) 2004-2010 Tiny SPRL (). ++# ++# 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 . ++# ++############################################################################## --import os --import re --import sys --from setuptools import setup, find_packages ++import glob, os, re, setuptools, sys ++from os.path import join, isfile --execfile('addons/web/common/release.py') ++# List all data files ++def data(): ++ files = [] ++ for root, dirnames, filenames in os.walk('openerp'): ++ for filename in filenames: ++ if not re.match(r'.*(\.pyc|\.pyo|\~)$',filename): ++ files.append(os.path.join(root, filename)) ++ d = {} ++ for v in files: ++ k=os.path.dirname(v) ++ if k in d: ++ d[k].append(v) ++ else: ++ d[k]=[v] ++ r = d.items() ++ if os.name == 'nt': ++ r.append(("Microsoft.VC90.CRT", glob.glob('C:\Microsoft.VC90.CRT\*.*'))) ++ return r --version_dash_incompatible = False --if 'bdist_rpm' in sys.argv: -- version_dash_incompatible = True --try: -- import py2exe -- from py2exe_utils import opts -- version_dash_incompatible = True --except ImportError: -- opts = {} --if version_dash_incompatible: -- version = version.split('-')[0] ++def gen_manifest(): ++ file_list="\n".join(data()) ++ open('MANIFEST','w').write(file_list) --FILE_PATTERNS = \ -- r'.+\.(py|cfg|po|pot|mo|txt|rst|gif|png|jpg|ico|mako|html|js|css|htc|swf)$' --def find_data_files(source, patterns=FILE_PATTERNS): -- file_matcher = re.compile(patterns, re.I) -- out = [] -- for base, _, files in os.walk(source): -- cur_files = [] -- for f in files: -- if file_matcher.match(f): -- cur_files.append(os.path.join(base, f)) -- if cur_files: -- out.append( -- (base, cur_files)) ++if os.name == 'nt': ++ sys.path.append("C:\Microsoft.VC90.CRT") -- return out ++def py2exe_options(): ++ if os.name == 'nt': ++ import py2exe ++ return { ++ "console" : [ { "script": "openerp-server", "icon_resources": [(1, join("install","openerp-icon.ico"))], }], ++ 'options' : { ++ "py2exe": { ++ "skip_archive": 1, ++ "optimize": 2, ++ "dist_dir": 'dist', ++ "packages": [ "DAV", "HTMLParser", "PIL", "asynchat", "asyncore", "commands", "dateutil", "decimal", "email", "encodings", "imaplib", "lxml", "lxml._elementpath", "lxml.builder", "lxml.etree", "lxml.objectify", "mako", "openerp", "poplib", "pychart", "pydot", "pyparsing", "reportlab", "select", "simplejson", "smtplib", "uuid", "vatnumber", "vobject", "xml", "xml.dom", "yaml", ], ++ "excludes" : ["Tkconstants","Tkinter","tcl"], ++ } ++ } ++ } ++ else: ++ return {} --setup( -- name=name, -- version=version, -- description=description, -- long_description=long_description, -- author=author, -- author_email=author_email, -- url=url, -- download_url=download_url, -- license=license, -- install_requires=[ -- "Babel >= 0.9.6", -- "simplejson >= 2.0.9", - "python-dateutil >= 1.4.1", - "pytz", - "werkzeug == 0.7", - ], - tests_require=[ - 'unittest2', - 'mock', - ], - test_suite = 'unittest2.collector', - zip_safe=False, - packages=find_packages(), - classifiers=[ - 'Development Status :: 6 - Production/Stable', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Environment :: Web Environment', - 'Topic :: Office/Business :: Financial', - ], - scripts=['openerp-web'], - data_files=(find_data_files('addons') - + opts.pop('data_files', []) - ), - **opts - "python-dateutil >= 1.4.1, < 2", - "pytz", - "werkzeug == 0.7", - ], - tests_require=[ - 'unittest2', - 'mock', - ], - test_suite = 'unittest2.collector', - zip_safe=False, - packages=find_packages(), - classifiers=[ - 'Development Status :: 6 - Production/Stable', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Environment :: Web Environment', - 'Topic :: Office/Business :: Financial', - ], - scripts=['openerp-web'], - data_files=(find_data_files('addons') - + opts.pop('data_files', []) - ), - **opts ++execfile(join(os.path.dirname(__file__), 'openerp', 'release.py')) ++ ++setuptools.setup( ++ name = 'openerp', ++ version = version, ++ description = description, ++ long_description = long_desc, ++ url = url, ++ author = author, ++ author_email = author_email, ++ classifiers = filter(None, classifiers.split("\n")), ++ license = license, ++ scripts = ['openerp-server'], ++ data_files = data(), ++ packages = setuptools.find_packages(), ++ #include_package_data = True, ++ install_requires = [ ++ # TODO the pychart package we include in openerp corresponds to PyChart 1.37. ++ # It seems there is a single difference, which is a spurious print in generate_docs.py. ++ # It is probably safe to move to PyChart 1.39 (the latest one). ++ # (Let setup.py choose the latest one, and we should check we can remove pychart from ++ # our tree.) http://download.gna.org/pychart/ ++ # TODO 'pychart', ++ 'babel', ++ 'feedparser', ++ 'gdata', ++ 'lxml', ++ 'mako', ++ 'psycopg2', ++ 'pydot', ++ 'python-dateutil < 2', ++ 'python-ldap', ++ 'python-openid', ++ 'pytz', ++ 'pywebdav', ++ 'pyyaml', ++ 'reportlab', ++ 'simplejson', ++ 'vatnumber', ++ 'vobject', ++ 'werkzeug', ++ 'zsi', ++ ], ++ extras_require = { ++ 'SSL' : ['pyopenssl'], ++ }, ++ **py2exe_options() ) ++ ++ ++# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: