4 new revisions:

Revision: 387e1cf4dc70
Branch:   default
Author:   Pekka Klärck
Date:     Thu Nov 21 09:41:12 2013 UTC
Log: atests: Combined dynamic library invalid argpspec tests and cleaned th...
http://code.google.com/p/robotframework/source/detail?r=387e1cf4dc70

Revision: 3d9d713eb6b1
Branch:   default
Author:   Pekka Klärck
Date:     Thu Nov 21 10:05:15 2013 UTC
Log:      Cleaned up dynamic library atests...
http://code.google.com/p/robotframework/source/detail?r=3d9d713eb6b1

Revision: 54ed6c9c33cf
Branch:   default
Author:   Pekka Klärck
Date:     Thu Nov 21 12:26:42 2013 UTC
Log: Dynamic libs: return '*varargs' instead of '*unknown' when no arg spec...
http://code.google.com/p/robotframework/source/detail?r=54ed6c9c33cf

Revision: e3ae9ca64a98
Branch:   default
Author:   Pekka Klärck
Date:     Thu Nov 21 12:51:47 2013 UTC
Log: Dynamic libs: Refactored detecting does run_keyword support **kwargs...
http://code.google.com/p/robotframework/source/detail?r=e3ae9ca64a98

==============================================================================
Revision: 387e1cf4dc70
Branch:   default
Author:   Pekka Klärck
Date:     Thu Nov 21 09:41:12 2013 UTC
Log: atests: Combined dynamic library invalid argpspec tests and cleaned them up in general.

Update issue 1500
Combined invalid argspec tests.
http://code.google.com/p/robotframework/source/detail?r=387e1cf4dc70

Added:
 /atest/testdata/test_libraries/dynamic_libraries/InvalidArgSpecs.py
Deleted:
 /atest/robot/test_libraries/dynamic_kwargs_support_with_invalid_argspec.txt
/atest/testdata/test_libraries/dynamic_kwargs_support_with_invalid_argspec.txt
 /atest/testdata/test_libraries/dynamic_libraries/DynamicLibrary.py
/atest/testdata/test_libraries/dynamic_libraries/DynamicLibraryWithKwargsSupport.py
Modified:
 /atest/robot/test_libraries/dynamic_libraries_with_invalid_argspec.txt
 /atest/testdata/test_libraries/dynamic_libraries_with_invalid_argspec.txt

=======================================
--- /dev/null
+++ /atest/testdata/test_libraries/dynamic_libraries/InvalidArgSpecs.py Thu Nov 21 09:41:12 2013 UTC
@@ -0,0 +1,20 @@
+KEYWORDS = [('argspec with other than strings', [1, 2]),
+            ('named args before positional', ['a=1', 'b']),
+            ('varargs before positional args', ['*varargs', 'a']),
+            ('varargs before named args', ['*varargs', 'a=1']),
+            ('kwargs before positional args', ['**kwargs', 'a']),
+            ('kwargs before named args', ['**kwargs', 'a=1']),
+            ('kwargs before varargs', ['**kwargs', '*varargs']),
+            ('valid argspec', ['a'])]
+
+
+class InvalidArgSpecs(object):
+
+    def get_keyword_names(self):
+        return [name for name, _ in KEYWORDS]
+
+    def run_keyword(self, name, args, kwargs):
+        return ''.join(args + tuple(kwargs)).upper()
+
+    def get_keyword_arguments(self, name):
+        return dict(KEYWORDS)[name]
=======================================
--- /atest/robot/test_libraries/dynamic_kwargs_support_with_invalid_argspec.txt Wed Nov 20 17:05:12 2013 UTC
+++ /dev/null
@@ -1,28 +0,0 @@
-# TODO: Move these tests to dynamic_libraries_with_invalid_argspec.txt
-
-*** Settings ***
-Suite Setup Run Tests ${EMPTY} test_libraries/dynamic_kwargs_support_with_invalid_argspec.txt
-Force Tags      regression  jybot  pybot
-Resource        atest_resource.txt
-
-*** Test Cases ***
-
-Argspec has kwargs before positional arguments
-    Error message should be correct    1    kwargs before positional args
-    ...    Only last argument can be kwargs.
-
-Argspec has kwargs before named arguments
-    Error message should be correct    0    kwargs before named args
-    ...    Only last argument can be kwargs.
-
-Argspec has kwargs before varargs
-    Error message should be correct    2    kwargs before varargs
-    ...    Only last argument can be kwargs.
-
-
-*** Keywords ***
-
-Error message should be correct
-    [Arguments]    ${index}    ${kw}    ${msg}
-    Check Test Case    ${TESTNAME}
- Check Log Message ${ERRORS[${index}]} Adding keyword '${kw}' to library 'DynamicLibraryWithKwargsSupport' failed: ${msg} WARN
=======================================
--- /atest/testdata/test_libraries/dynamic_kwargs_support_with_invalid_argspec.txt Wed Nov 20 17:05:12 2013 UTC
+++ /dev/null
@@ -1,16 +0,0 @@
-*** Settings ***
-Library         dynamic_libraries/DynamicLibraryWithKwargsSupport.py
-
-*** Test Cases ***
-
-Argspec has kwargs before positional arguments
- [Documentation] FAIL No keyword with name 'Kwargs Before Positional Args' found.
-    Kwargs Before Positional Args
-
-Argspec has kwargs before named arguments
- [Documentation] FAIL No keyword with name 'Kwargs Before Named Args' found.
-    Kwargs Before Named Args
-
-Argspec has kwargs before varargs
- [Documentation] FAIL No keyword with name 'Kwargs Before Varargs' found.
-    Kwargs Before Varargs
=======================================
--- /atest/testdata/test_libraries/dynamic_libraries/DynamicLibrary.py Wed Nov 20 17:05:12 2013 UTC
+++ /dev/null
@@ -1,20 +0,0 @@
-# TODO: Move code to run_keyword
-
-KEYWORDS = {
-    'argspec with other than strings': (lambda a, *x: (a, x), [1, 2]),
- 'varargs before positional args': (lambda a, *x: (a, x), ['*varargs', 'a']), - 'varargs before named args': (lambda a=1, *x: (a, x), ['*varargs', 'a=1']),
-    'named args before positional': (lambda a, b: (a, b), ['a=1', 'b']),
-    'method': (lambda a: a, ['a'])
-}
-
-class DynamicLibrary(object):
-
-    def get_keyword_names(self):
-        return sorted(KEYWORDS)
-
-    def run_keyword(self, kw_name, args):
-        KEYWORDS[kw_name][0](*args)
-
-    def get_keyword_arguments(self, kw_name):
-        return KEYWORDS[kw_name][1]
=======================================
--- /atest/testdata/test_libraries/dynamic_libraries/DynamicLibraryWithKwargsSupport.py Wed Nov 20 17:05:12 2013 UTC
+++ /dev/null
@@ -1,18 +0,0 @@
-# TODO: Rename to DynamicLibraryWithInvalidArgSpec
-# Also, run_keyword can just pass...
-KEYWORDS = {
- 'kwargs before positional args': (lambda a, *x: (a, x), ['**kwargs', 'a']), - 'kwargs before named args': (lambda a=1, *x: (a, x), ['**kwargs', 'a=1']), - 'kwargs before varargs': (lambda a=1, *x: (a, x), ['**kwargs', '*varargs']),
-}
-
-class DynamicLibraryWithKwargsSupport(object):
-
-    def get_keyword_names(self):
-        return sorted(KEYWORDS)
-
-    def run_keyword(self, kw_name, args, kwargs):
-        return KEYWORDS[kw_name][0](*args, **kwargs)
-
-    def get_keyword_arguments(self, kw_name):
-        return KEYWORDS[kw_name][1]
=======================================
--- /atest/robot/test_libraries/dynamic_libraries_with_invalid_argspec.txt Wed Aug 7 21:31:57 2013 UTC +++ /atest/robot/test_libraries/dynamic_libraries_with_invalid_argspec.txt Thu Nov 21 09:41:12 2013 UTC
@@ -4,27 +4,39 @@
 Resource        atest_resource.txt

 *** Test Cases ***
-
 Argspec consists of something else than strings
     Error message should be correct    0    argspec with other than strings
... Calling dynamic method 'get_keyword_arguments' failed: Return value must be list of strings.

+Argspec has named arguments before positional
+    Error message should be correct    1    named args before positional
+    ...     Non-default argument after default arguments.
+
 Argspec has varargs before positional arguments
-    Error message should be correct    3    varargs before positional args
+    Error message should be correct    2    varargs before positional args
     ...    Positional argument after varargs.

 Argspec has varargs before named arguments
-    Error message should be correct    2    varargs before named args
+    Error message should be correct    3    varargs before named args
     ...    Positional argument after varargs.

-Argspec has named arguments before positional
-    Error message should be correct    1    named args before positional
-    ...     Non-default argument after default arguments.
+Argspec has kwargs before positional arguments
+    Error message should be correct    4    kwargs before positional args
+    ...    Only last argument can be kwargs.

+Argspec has kwargs before named arguments
+    Error message should be correct    5    kwargs before named args
+    ...    Only last argument can be kwargs.
+
+Argspec has kwargs before varargs
+    Error message should be correct    6    kwargs before varargs
+    ...    Only last argument can be kwargs.
+
+Keywords with valid arg spec can be used
+    Check Test Case

 *** Keywords ***
-
 Error message should be correct
     [Arguments]    ${index}    ${kw}    ${msg}
     Check Test Case    ${TESTNAME}
- Check Log Message ${ERRORS[${index}]} Adding keyword '${kw}' to library 'DynamicLibrary' failed: ${msg} WARN + Check Log Message ${ERRORS[${index}]} Adding keyword '${kw}' to library 'InvalidArgSpecs' failed: ${msg} WARN
=======================================
--- /atest/testdata/test_libraries/dynamic_libraries_with_invalid_argspec.txt Thu Apr 25 11:35:28 2013 UTC +++ /atest/testdata/test_libraries/dynamic_libraries_with_invalid_argspec.txt Thu Nov 21 09:41:12 2013 UTC
@@ -1,5 +1,5 @@
 *** Settings ***
-Library         ${CURDIR}/dynamic_libraries/DynamicLibrary.py
+Library         dynamic_libraries/InvalidArgSpecs.py

 *** Test Cases ***

@@ -7,6 +7,10 @@
[Documentation] FAIL No keyword with name 'Argspec With Other Than Strings' found.
     Argspec With Other Than Strings

+Argspec has named arguments before positional
+ [Documentation] FAIL No keyword with name 'Named Args Before Positional' found.
+    Named Args Before Positional
+
 Argspec has varargs before positional arguments
[Documentation] FAIL No keyword with name 'Varargs Before Positional Args' found.
     Varargs Before Positional Args
@@ -15,6 +19,18 @@
[Documentation] FAIL No keyword with name 'Varargs Before Named Args' found.
     Varargs Before Named Args

-Argspec has named arguments before positional
- [Documentation] FAIL No keyword with name 'Named Args Before Positional' found.
-    Named Args Before Positional
+Argspec has kwargs before positional arguments
+ [Documentation] FAIL No keyword with name 'Kwargs Before Positional Args' found.
+    Kwargs Before Positional Args
+
+Argspec has kwargs before named arguments
+ [Documentation] FAIL No keyword with name 'Kwargs Before Named Args' found.
+    Kwargs Before Named Args
+
+Argspec has kwargs before varargs
+ [Documentation] FAIL No keyword with name 'Kwargs Before Varargs' found.
+    Kwargs Before Varargs
+
+Keywords with valid arg spec can be used
+    ${ret} =    Valid argspec    Hello!
+    Should be equal    ${ret}    HELLO!

==============================================================================
Revision: 3d9d713eb6b1
Branch:   default
Author:   Pekka Klärck
Date:     Thu Nov 21 10:05:15 2013 UTC
Log:      Cleaned up dynamic library atests

Update issue 1500
Further test cleanup
http://code.google.com/p/robotframework/source/detail?r=3d9d713eb6b1

Deleted:
 /atest/testdata/keywords/named_args/dynamic_library_impl.py
Modified:
 /atest/testdata/keywords/named_args/DynamicLibrary.py
 /atest/testdata/keywords/named_args/DynamicLibraryWithKwargsSupport.py
 /atest/testdata/keywords/named_args/with_dynamic_keywords.txt
/atest/testdata/test_libraries/dynamic_libraries/DynamicLibraryWithKwargsSupportWithoutArgspec.py /atest/testdata/test_libraries/dynamic_libraries/DynamicLibraryWithoutArgspec.py

=======================================
--- /atest/testdata/keywords/named_args/dynamic_library_impl.py Wed Nov 20 17:05:12 2013 UTC
+++ /dev/null
@@ -1,12 +0,0 @@
-from helper import pretty
-
-# TODO: This file is not really needed. Dynamic libs should do this themselves.
-
-def var_args(*varargs, **kwargs):
-    return pretty(*varargs, **kwargs)
-
-def return_argument(arg):
-    return arg
-
-def return_arguments(*args):
-    return args
=======================================
--- /atest/testdata/keywords/named_args/DynamicLibrary.py Wed Nov 20 17:05:12 2013 UTC +++ /atest/testdata/keywords/named_args/DynamicLibrary.py Thu Nov 21 10:05:15 2013 UTC
@@ -1,20 +1,19 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
+from helper import pretty

-from dynamic_library_impl import var_args, return_argument, return_arguments
-

 KEYWORDS = {
- 'Escaped Default Value': (var_args, ['d1=${notvariable}', 'd2=\\\\', 'd3=\n', 'd4=\t']), - 'Four Kw Args': (var_args, ['a=default', 'b=default', 'c=default', 'd=default']), - 'Mandatory, Named And Varargs': (var_args, ['a', 'b=default', '*varargs']), - 'Mandatory And Kwargs': (var_args, ['man1', 'man2', 'kwarg=KWARG VALUE']),
-    'Mandatory And Named': (var_args, ['a', 'b=default']),
- 'Named Arguments With Varargs': (return_arguments, ['a=default', 'b=default', '*varargs']),
-    'One Kwarg Returned': (return_argument, ['kwarg=']),
-    'Two Kwargs': (var_args, ['first=', 'second=']),
-    u'Nön äscii named args': (var_args, [u'nönäscii=', u'官话=']),
-    'three named': (var_args, ['a=a', 'b=b', 'c=c'])
+ 'Escaped Default Value': ['d1=${notvariable}', 'd2=\\\\', 'd3=\n', 'd4=\t'],
+    'Four Kw Args': ['a=default', 'b=default', 'c=default', 'd=default'],
+    'Mandatory, Named And Varargs': ['a', 'b=default', '*varargs'],
+    'Mandatory And Kwargs': ['man1', 'man2', 'kwarg=KWARG VALUE'],
+    'Mandatory And Named': ['a', 'b=default'],
+    'Named Arguments With Varargs': ['a=default', 'b=default', '*varargs'],
+    'One Kwarg Returned': ['kwarg='],
+    'Two Kwargs': ['first=', 'second='],
+    u'Nön äscii named args': [u'nönäscii=', u'官话='],
+    'three named': ['a=a', 'b=b', 'c=c']
 }


@@ -27,7 +26,12 @@
         return self.keywords.keys()

     def run_keyword(self, kw_name, args):
-        return self.keywords[kw_name][0](*args)
+        return self._pretty(*args)
+
+    def _pretty(self, *args, **kwargs):
+        if all(isinstance(a, basestring) for a in args):
+            return pretty(*args, **kwargs)
+        return args[0] if len(args) == 1 else args

     def get_keyword_arguments(self, kw_name):
-        return self.keywords[kw_name][1]
+        return self.keywords[kw_name]
=======================================
--- /atest/testdata/keywords/named_args/DynamicLibraryWithKwargsSupport.py Wed Nov 20 17:05:12 2013 UTC +++ /atest/testdata/keywords/named_args/DynamicLibraryWithKwargsSupport.py Thu Nov 21 10:05:15 2013 UTC
@@ -1,9 +1,8 @@
-from dynamic_library_impl import var_args
 from DynamicLibrary import DynamicLibrary

 KEYWORDS = {
- 'Mandatory, Named And Kwargs': (var_args, ['a', 'b=default', '**kwargs']), - 'Mandatory, Named, Varargs And Kwargs': (var_args, ['a', 'b=default', '*varargs', '**kwargs']),
+    'Mandatory, Named And Kwargs': ['a', 'b=default', '**kwargs'],
+ 'Mandatory, Named, Varargs And Kwargs': ['a', 'b=default', '*varargs', '**kwargs'],
 }


@@ -13,4 +12,4 @@
         DynamicLibrary.__init__(self, **KEYWORDS)

     def run_keyword(self, name, args, kwargs):
-        return self.keywords[name][0](*args, **kwargs)
+        return self._pretty(*args, **kwargs)
=======================================
--- /atest/testdata/keywords/named_args/with_dynamic_keywords.txt Tue Sep 24 09:38:39 2013 UTC +++ /atest/testdata/keywords/named_args/with_dynamic_keywords.txt Thu Nov 21 10:05:15 2013 UTC
@@ -45,16 +45,16 @@
     Should Be Equal    ${ret}    \${notvariable}, \\\\, \n, \${nv}

 Varargs without naming arguments works
-    @{ret} =    Named arguments with varargs    foo    bar    dar
-    Should be equal    @{ret}[0]    foo
-    @{ret} =    Named arguments with varargs    foo    bar=bar    dar
-    Should be equal    @{ret}[1]    bar=bar
-    @{ret} =    Named arguments with varargs    foo    b\=bar    dar
-    Should be equal    @{ret}[1]    b=bar
+    ${ret} =    Named arguments with varargs    foo    bar    dar
+    Should be equal    ${ret}     foo, bar, dar
+    ${ret} =    Named arguments with varargs    foo    bar=bar    dar
+    Should be equal    ${ret}     foo, bar=bar, dar
+    ${ret} =    Named arguments with varargs    foo    b\=bar    dar
+    Should be equal    ${ret}     foo, b=bar, dar

 Naming without the varargs works
-    @{ret} =    Named arguments with varargs    foo    b=bar
-    Should be equal    @{ret}[1]    bar
+    ${ret} =    Named arguments with varargs    foo    b=bar
+    Should be equal    ${ret}     foo, bar

 Varargs with naming does not work
[documentation] FAIL Keyword '${DynamicLibrary}.Named Arguments With Varargs' got positional argument after named arguments.
=======================================
--- /atest/testdata/test_libraries/dynamic_libraries/DynamicLibraryWithKwargsSupportWithoutArgspec.py Wed Nov 20 17:05:12 2013 UTC +++ /atest/testdata/test_libraries/dynamic_libraries/DynamicLibraryWithKwargsSupportWithoutArgspec.py Thu Nov 21 10:05:15 2013 UTC
@@ -1,23 +1,10 @@
-import sys
-import os
+from DynamicLibraryWithoutArgspec import DynamicLibraryWithoutArgspec

-# TODO: 1) Is sys.path.insert really needed?
-# TODO: 2) Should not update KEYWORDS without copying it first.
-# TODO: 3) See also DynamicLibraryWithoutArgspec

-sys.path.insert(0, os.path.dirname(__file__))
-from DynamicLibraryWithoutArgspec import (
-  KEYWORDS, DynamicLibraryWithoutArgspec)
+class DynamicLibraryWithKwargsSupportWithoutArgspec(DynamicLibraryWithoutArgspec):

+    def run_keyword(self, name, args, kwargs):
+        return getattr(self, name)(*args, **kwargs)

-def do_something_with_kwargs(a, b=2, c=3, **kwargs):
-    print a, b, c, ' '.join('%s:%s' % (k, v) for k, v in kwargs.items())
-
-KEYWORDS.update({
-    'do_something_with_kwargs': do_something_with_kwargs,
-})
-
-class DynamicLibraryWithKwargsSupportWithoutArgspec(DynamicLibraryWithoutArgspec):
-
-    def run_keyword(self, kw_name, args, kwargs):
-        return KEYWORDS[kw_name](*args, **kwargs)
+    def do_something_with_kwargs(self, a, b=2, c=3, **kwargs):
+ print a, b, c, ' '.join('%s:%s' % (k, v) for k, v in kwargs.items())
=======================================
--- /atest/testdata/test_libraries/dynamic_libraries/DynamicLibraryWithoutArgspec.py Wed Nov 20 17:05:12 2013 UTC +++ /atest/testdata/test_libraries/dynamic_libraries/DynamicLibraryWithoutArgspec.py Thu Nov 21 10:05:15 2013 UTC
@@ -1,22 +1,16 @@
-# TODO: Move actual code to run_keyword
-def do_something(x):
-    print x
+class DynamicLibraryWithoutArgspec(object):

-def do_something_else(x, y=0):
-    print 'x: %s, y: %s' % (x, y)
+    def get_keyword_names(self):
+        return [name for name in dir(self) if name.startswith('do_')]

-def do_something_third(a, b=2, c=3):
-    print a, b, c
+    def run_keyword(self, name, args):
+        return getattr(self, name)(*args)

-KEYWORDS = {
-    'do_something': do_something,
-    'do_something_else': do_something_else,
-    'do_something_third': do_something_third
-}
+    def do_something(self, x):
+        print x

-class DynamicLibraryWithoutArgspec(object):
-    def get_keyword_names(self):
-        return KEYWORDS.keys()
+    def do_something_else(self, x, y=0):
+        print 'x: %s, y: %s' % (x, y)

-    def run_keyword(self, kw_name, args):
-        KEYWORDS[kw_name](*args)
+    def do_something_third(self, a, b=2, c=3):
+        print a, b, c

==============================================================================
Revision: 54ed6c9c33cf
Branch:   default
Author:   Pekka Klärck
Date:     Thu Nov 21 12:26:42 2013 UTC
Log: Dynamic libs: return '*varargs' instead of '*unknown' when no arg spec.

Also tested this better.

Update issue 1500
Return '*varargs, **kwargs' and not '*unknown, **kwargs' if there is no arg spec.
http://code.google.com/p/robotframework/source/detail?r=54ed6c9c33cf

Modified:
 /atest/robot/libdoc/dynamic_library_with_args.txt
 /atest/testdata/libdoc/DynamicLibrary.py
 /src/robot/running/dynamicmethods.py
 /utest/running/test_handlers.py

=======================================
--- /atest/robot/libdoc/dynamic_library_with_args.txt Mon May 6 12:19:31 2013 UTC +++ /atest/robot/libdoc/dynamic_library_with_args.txt Thu Nov 21 12:26:42 2013 UTC
@@ -47,4 +47,7 @@
     Keyword Doc Should Start With    2   Dummy documentation for `KW2`.

 Non ASCII
-    Keyword Doc Should Be    3    Hyvää yötä.\n\nСпасибо!
+    Keyword Doc Should Be    4    Hyvää yötä.\n\nСпасибо!
+
+No Argspec
+    Keyword Arguments Should be     3     *varargs   **kwargs
=======================================
--- /atest/testdata/libdoc/DynamicLibrary.py    Tue Feb 14 11:59:52 2012 UTC
+++ /atest/testdata/libdoc/DynamicLibrary.py    Thu Nov 21 12:26:42 2013 UTC
@@ -8,12 +8,14 @@
         """This is overwritten and not shown in docs"""

     def get_keyword_names(self):
-        return ['0', 'Keyword 1', 'KW2', 'non ascii doc 42']
+        return ['0', 'Keyword 1', 'KW2', 'non ascii doc 42', 'no arg spec']

-    def run_keyword(self, name, args):
+    def run_keyword(self, name, args, kwargs):
         print name, args

     def get_keyword_arguments(self, name):
+        if name == 'no arg spec':
+            return None
         return ['arg%d' % (i+1) for i in range(int(name[-1]))]

     def get_keyword_documentation(self, name):
=======================================
--- /src/robot/running/dynamicmethods.py        Wed Nov 20 17:05:12 2013 UTC
+++ /src/robot/running/dynamicmethods.py        Thu Nov 21 12:26:42 2013 UTC
@@ -102,8 +102,7 @@

     def _handle_return_value(self, value):
         if value is None:
-             # TODO: Use *varargs, **kwargs or *unknown, **unknown
             if self._kwargs_support:
-                return ['*unknown', '**kwargs']
-            return ['*unknown']
+                return ['*varargs', '**kwargs']
+            return ['*varargs']
         return self._to_list_of_strings(value)
=======================================
--- /utest/running/test_handlers.py     Wed Nov 20 17:05:12 2013 UTC
+++ /utest/running/test_handlers.py     Thu Nov 21 12:26:42 2013 UTC
@@ -93,7 +93,10 @@
         self._assert_fails('Return value must be string.', doc=True)

     def test_none_argspec(self):
-        self._assert_spec(None, maxargs=sys.maxint,vararg='unknown')
+ self._assert_spec(None, maxargs=sys.maxint, vararg='varargs', kwarg=False)
+
+    def test_none_argspec_when_kwargs_supported(self):
+ self._assert_spec(None, maxargs=sys.maxint, vararg='varargs', kwarg='kwargs')

     def test_empty_argspec(self):
         self._assert_spec([])
@@ -160,7 +163,14 @@

     def _assert_spec(self, argspec, minargs=0, maxargs=0, positional=[],
                      defaults=[], vararg=None, kwarg=None):
-        for kwargs_support in [True, False] if not kwarg else [True]:
+        if kwarg is None:
+            kwargs_support_modes = [True, False]
+        elif kwarg is False:
+            kwargs_support_modes = [False]
+            kwarg = None
+        else:
+            kwargs_support_modes = [True]
+        for kwargs_support in kwargs_support_modes:
             arguments = self._create_handler(argspec,
                                              kwargs_support=kwargs_support
                                              ).arguments
@@ -176,14 +186,14 @@
                                self._create_handler, argspec, doc)

def _create_handler(self, argspec=None, doc=None, kwargs_support=False):
-        doc = GetKeywordDocumentation(lib=None)._handle_return_value(doc)
- argspec = GetKeywordArguments(lib=None)._handle_return_value(argspec)
+        lib = LibraryMock('TEST CASE')
         if kwargs_support:
-            handler_func = lambda name, args, kwargs: None
+            lib.run_keyword = lambda name, args, kwargs: None
         else:
-            handler_func = lambda name, args: None
- return DynamicHandler(LibraryMock('TEST CASE'), 'mock', handler_func,
-                              doc, argspec)
+            lib.run_keyword = lambda name, args: None
+        doc = GetKeywordDocumentation(lib)._handle_return_value(doc)
+        argspec = GetKeywordArguments(lib)._handle_return_value(argspec)
+        return DynamicHandler(lib, 'mock', lib.run_keyword, doc, argspec)


 if utils.is_jython:
@@ -209,7 +219,7 @@

         def test_arg_limits_with_defaults(self):
             # defaults i.e. multiple signatures
-            for mina, maxa in [(0,1), (1,3)]:
+            for mina, maxa in [(0, 1), (1, 3)]:
                 method = handlers['a_%d_%d' % (mina, maxa)]
handler = _JavaHandler(LibraryMock(), method.__name__, method)
                 assert_equals(handler.arguments.minargs, mina)

==============================================================================
Revision: e3ae9ca64a98
Branch:   default
Author:   Pekka Klärck
Date:     Thu Nov 21 12:51:47 2013 UTC
Log: Dynamic libs: Refactored detecting does run_keyword support **kwargs

Update issue 1500
Refactored detecting does run_keyword support **kwargs. Now RunKeyword knows it and we also got rid off DynamicMethodArgumentParser.

We did some changes to internal APIs to make the code cleaner, but those changes should not matter to anyone using Robot.

We have now gone through all the TODOs we added to tests and code while merging in the original code. Next up is reviewing the docs. After that this issue ought to be done. Comments from Stefan regarding to our changes are obviously welcome.
http://code.google.com/p/robotframework/source/detail?r=e3ae9ca64a98

Added:
 /src/robot/utils/robotinspect.py
Modified:
 /atest/testresources/testlibs/classes.py
 /src/robot/running/arguments/__init__.py
 /src/robot/running/arguments/argumentparser.py
 /src/robot/running/dynamicmethods.py
 /src/robot/running/handlers.py
 /src/robot/running/testlibraries.py
 /src/robot/running/userkeyword.py
 /src/robot/utils/__init__.py
 /utest/running/test_handlers.py
 /utest/running/test_userhandlers.py

=======================================
--- /dev/null
+++ /src/robot/utils/robotinspect.py    Thu Nov 21 12:51:47 2013 UTC
@@ -0,0 +1,34 @@
+#  Copyright 2008-2013 Nokia Siemens Networks Oyj
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import sys
+
+
+if sys.platform.startswith('java'):
+    from org.python.core import PyReflectedFunction, PyReflectedConstructor
+
+    def is_java_init(init):
+        return isinstance(init, PyReflectedConstructor)
+
+    def is_java_method(method):
+        return hasattr(method, 'im_func') \
+            and isinstance(method.im_func, PyReflectedFunction)
+
+else:
+
+    def is_java_init(init):
+        return False
+
+    def is_java_method(method):
+        return False
=======================================
--- /atest/testresources/testlibs/classes.py    Wed Nov 20 17:05:12 2013 UTC
+++ /atest/testresources/testlibs/classes.py    Thu Nov 21 12:51:47 2013 UTC
@@ -158,7 +158,7 @@
('Varargs and Kwargs', ['*args', '**kwargs'])]:
             self._keywords[name] = _KeywordInfo(name, argspec)

-    def run_keyword(self, name, args, kwargs):
+    def run_keyword(self, name, args, kwargs={}):
         argstr = ' '.join([str(a) for a in args] +
                           ['%s:%s' % kv for kv in sorted(kwargs.items())])
print '*INFO* Executed keyword %s with arguments %s' % (name, argstr)
=======================================
--- /src/robot/running/arguments/__init__.py    Tue Oct  1 09:50:04 2013 UTC
+++ /src/robot/running/arguments/__init__.py    Thu Nov 21 12:51:47 2013 UTC
@@ -16,8 +16,7 @@

 from .argumentmapper import ArgumentMapper
from .argumentparser import (PythonArgumentParser, UserKeywordArgumentParser,
-                             DynamicArgumentParser, JavaArgumentParser,
-                             DynamicMethodArgumentParser)
+                             DynamicArgumentParser, JavaArgumentParser)
 from .argumentresolver import ArgumentResolver
 from .argumentvalidator import ArgumentValidator
 if sys.platform.startswith('java'):
=======================================
--- /src/robot/running/arguments/argumentparser.py Wed Nov 20 17:05:12 2013 UTC +++ /src/robot/running/arguments/argumentparser.py Thu Nov 21 12:51:47 2013 UTC
@@ -25,7 +25,7 @@
     def __init__(self, type='Keyword'):
         self._type = type

-    def parse(self, name, source):
+    def parse(self, source, name=None):
         return ArgumentSpec(name, self._type, *self._get_arg_spec(source))

     def _get_arg_spec(self, source):
@@ -77,33 +77,9 @@
         return positional, defaults, varargs


-# TODO: Could this be implemented as a helper method instead of a class?
-# Current name isn't ideal anyway.
-class DynamicMethodArgumentParser(PythonArgumentParser, JavaArgumentParser):
-    """A generic argument parser for Dynamic Test Library API methods
-       like run(_k|K)eyword, which can be either Python or Java based.
-    """
-    def __init__(self):
-        _ArgumentParser.__init__(self, 'DynamicMethod')
-
-    def _get_arg_spec(self, method):
-        try:
-            return PythonArgumentParser._get_arg_spec(self, method)
-        except TypeError, err:
-            if sys.platform.startswith('java'):
-                try:
-                    # Adapted from _JavaHandler._get_signatures():
-                    func = method.im_func
-                    signatures = func.argslist[:func.nargs]
-                except AttributeError:
-                    raise err
-                return JavaArgumentParser._get_arg_spec(self, signatures)
-            raise err
-
-
 class _ArgumentSpecParser(_ArgumentParser):

-    def parse(self, name, argspec):
+    def parse(self, argspec, name=None):
         result = ArgumentSpec(name, self._type)
         for arg in argspec:
             if result.kwargs:
=======================================
--- /src/robot/running/dynamicmethods.py        Thu Nov 21 12:26:42 2013 UTC
+++ /src/robot/running/dynamicmethods.py        Thu Nov 21 12:51:47 2013 UTC
@@ -13,9 +13,9 @@
 #  limitations under the License.

 from robot.errors import DataError
-from robot.utils import get_error_message, unic
+from robot.utils import get_error_message, unic, is_java_method

-from .arguments import DynamicMethodArgumentParser
+from .arguments import JavaArgumentParser, PythonArgumentParser


 def no_dynamic_method(*args):
@@ -40,6 +40,10 @@
         tokens = self._underscore_name.split('_')
         return ''.join([tokens[0]] + [t.capitalize() for t in tokens[1:]])

+    @property
+    def name(self):
+        return self.method.__name__
+
     def __call__(self, *args):
         try:
             return self._handle_return_value(self.method(*args))
@@ -75,6 +79,18 @@
 class RunKeyword(_DynamicMethod):
     _underscore_name = 'run_keyword'

+    def __init__(self, lib):
+        _DynamicMethod.__init__(self, lib)
+        argspec = self._parse_argspec(self.method)
+        self.kwargs_supported = len(argspec.positional) == 3
+
+    def _parse_argspec(self, method):
+        if not is_java_method(method):
+            return PythonArgumentParser().parse(method)
+        func = method.im_func
+        signatures = func.argslist[:func.nargs]
+        return JavaArgumentParser().parse(signatures)
+

 class GetKeywordDocumentation(_DynamicMethod):
     _underscore_name = 'get_keyword_documentation'
@@ -88,21 +104,11 @@

     def __init__(self, lib):
         _DynamicMethod.__init__(self, lib)
-        # Check if the lib's run_keyword method supports **kwargs
-        # (self, name, args, kwargs)
-        # TODO: Extract method
-        run_keyword_method = RunKeyword(lib).method
-        if run_keyword_method is not no_dynamic_method:
-            argspec = DynamicMethodArgumentParser().parse(
-              'run_keyword', run_keyword_method)
-            if len(argspec.positional) > 2:
-                self._kwargs_support = True
-                return
-        self._kwargs_support = False
+        self._kwargs_supported = RunKeyword(lib).kwargs_supported

     def _handle_return_value(self, value):
         if value is None:
-            if self._kwargs_support:
+            if self._kwargs_supported:
                 return ['*varargs', '**kwargs']
             return ['*varargs']
         return self._to_list_of_strings(value)
=======================================
--- /src/robot/running/handlers.py      Wed Nov 20 17:05:12 2013 UTC
+++ /src/robot/running/handlers.py      Thu Nov 21 12:51:47 2013 UTC
@@ -20,30 +20,19 @@

 from .arguments import (PythonArgumentParser, JavaArgumentParser,
                         DynamicArgumentParser, ArgumentResolver,
-                        ArgumentMapper, JavaArgumentCoercer,
-                        DynamicMethodArgumentParser)
+                        ArgumentMapper, JavaArgumentCoercer)
 from .keywords import Keywords, Keyword
 from .outputcapture import OutputCapturer
 from .runkwregister import RUN_KW_REGISTER
 from .signalhandler import STOP_SIGNAL_MONITOR


-if utils.is_jython:
-    from org.python.core import PyReflectedFunction, PyReflectedConstructor

-    def _is_java_init(init):
-        return isinstance(init, PyReflectedConstructor)
-    def _is_java_method(method):
-        return hasattr(method, 'im_func') \
-               and isinstance(method.im_func, PyReflectedFunction)
-else:
-    _is_java_init = _is_java_method = lambda item: False
-

 def Handler(library, name, method):
     if RUN_KW_REGISTER.is_run_keyword(library.orig_name, name):
         return _RunKeywordHandler(library, name, method)
-    if _is_java_method(method):
+    if utils.is_java_method(method):
         return _JavaHandler(library, name, method)
     else:
         return _PythonHandler(library, name, method)
@@ -56,7 +45,7 @@


 def InitHandler(library, method, docgetter=None):
- Init = _PythonInitHandler if not _is_java_init(method) else _JavaInitHandler + Init = _PythonInitHandler if not utils.is_java_init(method) else _JavaInitHandler
     return Init(library, '__init__', method, docgetter)


@@ -177,7 +166,7 @@
         self._doc = utils.getdoc(handler_method)

     def _parse_arguments(self, handler_method):
-        return PythonArgumentParser().parse(self.longname, handler_method)
+        return PythonArgumentParser().parse(handler_method, self.longname)


 class _JavaHandler(_RunnableHandler):
@@ -189,7 +178,7 @@

     def _parse_arguments(self, handler_method):
         signatures = self._get_signatures(handler_method)
-        return JavaArgumentParser().parse(self.longname, signatures)
+        return JavaArgumentParser().parse(signatures, self.longname)

     def _get_argument_resolver(self, argspec):
         return ArgumentResolver(argspec, resolve_named=False)
@@ -206,28 +195,21 @@

 class _DynamicHandler(_RunnableHandler):

-    def __init__(self, library, handler_name, handler_method, doc='',
+    def __init__(self, library, handler_name, dynamic_method, doc='',
                  argspec=None):
         self._argspec = argspec
- _RunnableHandler.__init__(self, library, handler_name, handler_method)
-        self._run_keyword_method_name = handler_method.__name__
+        _RunnableHandler.__init__(self, library, handler_name,
+                                  dynamic_method.method)
+        self._run_keyword_method_name = dynamic_method.name
         self._doc = doc is not None and utils.unic(doc) or ''
- # TODO: Extract method. Also store only info are kwargs supported or not.
-        # Check **kwargs handling requirements:
-        self._handler_argspec = DynamicMethodArgumentParser().parse(
-              handler_name, handler_method)
+        self._kwargs_supported = dynamic_method.kwargs_supported
         if argspec and argspec[-1].startswith('**'):
-            # --> Keyword has **kwargs
-            handler_args = self._handler_argspec.positional
-            # --> Handler method needs (self, name, args, kwargs)
-            if len(handler_args) < 3:
-                raise DataError(
-                  "Too few '%s' method parameters"
-                  " for **kwargs support."
-                  % self._run_keyword_method_name)
+            if not self._kwargs_supported:
+ raise DataError("Too few '%s' method parameters for **kwargs "
+                                "support." % self._run_keyword_method_name)

     def _parse_arguments(self, handler_method):
-        return DynamicArgumentParser().parse(self.longname, self._argspec)
+        return DynamicArgumentParser().parse(self._argspec, self.longname)

     def resolve_arguments(self, arguments, variables=None):
positional, named = _RunnableHandler.resolve_arguments(self, arguments, variables)
@@ -244,9 +226,7 @@

     def _get_dynamic_handler(self, runner, name):
         def handler(*positional, **kwargs):
-            # Does the runner have enough parameters for **kwargs support?
-            # (self, name, args, kwargs)
-            if len(self._handler_argspec.positional) > 2:
+            if self._kwargs_supported:
                 return runner(name, positional, kwargs)
             else:
                 return runner(name, positional)
@@ -400,7 +380,7 @@

     def _parse_arguments(self, handler_method):
         parser = PythonArgumentParser(type='Test Library')
-        return parser.parse(self.library.name, handler_method)
+        return parser.parse(handler_method, self.library.name)


 class _JavaInitHandler(_JavaHandler):
@@ -419,4 +399,4 @@
     def _parse_arguments(self, handler_method):
         parser = JavaArgumentParser(type='Test Library')
         signatures = self._get_signatures(handler_method)
-        return parser.parse(self.library.name, signatures)
+        return parser.parse(signatures, self.library.name)
=======================================
--- /src/robot/running/testlibraries.py Wed Nov 13 08:14:41 2013 UTC
+++ /src/robot/running/testlibraries.py Thu Nov 21 12:51:47 2013 UTC
@@ -315,7 +315,7 @@
         return GetKeywordNames(instance)()

     def _get_handler_method(self, instance, name):
-        return RunKeyword(instance).method
+        return RunKeyword(instance)

     def _create_handler(self, name, method):
         doc = self._get_kw_doc(name)
=======================================
--- /src/robot/running/userkeyword.py   Wed Nov 20 17:05:12 2013 UTC
+++ /src/robot/running/userkeyword.py   Thu Nov 21 12:51:47 2013 UTC
@@ -116,8 +116,8 @@
         self.teardown = keyword.teardown
         self.libname = libname
         self.doc = self._doc = unicode(keyword.doc)
-        self.arguments = UserKeywordArgumentParser().parse(self.longname,
- tuple(keyword.args)) + self.arguments = UserKeywordArgumentParser().parse(tuple(keyword.args),
+                                                           self.longname)
         self._timeout = keyword.timeout

     @property
=======================================
--- /src/robot/utils/__init__.py        Tue Nov 19 13:19:28 2013 UTC
+++ /src/robot/utils/__init__.py        Thu Nov 21 12:51:47 2013 UTC
@@ -49,6 +49,7 @@
from .misc import plural_or_not, printable_name, seq2str, seq2str2, getdoc, isatty
 from .normalizing import lower, normalize, NormalizedDict
 from .robotenv import get_env_var, set_env_var, del_env_var, get_env_vars
+from .robotinspect import is_java_init, is_java_method
 from .robotpath import abspath, find_file, get_link_path, normpath
 from .robottime import (get_timestamp, get_start_timestamp, format_time,
                         get_time, get_elapsed_time, elapsed_time_to_string,
=======================================
--- /utest/running/test_handlers.py     Thu Nov 21 12:26:42 2013 UTC
+++ /utest/running/test_handlers.py     Thu Nov 21 12:51:47 2013 UTC
@@ -6,7 +6,8 @@
 from robot import utils
 from robot.utils.asserts import *
 from robot.running.testlibraries import TestLibrary
-from robot.running.dynamicmethods import GetKeywordArguments, GetKeywordDocumentation
+from robot.running.dynamicmethods import (
+    GetKeywordArguments, GetKeywordDocumentation, RunKeyword)
 from robot.errors import DataError

 from classes import NameLibrary, DocLibrary, ArgInfoLibrary
@@ -193,7 +194,7 @@
             lib.run_keyword = lambda name, args: None
         doc = GetKeywordDocumentation(lib)._handle_return_value(doc)
         argspec = GetKeywordArguments(lib)._handle_return_value(argspec)
-        return DynamicHandler(lib, 'mock', lib.run_keyword, doc, argspec)
+        return DynamicHandler(lib, 'mock', RunKeyword(lib), doc, argspec)


 if utils.is_jython:
=======================================
--- /utest/running/test_userhandlers.py Thu May 16 13:01:15 2013 UTC
+++ /utest/running/test_userhandlers.py Thu Nov 21 12:51:47 2013 UTC
@@ -153,7 +153,7 @@
         assert_equals(argspec.varargs, exp_varargs)

     def _parse(self, in_args):
-        return UserKeywordArgumentParser().parse('Name', in_args.split())
+        return UserKeywordArgumentParser().parse(in_args.split())

     def test_many_varargs_raises(self):
         assert_raises(DataError, self._parse, '@{varargs} @{varargs2}')

--

--- You received this message because you are subscribed to the Google Groups "robotframework-commit" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to