[FORWARD] Forward port of server 7.0 until revision 4988
authorThibault Delavallée <tde@openerp.com>
Tue, 28 May 2013 10:27:33 +0000 (12:27 +0200)
committerThibault Delavallée <tde@openerp.com>
Tue, 28 May 2013 10:27:33 +0000 (12:27 +0200)
bzr revid: tde@openerp.com-20130528102733-bsszxp6nvy8yws3t

12 files changed:
1  2 
openerp/addons/base/ir/ir_mail_server.py
openerp/addons/base/res/res_currency.py
openerp/addons/base/res/res_partner.py
openerp/cli/server.py
openerp/netsvc.py
openerp/osv/expression.py
openerp/report/render/rml2pdf/customfonts.py
openerp/report/render/rml2pdf/utils.py
openerp/service/cron.py
openerp/service/http_server.py
openerp/service/websrv_lib.py
setup.py

@@@ -31,6 -31,7 +31,7 @@@ import r
  import smtplib
  import threading
  
+ from openerp import SUPERUSER_ID
  from openerp.osv import osv, fields
  from openerp.tools.translate import _
  from openerp.tools import html2text
@@@ -41,8 -42,6 +42,8 @@@ import openerp.tools as tool
  from openerp.loglevels import ustr
  
  _logger = logging.getLogger(__name__)
 +_test_logger = logging.getLogger('openerp.tests')
 +
  
  class MailDeliveryException(osv.except_osv):
      """Specific exception subclass for mail delivery errors"""
@@@ -413,17 -412,17 +414,17 @@@ class ir_mail_server(osv.osv)
  
          # Do not actually send emails in testing mode!
          if getattr(threading.currentThread(), 'testing', False):
 -            _logger.log(logging.TEST, "skip sending email in test mode")
 +            _test_logger.info("skip sending email in test mode")
              return message['Message-Id']
  
          # Get SMTP Server Details from Mail Server
          mail_server = None
          if mail_server_id:
-             mail_server = self.browse(cr, uid, mail_server_id)
+             mail_server = self.browse(cr, SUPERUSER_ID, mail_server_id)
          elif not smtp_server:
-             mail_server_ids = self.search(cr, uid, [], order='sequence', limit=1)
+             mail_server_ids = self.search(cr, SUPERUSER_ID, [], order='sequence', limit=1)
              if mail_server_ids:
-                 mail_server = self.browse(cr, uid, mail_server_ids[0])
+                 mail_server = self.browse(cr, SUPERUSER_ID, mail_server_ids[0])
  
          if mail_server:
              smtp_server = mail_server.smtp_host
@@@ -30,11 -30,7 +30,11 @@@ from openerp.tools.translate import 
  CURRENCY_DISPLAY_PATTERN = re.compile(r'(\w+)\s*(?:\((.*)\))?')
  
  class res_currency(osv.osv):
 +
      def _current_rate(self, cr, uid, ids, name, arg, context=None):
 +        return self._get_current_rate(cr, uid, ids, name, arg, context=context)
 +
 +    def _get_current_rate(self, cr, uid, ids, name, arg, context=None):
          if context is None:
              context = {}
          res = {}
@@@ -77,6 -73,7 +77,7 @@@
          'position' : 'after',
          'rounding': 0.01,
          'accuracy': 4,
+         'company_id': False,
      }
      _sql_constraints = [
          # this constraint does not cover all cases due to SQL NULL handling for company_id,
@@@ -27,14 -27,14 +27,14 @@@ import r
  
  import openerp
  from openerp import SUPERUSER_ID
 -from openerp import pooler, tools
 +from openerp import tools
  from openerp.osv import osv, fields
  from openerp.tools.translate import _
  from openerp.tools.yaml_import import is_comment
  
  class format_address(object):
      def fields_view_get_address(self, cr, uid, arch, context={}):
 -        user_obj = self.pool.get('res.users')
 +        user_obj = self.pool['res.users']
          fmt = user_obj.browse(cr, SUPERUSER_ID, uid, context).company_id.country_id
          fmt = fmt and fmt.address_format
          layouts = {
@@@ -74,7 -74,8 +74,8 @@@
  
  
  def _tz_get(self,cr,uid, context=None):
-     return [(x, x) for x in pytz.all_timezones]
+     # put POSIX 'Etc/*' entries at the end to avoid confusing users - see bug 1086728
+     return [(tz,tz) for tz in sorted(pytz.all_timezones, key=lambda tz: tz if not tz.startswith('Etc/') else '_')]
  
  class res_partner_category(osv.osv):
  
@@@ -155,13 -156,14 +156,13 @@@ class res_partner_title(osv.osv)
      }
  
  def _lang_get(self, cr, uid, context=None):
 -    lang_pool = self.pool.get('res.lang')
 +    lang_pool = self.pool['res.lang']
      ids = lang_pool.search(cr, uid, [], context=context)
      res = lang_pool.read(cr, uid, ids, ['code', 'name'], context)
      return [(r['code'], r['name']) for r in res]
  
  # fields copy if 'use_parent_address' is checked
  ADDRESS_FIELDS = ('street', 'street2', 'zip', 'city', 'state_id', 'country_id')
 -POSTAL_ADDRESS_FIELDS = ADDRESS_FIELDS # deprecated, to remove after 7.0
  
  class res_partner(osv.osv, format_address):
      _description = 'Partner'
              result[partner.id] = current_partner.id
          return result
  
 -    # indirection to avoid passing a copy of the overridable method when declaring the function field
 +    def _display_name_compute(self, cr, uid, ids, name, args, context=None):
 +        return dict(self.name_get(cr, uid, ids, context=context))
 +
 +    # indirections to avoid passing a copy of the overridable method when declaring the function field
      _commercial_partner_id = lambda self, *args, **kwargs: self._commercial_partner_compute(*args, **kwargs)
 +    _display_name = lambda self, *args, **kwargs: self._display_name_compute(*args, **kwargs)
 +
 +    _commercial_partner_store_triggers = {
 +        'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)]),
 +                        ['parent_id', 'is_company'], 10) 
 +    }
 +    _display_name_store_triggers = {
 +        'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)]),
 +                        ['parent_id', 'is_company', 'name'], 10) 
 +    }
  
 -    _order = "name"
 +    _order = "display_name"
      _columns = {
          'name': fields.char('Name', size=128, required=True, select=True),
 +        'display_name': fields.function(_display_name, type='char', string='Name', store=_display_name_store_triggers),
          'date': fields.date('Date', select=1),
          'title': fields.many2one('res.partner.title', 'Title'),
          'parent_id': fields.many2one('res.partner', 'Related Company'),
          'contact_address': fields.function(_address_display,  type='char', string='Complete Address'),
  
          # technical field used for managing commercial fields
 -        'commercial_partner_id': fields.function(_commercial_partner_id, type='many2one', relation='res.partner', string='Commercial Entity')
 +        'commercial_partner_id': fields.function(_commercial_partner_id, type='many2one', relation='res.partner', string='Commercial Entity', store=_commercial_partner_store_triggers)
      }
  
      def _default_category(self, cr, uid, context=None):
  
      def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
          if (not view_id) and (view_type=='form') and context and context.get('force_email', False):
 -            view_id = self.pool.get('ir.model.data').get_object_reference(cr, user, 'base', 'view_partner_simple_form')[1]
 +            view_id = self.pool['ir.model.data'].get_object_reference(cr, user, 'base', 'view_partner_simple_form')[1]
          res = super(res_partner,self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
          if view_type == 'form':
              res['arch'] = self.fields_view_get_address(cr, user, res['arch'], context=context)
          'tz': lambda self, cr, uid, ctx: ctx.get('tz', False),
          'customer': True,
          'category_id': _default_category,
 -        'company_id': lambda self, cr, uid, ctx: self.pool.get('res.company')._company_default_get(cr, uid, 'res.partner', context=ctx),
 +        'company_id': lambda self, cr, uid, ctx: self.pool['res.company']._company_default_get(cr, uid, 'res.partner', context=ctx),
          'color': 0,
          'is_company': False,
          'type': 'contact', # type 'default' is wildcard and thus inappropriate
  
      def onchange_state(self, cr, uid, ids, state_id, context=None):
          if state_id:
 -            country_id = self.pool.get('res.country.state').browse(cr, uid, state_id, context).country_id.id
 +            country_id = self.pool['res.country.state'].browse(cr, uid, state_id, context).country_id.id
              return {'value':{'country_id':country_id}}
          return {}
  
      def _check_ean_key(self, cr, uid, ids, context=None):
 -        for partner_o in pooler.get_pool(cr.dbname).get('res.partner').read(cr, uid, ids, ['ean13',]):
 +        for partner_o in self.pool['res.partner'].read(cr, uid, ids, ['ean13',]):
              thisean=partner_o['ean13']
              if thisean and thisean!='':
                  if len(thisean)!=13:
  
      def email_send(self, cr, uid, ids, email_from, subject, body, on_error=''):
          while len(ids):
 -            self.pool.get('ir.cron').create(cr, uid, {
 +            self.pool['ir.cron'].create(cr, uid, {
                  'name': 'Send Partner Emails',
                  'user_id': uid,
                  'model': 'res.partner',
          if res: return res
          if not context.get('category_id', False):
              return False
 -        return _('Partners: ')+self.pool.get('res.partner.category').browse(cr, uid, context['category_id'], context).name
 +        return _('Partners: ')+self.pool['res.partner.category'].browse(cr, uid, context['category_id'], context).name
  
      def main_partner(self, cr, uid):
          ''' Return the id of the main partner
          '''
 -        model_data = self.pool.get('ir.model.data')
 +        model_data = self.pool['ir.model.data']
          return model_data.browse(cr, uid,
                              model_data.search(cr, uid, [('module','=','base'),
                                                  ('name','=','main_partner')])[0],
diff --combined openerp/cli/server.py
@@@ -1,4 -1,3 +1,3 @@@
- #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  ##############################################################################
  #
@@@ -95,18 -94,16 +94,18 @@@ def preload_registry(dbname)
      """ Preload a registry, and start the cron."""
      try:
          update_module = True if openerp.tools.config['init'] or openerp.tools.config['update'] else False
 -        db, registry = openerp.pooler.get_db_and_pool(dbname,update_module=update_module)
 +        openerp.modules.registry.RegistryManager.new(dbname, update_module=update_module)
      except Exception:
          _logger.exception('Failed to initialize database `%s`.', dbname)
 +        return False
 +    return True
  
  def run_test_file(dbname, test_file):
      """ Preload a registry, possibly run a test file, and start the cron."""
      try:
          config = openerp.tools.config
 -        db, registry = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'])
 -        cr = db.cursor()
 +        registry = openerp.modules.registry.RegistryManager.new(dbname, update_module=config['init'] or config['update'])
 +        cr = registry.db.cursor()
          _logger.info('loading test file %s', test_file)
          openerp.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'test', True)
          cr.rollback()
@@@ -127,8 -124,7 +126,8 @@@ def export_translation()
  
      fileformat = os.path.splitext(config["translate_out"])[-1][1:].lower()
      buf = file(config["translate_out"], "w")
 -    cr = openerp.pooler.get_db(dbname).cursor()
 +    registry = openerp.modules.registry.RegistryManager.new(dbname)
 +    cr = registry.db.cursor()
      openerp.tools.trans_export(config["language"],
          config["translate_modules"] or ["all"], buf, fileformat, cr)
      cr.close()
@@@ -141,8 -137,7 +140,8 @@@ def import_translation()
      context = {'overwrite': config["overwrite_existing_translations"]}
      dbname = config['db_name']
  
 -    cr = openerp.pooler.get_db(dbname).cursor()
 +    registry = openerp.modules.registry.RegistryManager.new(dbname)
 +    cr = registry.db.cursor()
      openerp.tools.trans_load( cr, config["translate_in"], config["language"],
          context=context)
      cr.commit()
@@@ -185,9 -180,9 +184,9 @@@ def dumpstacks(sig, frame)
                  code.append("  %s" % (line.strip()))
      _logger.info("\n".join(code))
  
 -def setup_signal_handlers():
 -    """ Register the signal handler defined above. """
 -    SIGNALS = map(lambda x: getattr(signal, "SIG%s" % x), "INT TERM".split())
 +def setup_signal_handlers(signal_handler):
 +    """ Register the given signal handler. """
 +    SIGNALS = (signal.SIGINT, signal.SIGTERM)
      if os.name == 'posix':
          map(lambda sig: signal.signal(sig, signal_handler), SIGNALS)
          signal.signal(signal.SIGQUIT, dumpstacks)
@@@ -226,21 -221,13 +225,21 @@@ def main(args)
      check_root_user()
      openerp.tools.config.parse_config(args)
  
 +    if openerp.tools.config.options["gevent"]:
 +        openerp.evented = True
 +        _logger.info('Using gevent mode')
 +        import gevent.monkey
 +        gevent.monkey.patch_all()
 +        import gevent_psycopg2
 +        gevent_psycopg2.monkey_patch()
 +
      check_postgres_user()
      openerp.netsvc.init_logger()
      report_configuration()
  
      config = openerp.tools.config
  
 -    setup_signal_handlers()
 +    setup_signal_handlers(signal_handler)
  
      if config["test_file"]:
          run_test_file(config['db_name'], config['test_file'])
          else:
              openerp.service.start_services()
  
 +    rc = 0
      if config['db_name']:
          for dbname in config['db_name'].split(','):
 -            preload_registry(dbname)
 +            if not preload_registry(dbname):
 +                rc += 1
  
      if config["stop_after_init"]:
 -        sys.exit(0)
 +        sys.exit(rc)
  
      _logger.info('OpenERP server is running, waiting for connections...')
      quit_on_signals()
diff --combined openerp/netsvc.py
@@@ -1,4 -1,3 +1,3 @@@
- #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  ##############################################################################
  #
  #
  ##############################################################################
  
 -#.apidoc title: Common Services: netsvc
 -#.apidoc module-mods: member-order: bysource
  
  import logging
  import logging.handlers
  import os
 -import platform
  import release
 -import socket
  import sys
  import threading
  import time
  import types
  from pprint import pformat
 +import psutil
  
 -try:
 -    import psutil
 -except ImportError:
 -    psutil = None
 -
 -# TODO modules that import netsvc only for things from loglevels must be changed to use loglevels.
 -from loglevels import *
  import tools
  import openerp
  
  _logger = logging.getLogger(__name__)
  
 -
 -def close_socket(sock):
 -    """ Closes a socket instance cleanly
 -
 -    :param sock: the network socket to close
 -    :type sock: socket.socket
 -    """
 -    try:
 -        sock.shutdown(socket.SHUT_RDWR)
 -    except socket.error, e:
 -        # On OSX, socket shutdowns both sides if any side closes it
 -        # causing an error 57 'Socket is not connected' on shutdown
 -        # of the other side (or something), see
 -        # http://bugs.python.org/issue4397
 -        # note: stdlib fixed test, not behavior
 -        if e.errno != errno.ENOTCONN or platform.system() not in ['Darwin', 'Windows']:
 -            raise
 -    sock.close()
 -
 -def abort_response(dummy_1, description, dummy_2, details):
 -    # TODO Replace except_{osv,orm} with these directly.
 -    raise openerp.osv.osv.except_osv(description, details)
 -
 -class Service(object):
 -    """ Base class for Local services
 -    Functionality here is trusted, no authentication.
 -    Workflow engine and reports subclass this.
 -    """
 -    _services = {}
 -    def __init__(self, name):
 -        Service._services[name] = self
 -        self.__name = name
 -
 -    @classmethod
 -    def exists(cls, name):
 -        return name in cls._services
 -
 -    @classmethod
 -    def remove(cls, name):
 -        if cls.exists(name):
 -            cls._services.pop(name)
 -
  def LocalService(name):
 -    # Special case for addons support, will be removed in a few days when addons
 -    # are updated to directly use openerp.osv.osv.service.
 -    if name == 'object_proxy':
 -        return openerp.osv.osv.service
 -
 -    return Service._services[name]
 -
 -class ExportService(object):
 -    """ Proxy for exported services.
 -
 -    Note that this class has no direct proxy, capable of calling
 -    eservice.method(). Rather, the proxy should call
 -    dispatch(method, params)
      """
 +    The openerp.netsvc.LocalService() function is deprecated. It still works
 +    in two cases: workflows and reports. For workflows, instead of using
 +    LocalService('workflow'), openerp.workflow should be used (better yet,
 +    methods on openerp.osv.orm.Model should be used). For reports,
 +    openerp.report.render_report() should be used (methods on the Model should
 +    be provided too in the future).
 +    """
 +    assert openerp.conf.deprecation.allow_local_service
 +    _logger.warning("LocalService() is deprecated since march 2013 (it was called with '%s')." % name)
  
 -    _services = {}
 -    
 -    def __init__(self, name):
 -        ExportService._services[name] = self
 -        self.__name = name
 -        _logger.debug("Registered an exported service: %s" % name)
 -
 -    @classmethod
 -    def getService(cls,name):
 -        return cls._services[name]
 +    if name == 'workflow':
 +        return openerp.workflow
  
 -    # Dispatch a RPC call w.r.t. the method name. The dispatching
 -    # w.r.t. the service (this class) is done by OpenERPDispatcher.
 -    def dispatch(self, method, params):
 -        raise Exception("stub dispatch at %s" % self.__name)
 +    if name.startswith('report.'):
 +        report = openerp.report.interface.report_int._reports.get(name)
 +        if report:
 +            return report
 +        else:
 +            dbname = getattr(threading.currentThread(), 'dbname', None)
 +            if dbname:
 +                registry = openerp.modules.registry.RegistryManager.get(dbname)
 +                with registry.cursor() as cr:
 +                    return registry['ir.actions.report.xml']._lookup_report(cr, name[len('report.'):])
  
  BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, _NOTHING, DEFAULT = range(10)
  #The background is set with 40 plus the number of the color, and the foreground with 30
@@@ -73,6 -131,7 +72,6 @@@ COLOR_PATTERN = "%s%s%%s%s" % (COLOR_SE
  LEVEL_COLOR_MAPPING = {
      logging.DEBUG: (BLUE, DEFAULT),
      logging.INFO: (GREEN, DEFAULT),
 -    logging.TEST: (WHITE, BLUE),
      logging.WARNING: (YELLOW, DEFAULT),
      logging.ERROR: (RED, DEFAULT),
      logging.CRITICAL: (WHITE, RED),
@@@ -139,12 -198,38 +138,12 @@@ def init_logger()
      handler.setFormatter(formatter)
  
      # Configure handlers
 -    default_config = [
 -        'openerp.netsvc.rpc.request:INFO',
 -        'openerp.netsvc.rpc.response:INFO',
 -        'openerp.addons.web.http:INFO',
 -        'openerp.sql_db:INFO',
 -        ':INFO',
 -    ]
 -
 -    if tools.config['log_level'] == 'info':
 -        pseudo_config = []
 -    elif tools.config['log_level'] == 'debug_rpc':
 -        pseudo_config = ['openerp:DEBUG','openerp.netsvc.rpc.request:DEBUG']
 -    elif tools.config['log_level'] == 'debug_rpc_answer':
 -        pseudo_config = ['openerp:DEBUG','openerp.netsvc.rpc.request:DEBUG', 'openerp.netsvc.rpc.response:DEBUG']
 -    elif tools.config['log_level'] == 'debug':
 -        pseudo_config = ['openerp:DEBUG']
 -    elif tools.config['log_level'] == 'test':
 -        pseudo_config = ['openerp:TEST']
 -    elif tools.config['log_level'] == 'warn':
 -        pseudo_config = ['openerp:WARNING']
 -    elif tools.config['log_level'] == 'error':
 -        pseudo_config = ['openerp:ERROR']
 -    elif tools.config['log_level'] == 'critical':
 -        pseudo_config = ['openerp:CRITICAL']
 -    elif tools.config['log_level'] == 'debug_sql':
 -        pseudo_config = ['openerp.sql_db:DEBUG']
 -    else:
 -        pseudo_config = []
 +    pseudo_config = PSEUDOCONFIG_MAPPER.get(tools.config['log_level'], [])
  
      logconfig = tools.config['log_handler']
  
 -    for logconfig_item in default_config + pseudo_config + logconfig:
 +    logging_configurations = DEFAULT_LOG_CONFIGURATION + pseudo_config + logconfig
 +    for logconfig_item in logging_configurations:
          loggername, level = logconfig_item.split(':')
          level = getattr(logging, level, logging.INFO)
          logger = logging.getLogger(loggername)
          if loggername != '':
              logger.propagate = False
  
 -    for logconfig_item in default_config + pseudo_config + logconfig:
 +    for logconfig_item in logging_configurations:
          _logger.debug('logger level set: "%s"', logconfig_item)
  
 +DEFAULT_LOG_CONFIGURATION = [
 +    'openerp.workflow.workitem:WARNING',
 +    'openerp.netsvc.rpc.request:INFO',
 +    'openerp.netsvc.rpc.response:INFO',
 +    'openerp.addons.web.http:INFO',
 +    'openerp.sql_db:INFO',
 +    ':INFO',
 +]
 +PSEUDOCONFIG_MAPPER = {
 +    'debug_rpc_answer': ['openerp:DEBUG','openerp.netsvc.rpc.request:DEBUG', 'openerp.netsvc.rpc.response:DEBUG'],
 +    'debug_rpc': ['openerp:DEBUG','openerp.netsvc.rpc.request:DEBUG'],
 +    'debug': ['openerp:DEBUG'],
 +    'debug_sql': ['openerp.sql_db:DEBUG'],
 +    'info': [],
 +    'warn': ['openerp:WARNING'],
 +    'error': ['openerp:ERROR'],
 +    'critical': ['openerp:CRITICAL'],
 +}
 +
  # A alternative logging scheme for automated runs of the
  # server intended to test it.
  def init_alternative_logger():
@@@ -207,8 -273,8 +206,8 @@@ def log(logger, level, prefix, msg, dep
  def dispatch_rpc(service_name, method, params):
      """ Handle a RPC call.
  
 -    This is pure Python code, the actual marshalling (from/to XML-RPC or
 -    NET-RPC) is done in a upper layer.
 +    This is pure Python code, the actual marshalling (from/to XML-RPC) is done
 +    in a upper layer.
      """
      try:
          rpc_request = logging.getLogger(__name__ + '.rpc.request')
          if rpc_request_flag or rpc_response_flag:
              start_time = time.time()
              start_rss, start_vms = 0, 0
 -            if psutil:
 -                start_rss, start_vms = psutil.Process(os.getpid()).get_memory_info()
 +            start_rss, start_vms = psutil.Process(os.getpid()).get_memory_info()
              if rpc_request and rpc_response_flag:
                  log(rpc_request,logging.DEBUG,'%s.%s'%(service_name,method), replace_request_password(params))
  
 -        result = ExportService.getService(service_name).dispatch(method, params)
 +        threading.current_thread().uid = None
 +        threading.current_thread().dbname = None
 +        if service_name == 'common':
 +            dispatch = openerp.service.common.dispatch
 +        elif service_name == 'db':
 +            dispatch = openerp.service.db.dispatch
 +        elif service_name == 'object':
 +            dispatch = openerp.service.model.dispatch
 +        elif service_name == 'report':
 +            dispatch = openerp.service.report.dispatch
 +        else:
 +            dispatch = openerp.service.wsgi_server.rpc_handlers.get(service_name)
 +        result = dispatch(method, params)
  
          if rpc_request_flag or rpc_response_flag:
              end_time = time.time()
              end_rss, end_vms = 0, 0
 -            if psutil:
 -                end_rss, end_vms = psutil.Process(os.getpid()).get_memory_info()
 +            end_rss, end_vms = psutil.Process(os.getpid()).get_memory_info()
              logline = '%s.%s time:%.3fs mem: %sk -> %sk (diff: %sk)' % (service_name, method, end_time - start_time, start_vms / 1024, end_vms / 1024, (end_vms - start_vms)/1024)
              if rpc_response_flag:
                  log(rpc_response,logging.DEBUG, logline, result)
                  log(rpc_request,logging.DEBUG, logline, replace_request_password(params), depth=1)
  
          return result
 +    except openerp.osv.orm.except_orm:
 +        raise
      except openerp.exceptions.AccessError:
          raise
      except openerp.exceptions.AccessDenied:
          raise
      except openerp.exceptions.Warning:
          raise
 +    except openerp.exceptions.RedirectWarning:
 +        raise
      except openerp.exceptions.DeferredException, e:
          _logger.exception(tools.exception_to_unicode(e))
          post_mortem(e.traceback)
@@@ -1,4 -1,3 +1,3 @@@
- #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  ##############################################################################
  #
@@@ -141,6 -140,7 +140,6 @@@ from openerp.osv import field
  from openerp.osv.orm import MAGIC_COLUMNS
  import openerp.tools as tools
  
 -#.apidoc title: Domain Expressions
  
  # Domain operators.
  NOT_OPERATOR = '!'
@@@ -757,7 -757,7 +756,7 @@@ class expression(object)
              field_path = left.split('.', 1)
              field = working_model._columns.get(field_path[0])
              if field and field._obj:
 -                relational_model = working_model.pool.get(field._obj)
 +                relational_model = working_model.pool[field._obj]
              else:
                  relational_model = None
  
                  # comments about inherits'd fields
                  #  { 'field_name': ('parent_model', 'm2o_field_to_reach_parent',
                  #                    field_column_obj, origina_parent_model), ... }
 -                next_model = working_model.pool.get(working_model._inherit_fields[field_path[0]][0])
 +                next_model = working_model.pool[working_model._inherit_fields[field_path[0]][0]]
                  leaf.add_join_context(next_model, working_model._inherits[next_model._name], 'id', working_model._inherits[next_model._name])
                  push(leaf)
  
-             elif not field and left == 'id' and operator == 'child_of':
+             elif left == 'id' and operator == 'child_of':
                  ids2 = to_ids(right, working_model, context)
                  dom = child_of_domain(left, ids2, working_model)
                  for dom_leaf in reversed(dom):
@@@ -28,6 -28,7 +28,6 @@@ from reportlab import rl_confi
  
  from openerp.tools import config
  
 -#.apidoc title: TTF Font Table
  
  """This module allows the mapping of some system-available TTF fonts to
  the reportlab engine.
@@@ -56,7 -57,9 +56,9 @@@ CustomTTFonts = [ ('Helvetica',"DejaVu 
          ('Courier',"FreeMono", "FreeMono.ttf", 'normal'),
          ('Courier',"FreeMono Bold", "FreeMonoBold.ttf", 'bold'),
          ('Courier',"FreeMono Oblique", "FreeMonoOblique.ttf", 'italic'),
-         ('Courier',"FreeMono BoldOblique", "FreeMonoBoldOblique.ttf", 'bolditalic'),]
+         ('Courier',"FreeMono BoldOblique", "FreeMonoBoldOblique.ttf", 'bolditalic'),
+         ('Sun-ExtA',"Sun-ExtA", "sun-exta.ttf", 'normal'),
+ ]
  
  
  TTFSearchPath_Linux = [
@@@ -16,7 -16,7 +16,7 @@@
  #
  # You should have received a copy of the GNU Lesser General Public
  # License along with this library; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  #
  ##############################################################################
  
@@@ -115,11 -115,14 +115,11 @@@ def _process_text(self, txt)
              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, basestring):
 -                        txt = tools.ustr(txt)
 -                except Exception:
 -                    pass
 +                txt = None
 +                expr = sps.pop(0)
 +                txt = eval(expr, self.localcontext)
 +                if txt and isinstance(txt, basestring):
 +                    txt = tools.ustr(txt)
                  if isinstance(txt, basestring):
                      result += txt
                  elif txt and (txt is not None) and (txt is not False):
diff --combined openerp/service/cron.py
@@@ -1,4 -1,3 +1,3 @@@
- #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  ##############################################################################
  #
@@@ -45,7 -44,11 +44,7 @@@ def cron_runner(number)
          _logger.debug('cron%d polling for jobs', number)
          for db_name, registry in registries.items():
              while True and registry.ready:
 -                # acquired = openerp.addons.base.ir.ir_cron.ir_cron._acquire_job(db_name)
 -                # TODO why isnt openerp.addons.base defined ?
 -                import sys
 -                base = sys.modules['addons.base']
 -                acquired = base.ir.ir_cron.ir_cron._acquire_job(db_name)
 +                acquired = openerp.addons.base.ir.ir_cron.ir_cron._acquire_job(db_name)
                  if not acquired:
                      break
  
  #
  # You should have received a copy of the GNU General Public License
  # along with this program; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  ###############################################################################
  
 -#.apidoc title: HTTP and XML-RPC Server
  
  """ This module offers the family of HTTP-based servers. These are not a single
      class/functionality, but a set of network stack layers, implementing
  #
  # You should have received a copy of the GNU General Public License
  # along with this program; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  ###############################################################################
  
 -#.apidoc title: HTTP Layer library (websrv_lib)
  
  """ Framework for generic http servers
  
diff --combined setup.py
index 00bfa57,b53c9a4..28c78a9
mode 100755,100644..100644
+++ b/setup.py
@@@ -1,4 -1,3 +1,3 @@@
- #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  ##############################################################################
  #
@@@ -128,7 -127,6 +127,7 @@@ setuptools.setup
            'psutil', # windows binary code.google.com/p/psutil/downloads/list
            'psycopg2 >= 2.2',
            'pydot',
 +          'pyparsing < 2',
            'python-dateutil < 2',
            'python-ldap', # optional
            'python-openid',