From 47ca5f17737155a64d0b98466ecef496db3039ef Mon Sep 17 00:00:00 2001
From: Vincent Pelletier <vincent@nexedi.com>
Date: Fri, 8 Mar 2013 15:12:47 +0100
Subject: [PATCH] Fix magic "self" parameter detection.

Original code behaviour:
>>> def foo(self, a=None):
...    return 'works'
...
>>> context.foo(a=1)
works
>>> def foo(self, a):
...   return 'works'
...
>>> context.foo(1)
works
>>> context.foo(a=1)
TypeError: foo() takes exactly 2 non-keyword arguments (0 given)

New behaviour fixes this TypeError, to be closer to normal python
behaviour.
Also, original code was doing expensive checks before cheap ones.
---
 product/ERP5Type/patches/ExternalMethod.py | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/product/ERP5Type/patches/ExternalMethod.py b/product/ERP5Type/patches/ExternalMethod.py
index a7e2768f89..fcb6d8ab57 100644
--- a/product/ERP5Type/patches/ExternalMethod.py
+++ b/product/ERP5Type/patches/ExternalMethod.py
@@ -11,6 +11,7 @@
 #
 ##############################################################################
 
+from inspect import getargspec
 from Products.ExternalMethod.ExternalMethod import *
 
 if 1:
@@ -65,6 +66,8 @@ if 1:
           Component Extension if available, otherwise fallback on filesystem
           Extension
         - access volatile attribute safely
+        - fix magic "self" argument when positional arguments get their values
+          from kw.
         """
         try:
             f = getattr(__import__('erp5.component.extension.' + self._module,
@@ -103,9 +106,13 @@ if 1:
         except TypeError, v:
             tb=sys.exc_info()[2]
             try:
-                if ((self._v_func_code.co_argcount-
-                     len(self._v_func_defaults or ()) - 1 == len(args))
-                    and self._v_func_code.co_varnames[0]=='self'):
+                func_args, func_varargs, _, func_defaults = getargspec(f)
+                by_kw = set(kw)
+                if func_defaults:
+                    by_kw.update(func_args[-len(func_defaults):])
+                if func_args[0] == 'self' and 'self' not in kw and (
+                        func_varargs or len(set(func_args[len(args):]
+                            ).difference(by_kw)) == 1):
                     return f(self.aq_parent.this(), *args, **kw)
 
                 raise TypeError, v, tb
-- 
2.30.9