8 new revisions:

Revision: a8df3f62edee
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 10:52:59 2013 UTC
Log: remoteserver test runner: use robot under src, not installed robot, wh...
http://code.google.com/p/robotframework/source/detail?r=a8df3f62edee

Revision: 64d6f94bffac
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 10:59:10 2013 UTC
Log:      Remote: Cleanup
http://code.google.com/p/robotframework/source/detail?r=64d6f94bffac

Revision: 4952d866ea5c
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 11:04:24 2013 UTC
Log:      whitespace
http://code.google.com/p/robotframework/source/detail?r=4952d866ea5c

Revision: b789f4fff467
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 11:33:47 2013 UTC
Log:      Support **kwargs in remote interface...
http://code.google.com/p/robotframework/source/detail?r=b789f4fff467

Revision: 285ada2433ea
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 12:29:11 2013 UTC
Log: utils: renamed iterable -> is_list_like, added is_str_like and is_dict...
http://code.google.com/p/robotframework/source/detail?r=285ada2433ea

Revision: 28d2d99f6d0b
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 12:52:16 2013 UTC
Log:      renamed utest file to match tested file name
http://code.google.com/p/robotframework/source/detail?r=28d2d99f6d0b

Revision: b5cec12fa691
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 13:01:53 2013 UTC
Log:      test data cleanup
http://code.google.com/p/robotframework/source/detail?r=b5cec12fa691

Revision: 8b6bf3ff4728
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 13:33:49 2013 UTC
Log:      Remote: support generic iterables and mappings...
http://code.google.com/p/robotframework/source/detail?r=8b6bf3ff4728

==============================================================================
Revision: a8df3f62edee
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 10:52:59 2013 UTC
Log: remoteserver test runner: use robot under src, not installed robot, when running tests
http://code.google.com/p/robotframework/source/detail?r=a8df3f62edee

Modified:
 /tools/remoteserver/test/run.py

=======================================
--- /tools/remoteserver/test/run.py     Thu May 26 20:30:28 2011 UTC
+++ /tools/remoteserver/test/run.py     Fri Nov 29 10:52:59 2013 UTC
@@ -4,7 +4,7 @@
 Usage 1: run.py language[:runner] [[options] datasources]

 Valid languages are 'python', 'jython' or 'ruby', and runner can
-either by 'pybot' (default) or 'jybot'. By default, all tests under
+either by 'python' (default) or 'jython'. By default, all tests under
 'test/data' directory are run, but this can be changed by providing
 options, which can be any Robot Framework command line options.

@@ -16,13 +16,14 @@
 import xmlrpclib
 import time
 import os
+from os.path import abspath, dirname, exists, join, normpath
 import subprocess
 import shutil
 import socket

-REMOTEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-OUTPUTDIR = os.path.join(REMOTEDIR, 'test', 'logs')
-if os.path.exists(OUTPUTDIR):
+REMOTEDIR = dirname(dirname(abspath(__file__)))
+OUTPUTDIR = join(REMOTEDIR, 'test', 'logs')
+if exists(OUTPUTDIR):
     shutil.rmtree(OUTPUTDIR)
 os.mkdir(OUTPUTDIR)

@@ -38,9 +39,9 @@
     def _start_library(self, lang):
         opts = self._environment_setup(lang)
         ext = {'python': 'py', 'jython': 'py', 'ruby': 'rb'}[lang]
- lib = os.path.join(REMOTEDIR, 'test', 'libs', 'examplelib.%s' % ext)
-        stdout = os.path.join(OUTPUTDIR, 'stdout.txt')
-        stderr = os.path.join(OUTPUTDIR, 'stderr.txt')
+        lib = join(REMOTEDIR, 'test', 'libs', 'examplelib.%s' % ext)
+        stdout = join(OUTPUTDIR, 'stdout.txt')
+        stderr = join(OUTPUTDIR, 'stderr.txt')
         cmd = '%s%s%s 1> %s 2> %s' % (lang, opts, lib, stdout, stderr)
         print 'Starting %s remote library with command:\n%s' % (lang, cmd)
         subprocess.Popen(cmd, shell=True)
@@ -88,21 +89,22 @@
     if ':' in mode:
         lang, runner = mode.split(':')
     else:
-        lang, runner = mode, 'pybot'
+        lang, runner = mode, 'python'
     lib = Library(lang)
     include = lang if lang != 'jython' else 'python'
-    output = os.path.join(OUTPUTDIR, 'output.xml')
- args = [runner, '--log', 'NONE', '--report', 'NONE', '--output', output,
+    output = join(OUTPUTDIR, 'output.xml')
+ args = [runner, normpath(join(REMOTEDIR, '..', '..', 'src', 'robot', 'run.py')),
+            '--output', output, '--log', 'NONE', '--report', 'NONE',
'--name', mode, '--include', include, '--noncritical', 'non-critical']
     if len(sys.argv) == 2:
-        args.append(os.path.join(REMOTEDIR, 'test', 'atest'))
+        args.append(join(REMOTEDIR, 'test', 'atest'))
     else:
         args.extend(sys.argv[2:])
     print 'Running tests with command:\n%s' % ' '.join(args)
     subprocess.call(args)
     lib.stop()
     print
- checker = os.path.join(REMOTEDIR, '..', 'statuschecker', 'statuschecker.py')
+    checker = join(REMOTEDIR, '..', 'statuschecker', 'statuschecker.py')
     subprocess.call(['python', checker, output])
     rc = subprocess.call(['rebot', '--noncritical', 'non-critical',
                           '--outputdir', OUTPUTDIR, output])

==============================================================================
Revision: 64d6f94bffac
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 10:59:10 2013 UTC
Log:      Remote: Cleanup
http://code.google.com/p/robotframework/source/detail?r=64d6f94bffac

Modified:
 /src/robot/libraries/Remote.py

=======================================
--- /src/robot/libraries/Remote.py      Thu Jun  6 14:00:44 2013 UTC
+++ /src/robot/libraries/Remote.py      Fri Nov 29 10:59:10 2013 UTC
@@ -19,13 +19,14 @@
 try:
     from xml.parsers.expat import ExpatError
 except ImportError:   # No expat in IronPython 2.7
-    class ExpatError(Exception): pass
+    class ExpatError(Exception):
+        pass

-from robot import utils
 from robot.errors import RemoteError
+from robot.utils import unic


-class Remote:
+class Remote(object):
     ROBOT_LIBRARY_SCOPE = 'TEST SUITE'

     def __init__(self, uri='http://localhost:8270'):
@@ -56,7 +57,7 @@
             return ''

     def run_keyword(self, name, args):
-        args = [self._handle_argument(arg) for arg in args]
+        args = self._handle_argument(args)
         result = RemoteResult(self._client.run_keyword(name, args))
         sys.stdout.write(result.output)
         if result.status != 'PASS':
@@ -76,10 +77,10 @@
     def _str(self, item):
         if item is None:
             return ''
-        return utils.unic(item)
+        return unic(item)


-class RemoteResult:
+class RemoteResult(object):

     def __init__(self, result):
         try:
@@ -92,7 +93,7 @@
raise RuntimeError('Invalid remote result dictionary: %s' % result)


-class XmlRpcRemoteClient:
+class XmlRpcRemoteClient(object):

     def __init__(self, uri):
         self._server = xmlrpclib.ServerProxy(uri, encoding='UTF-8')

==============================================================================
Revision: 4952d866ea5c
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 11:04:24 2013 UTC
Log:      whitespace
http://code.google.com/p/robotframework/source/detail?r=4952d866ea5c

Modified:
 /tools/remoteserver/test/libs/examplelib.py

=======================================
--- /tools/remoteserver/test/libs/examplelib.py Fri Apr 17 13:08:38 2009 UTC
+++ /tools/remoteserver/test/libs/examplelib.py Fri Nov 29 11:04:24 2013 UTC
@@ -18,7 +18,7 @@
         See `Failing`, `Logging`, and `Returning` for other basic keywords.
         """
         pass
-
+
     def failing(self, message):
         """This keyword fails with provided `message`"""
         raise AssertionError(message)
@@ -52,7 +52,7 @@

     def log_unicode(self):
         print self._unicode
-
+
     def logging_and_failing(self):
         print '*INFO* This keyword will fail!'
         print '*WARN* Run for your lives!!'
@@ -216,16 +216,16 @@

     def return_negative_integer(self):
         return -1
-
+
     def return_float(self):
         return 3.14
-
+
     def return_negative_float(self):
         return -0.5

     def return_zero(self):
         return 0
-
+
     def return_boolean_true(self):
         return True


==============================================================================
Revision: b789f4fff467
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 11:33:47 2013 UTC
Log:      Support **kwargs in remote interface

Update issue 1596
Status: Started
Implemented changes to Remote and robotremoteserver. Documentation missing.
http://code.google.com/p/robotframework/source/detail?r=b789f4fff467

Added:
 /tools/remoteserver/test/atest/kwargs.txt
Modified:
 /src/robot/libraries/Remote.py
 /tools/remoteserver/robotremoteserver.py
 /tools/remoteserver/test/libs/examplelib.py

=======================================
--- /dev/null
+++ /tools/remoteserver/test/atest/kwargs.txt   Fri Nov 29 11:33:47 2013 UTC
@@ -0,0 +1,60 @@
+*** Settings ***
+Default Tags      python
+Library           Remote    localhost:${PORT}
+
+*** Variables ***
+${PORT}           8270
+
+*** Test Cases ***
+No kwargs
+    ${result} =    Kwargs
+    Should Be Equal    ${result}    ${EMPTY}
+
+One kwarg
+    ${result} =    Kwargs    foo=bar
+    Should Be Equal    ${result}    foo:bar
+
+Multiple kwargs
+    ${result} =    Kwargs    a=1    c=3    d=4    b=2
+    Should Be Equal    ${result}    a:1, b:2, c:3, d:4
+
+Args and kwargs
+    ${result} =    Args and kwargs    arg
+    Should Be Equal    ${result}    arg, default2
+    ${result} =    Args and kwargs    arg    foo=bar
+    Should Be Equal    ${result}    arg, default2, foo:bar
+    ${result} =    Args and kwargs    a    arg2=b    c=3    d=4
+    Should Be Equal    ${result}    a, b, c:3, d:4
+    ${result} =    Args and kwargs    arg2=b    c=3    d=4
+    Should Be Equal    ${result}    default1, b, c:3, d:4
+
+Varargs and kwargs
+    ${result} =    Varargs and kwargs
+    Should Be Equal    ${result}    ${EMPTY}
+    ${result} =    Varargs and kwargs    foo=bar
+    Should Be Equal    ${result}    foo:bar
+    ${result} =    Varargs and kwargs    arg    foo=bar
+    Should Be Equal    ${result}    arg, foo:bar
+    ${result} =    Varargs and kwargs    a    b    c    d=4    e=5    f=6
+    Should Be Equal    ${result}    a, b, c, d:4, e:5, f:6
+
+Args, varargs and kwargs
+    ${result} =    Args varargs and kwargs    arg
+    Should Be Equal    ${result}    arg, default2
+    ${result} =    Args varargs and kwargs    arg    foo=bar
+    Should Be Equal    ${result}    arg, default2, foo:bar
+    ${result} =    Args varargs and kwargs    arg2=foo    foo=bar
+    Should Be Equal    ${result}    default1, foo, foo:bar
+    ${result} =    Args varargs and kwargs    a    arg2=b    c=3
+    Should Be Equal    ${result}    a, b, c:3
+ ${result} = Args varargs and kwargs a b c d e=5 f=6
+    Should Be Equal    ${result}    a, b, c, d, e:5, f:6
+
+Non-ASCII kwargs
+    ${result} =    Kwargs    a=hyvää    b=päivää    c=\u2603
+    Should Be Equal    ${result}    a:hyvää, b:päivää, c:\u2603
+
+Non-string kwargs
+    ${list} =    Create List    1    ${2}
+    ${result} =    Non string kwargs    a=${1}    b=${NONE}    c=${list}
+    Should Be Equal    ${result}    a:1 (int), b: (str), c:['1', 2] (list)
=======================================
--- /src/robot/libraries/Remote.py      Fri Nov 29 10:59:10 2013 UTC
+++ /src/robot/libraries/Remote.py      Fri Nov 29 11:33:47 2013 UTC
@@ -56,9 +56,10 @@
         except TypeError:
             return ''

-    def run_keyword(self, name, args):
+    def run_keyword(self, name, args, kwargs):
         args = self._handle_argument(args)
-        result = RemoteResult(self._client.run_keyword(name, args))
+        kwargs = self._handle_argument(kwargs)
+        result = RemoteResult(self._client.run_keyword(name, args, kwargs))
         sys.stdout.write(result.output)
         if result.status != 'PASS':
             raise RemoteError(result.error, result.traceback)
@@ -118,9 +119,10 @@
         except xmlrpclib.Error:
             raise TypeError

-    def run_keyword(self, name, args):
+    def run_keyword(self, name, args, kwargs):
+        run_keyword_args = [name, args, kwargs] if kwargs else [name, args]
         try:
-            return self._server.run_keyword(name, args)
+            return self._server.run_keyword(*run_keyword_args)
         except xmlrpclib.Error, err:
             raise RuntimeError(err.faultString)
         except socket.error, (errno, err):
=======================================
--- /tools/remoteserver/robotremoteserver.py    Thu Jun  6 14:00:44 2013 UTC
+++ /tools/remoteserver/robotremoteserver.py    Fri Nov 29 11:33:47 2013 UTC
@@ -76,12 +76,12 @@
                      and inspect.isroutine(getattr(self._library, attr))]
         return names + ['stop_remote_server']

-    def run_keyword(self, name, args):
+    def run_keyword(self, name, args, kwargs=None):
         result = {'status': 'PASS', 'return': '', 'output': '',
                   'error': '', 'traceback': ''}
         self._intercept_stdout()
         try:
-            return_value = self._get_keyword(name)(*args)
+            return_value = self._get_keyword(name)(*args, **(kwargs or {}))
         except:
             result['status'] = 'FAIL'
result['error'], result['traceback'] = self._get_error_details()
@@ -97,7 +97,7 @@
         return self._arguments_from_kw(kw)

     def _arguments_from_kw(self, kw):
-        args, varargs, _, defaults = inspect.getargspec(kw)
+        args, varargs, kwargs, defaults = inspect.getargspec(kw)
         if inspect.ismethod(kw):
             args = args[1:]  # drop 'self'
         if defaults:
@@ -105,6 +105,8 @@
             args += ['%s=%s' % (n, d) for n, d in zip(names, defaults)]
         if varargs:
             args.append('*%s' % varargs)
+        if kwargs:
+            args.append('**%s' % kwargs)
         return args

     def get_keyword_documentation(self, name):
=======================================
--- /tools/remoteserver/test/libs/examplelib.py Fri Nov 29 11:04:24 2013 UTC
+++ /tools/remoteserver/test/libs/examplelib.py Fri Nov 29 11:33:47 2013 UTC
@@ -122,6 +122,28 @@
def required_defaults_and_varargs(self, req, default='world', *varargs):
         return ' '.join((req, default) + varargs)

+    def kwargs(self, **kwargs):
+        return self._format_args(**kwargs)
+
+    def args_and_kwargs(self, arg1='default1', arg2='default2', **kwargs):
+        return self._format_args(arg1, arg2, **kwargs)
+
+    def varargs_and_kwargs(self, *varargs, **kwargs):
+        return self._format_args(*varargs, **kwargs)
+
+    def args_varargs_and_kwargs(self, arg1='default1', arg2='default2',
+                                *varargs, **kwargs):
+        return self._format_args(arg1, arg2, *varargs, **kwargs)
+
+    def non_string_kwargs(self, **kwargs):
+        kwargs = dict((k, '%s (%s)' % (v, type(v).__name__))
+                      for k, v in kwargs.items())
+        return self._format_args(**kwargs)
+
+    def _format_args(self, *args, **kws):
+        args += tuple(':'.join(item) for item in sorted(kws.items()))
+        return ', '.join(args)
+
     # Argument types

     def string_as_argument(self, arg):

==============================================================================
Revision: 285ada2433ea
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 12:29:11 2013 UTC
Log: utils: renamed iterable -> is_list_like, added is_str_like and is_dict_like
http://code.google.com/p/robotframework/source/detail?r=285ada2433ea

Added:
 /src/robot/utils/islike.py
 /utest/utils/test_like.py
Modified:
 /src/robot/utils/__init__.py
 /src/robot/utils/misc.py
 /src/robot/variables/variables.py

=======================================
--- /dev/null
+++ /src/robot/utils/islike.py  Fri Nov 29 12:29:11 2013 UTC
@@ -0,0 +1,39 @@
+#  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.
+
+try:
+    from collections import Mapping
+except ImportError:  # New in 2.6
+    Mapping = dict
+from UserDict import UserDict
+from UserString import UserString
+
+
+def is_str_like(item):
+    return isinstance(item, (basestring, UserString))
+
+
+def is_list_like(item):
+    if is_str_like(item) or is_dict_like(item):
+        return False
+    try:
+        iter(item)
+    except TypeError:
+        return False
+    else:
+        return True
+
+
+def is_dict_like(item):
+    return isinstance(item, (Mapping, UserDict))
=======================================
--- /dev/null
+++ /utest/utils/test_like.py   Fri Nov 29 12:29:11 2013 UTC
@@ -0,0 +1,82 @@
+import unittest
+
+try:
+    from collections import Mapping
+except ImportError:
+    Mapping = dict
+from array import array
+from UserDict import UserDict
+from UserList import UserList
+from UserString import UserString, MutableString
+
+from robot.utils import is_dict_like, is_list_like, is_str_like
+from robot.utils.asserts import assert_equals
+
+
+class MyMapping(Mapping):
+
+    def __getitem__(self, item):
+        return 0
+
+    def __len__(self):
+        return 0
+
+    def __iter__(self):
+        return iter([])
+
+
+def generator():
+    yield 'generated'
+
+
+class TestListlike(unittest.TestCase):
+
+    def test_strings_are_not_list_like(self):
+        for thing in ['str', u'unicode', UserString('user')]:
+            assert_equals(is_list_like(thing), False, thing)
+
+    def test_dict_likes_are_not_list_like(self):
+        for thing in [dict(), UserDict(), MyMapping()]:
+            assert_equals(is_list_like(thing), False, thing)
+
+    def test_other_iterables_are_list_like(self):
+ for thing in [[], (), set(), xrange(1), generator(), array('i'), UserList()]:
+            assert_equals(is_list_like(thing), True, thing)
+
+    def test_others_are_not_list_like(self):
+        for thing in [1, None, True, object(), object]:
+            assert_equals(is_list_like(thing), False, thing)
+
+    def test_generators_are_not_consumed(self):
+        g = generator()
+        assert_equals(is_list_like(g), True)
+        assert_equals(is_list_like(g), True)
+        assert_equals(list(g), ['generated'])
+        assert_equals(list(g), [])
+        assert_equals(is_list_like(g), True)
+
+
+class TestDictlike(unittest.TestCase):
+
+    def test_dict_likes(self):
+        for thing in [dict(), UserDict(), MyMapping()]:
+            assert_equals(is_dict_like(thing), True, thing)
+
+    def test_others(self):
+ for thing in ['', u'', 1, None, True, object(), object, [], (), set()]:
+            assert_equals(is_dict_like(thing), False, thing)
+
+
+class TestStringlike(unittest.TestCase):
+
+    def test_string_likes(self):
+ for thing in ['', 'a', u'\xe4', UserString('us'), MutableString('ms')]:
+            assert_equals(is_str_like(thing), True, thing)
+
+    def test_others(self):
+        for thing in [1, None, True, object(), object, [], (), {}]:
+            assert_equals(is_str_like(thing), False, thing)
+
+
+if __name__ == "__main__":
+    unittest.main()
=======================================
--- /src/robot/utils/__init__.py        Thu Nov 28 13:25:17 2013 UTC
+++ /src/robot/utils/__init__.py        Fri Nov 29 12:29:11 2013 UTC
@@ -45,8 +45,9 @@
from .markuputils import html_format, html_escape, xml_escape, attribute_escape
 from .markupwriters import HtmlWriter, XmlWriter, NullMarkupWriter
 from .importer import Importer
+from .islike import is_dict_like, is_list_like, is_str_like
 from .match import eq, Matcher, MultiMatcher
-from .misc import (isatty, getdoc, iterable, plural_or_not, printable_name,
+from .misc import (isatty, getdoc, plural_or_not, printable_name,
                    seq2str, seq2str2)
 from .normalizing import lower, normalize, NormalizedDict
 from .robotenv import get_env_var, set_env_var, del_env_var, get_env_vars
=======================================
--- /src/robot/utils/misc.py    Thu Nov 28 13:25:17 2013 UTC
+++ /src/robot/utils/misc.py    Fri Nov 29 12:29:11 2013 UTC
@@ -105,17 +105,6 @@
         return unic(doc)


-def iterable(item):
-    if isinstance(item, basestring):
-        return False
-    try:
-        iter(item)
-    except TypeError:
-        return False
-    else:
-        return True
-
-
 # On IronPython sys.stdxxx.isatty() always returns True
 if sys.platform != 'cli':

=======================================
--- /src/robot/variables/variables.py   Thu Nov 28 13:25:17 2013 UTC
+++ /src/robot/variables/variables.py   Fri Nov 29 12:29:11 2013 UTC
@@ -126,7 +126,7 @@
             value = self._find_variable(name)
         except KeyError:
             value = self._get_extended_var(name)
-        if not utils.iterable(value):
+        if not utils.is_list_like(value):
raise DataError("Using scalar variable '%s' as list variable '@%s' "
                             "requires its value to be list or list-like."
                             % (name, name[1:]))

==============================================================================
Revision: 28d2d99f6d0b
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 12:52:16 2013 UTC
Log:      renamed utest file to match tested file name
http://code.google.com/p/robotframework/source/detail?r=28d2d99f6d0b

Added:
 /utest/utils/test_islike.py
Deleted:
 /utest/utils/test_like.py

=======================================
--- /dev/null
+++ /utest/utils/test_islike.py Fri Nov 29 12:52:16 2013 UTC
@@ -0,0 +1,82 @@
+import unittest
+
+try:
+    from collections import Mapping
+except ImportError:
+    Mapping = dict
+from array import array
+from UserDict import UserDict
+from UserList import UserList
+from UserString import UserString, MutableString
+
+from robot.utils import is_dict_like, is_list_like, is_str_like
+from robot.utils.asserts import assert_equals
+
+
+class MyMapping(Mapping):
+
+    def __getitem__(self, item):
+        return 0
+
+    def __len__(self):
+        return 0
+
+    def __iter__(self):
+        return iter([])
+
+
+def generator():
+    yield 'generated'
+
+
+class TestListlike(unittest.TestCase):
+
+    def test_strings_are_not_list_like(self):
+        for thing in ['str', u'unicode', UserString('user')]:
+            assert_equals(is_list_like(thing), False, thing)
+
+    def test_dict_likes_are_not_list_like(self):
+        for thing in [dict(), UserDict(), MyMapping()]:
+            assert_equals(is_list_like(thing), False, thing)
+
+    def test_other_iterables_are_list_like(self):
+ for thing in [[], (), set(), xrange(1), generator(), array('i'), UserList()]:
+            assert_equals(is_list_like(thing), True, thing)
+
+    def test_others_are_not_list_like(self):
+        for thing in [1, None, True, object(), object]:
+            assert_equals(is_list_like(thing), False, thing)
+
+    def test_generators_are_not_consumed(self):
+        g = generator()
+        assert_equals(is_list_like(g), True)
+        assert_equals(is_list_like(g), True)
+        assert_equals(list(g), ['generated'])
+        assert_equals(list(g), [])
+        assert_equals(is_list_like(g), True)
+
+
+class TestDictlike(unittest.TestCase):
+
+    def test_dict_likes(self):
+        for thing in [dict(), UserDict(), MyMapping()]:
+            assert_equals(is_dict_like(thing), True, thing)
+
+    def test_others(self):
+ for thing in ['', u'', 1, None, True, object(), object, [], (), set()]:
+            assert_equals(is_dict_like(thing), False, thing)
+
+
+class TestStringlike(unittest.TestCase):
+
+    def test_string_likes(self):
+ for thing in ['', 'a', u'\xe4', UserString('us'), MutableString('ms')]:
+            assert_equals(is_str_like(thing), True, thing)
+
+    def test_others(self):
+        for thing in [1, None, True, object(), object, [], (), {}]:
+            assert_equals(is_str_like(thing), False, thing)
+
+
+if __name__ == "__main__":
+    unittest.main()
=======================================
--- /utest/utils/test_like.py   Fri Nov 29 12:29:11 2013 UTC
+++ /dev/null
@@ -1,82 +0,0 @@
-import unittest
-
-try:
-    from collections import Mapping
-except ImportError:
-    Mapping = dict
-from array import array
-from UserDict import UserDict
-from UserList import UserList
-from UserString import UserString, MutableString
-
-from robot.utils import is_dict_like, is_list_like, is_str_like
-from robot.utils.asserts import assert_equals
-
-
-class MyMapping(Mapping):
-
-    def __getitem__(self, item):
-        return 0
-
-    def __len__(self):
-        return 0
-
-    def __iter__(self):
-        return iter([])
-
-
-def generator():
-    yield 'generated'
-
-
-class TestListlike(unittest.TestCase):
-
-    def test_strings_are_not_list_like(self):
-        for thing in ['str', u'unicode', UserString('user')]:
-            assert_equals(is_list_like(thing), False, thing)
-
-    def test_dict_likes_are_not_list_like(self):
-        for thing in [dict(), UserDict(), MyMapping()]:
-            assert_equals(is_list_like(thing), False, thing)
-
-    def test_other_iterables_are_list_like(self):
- for thing in [[], (), set(), xrange(1), generator(), array('i'), UserList()]:
-            assert_equals(is_list_like(thing), True, thing)
-
-    def test_others_are_not_list_like(self):
-        for thing in [1, None, True, object(), object]:
-            assert_equals(is_list_like(thing), False, thing)
-
-    def test_generators_are_not_consumed(self):
-        g = generator()
-        assert_equals(is_list_like(g), True)
-        assert_equals(is_list_like(g), True)
-        assert_equals(list(g), ['generated'])
-        assert_equals(list(g), [])
-        assert_equals(is_list_like(g), True)
-
-
-class TestDictlike(unittest.TestCase):
-
-    def test_dict_likes(self):
-        for thing in [dict(), UserDict(), MyMapping()]:
-            assert_equals(is_dict_like(thing), True, thing)
-
-    def test_others(self):
- for thing in ['', u'', 1, None, True, object(), object, [], (), set()]:
-            assert_equals(is_dict_like(thing), False, thing)
-
-
-class TestStringlike(unittest.TestCase):
-
-    def test_string_likes(self):
- for thing in ['', 'a', u'\xe4', UserString('us'), MutableString('ms')]:
-            assert_equals(is_str_like(thing), True, thing)
-
-    def test_others(self):
-        for thing in [1, None, True, object(), object, [], (), {}]:
-            assert_equals(is_str_like(thing), False, thing)
-
-
-if __name__ == "__main__":
-    unittest.main()

==============================================================================
Revision: b5cec12fa691
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 13:01:53 2013 UTC
Log:      test data cleanup
http://code.google.com/p/robotframework/source/detail?r=b5cec12fa691

Modified:
 /tools/remoteserver/test/atest/arguments.py

=======================================
--- /tools/remoteserver/test/atest/arguments.py Fri Apr 17 13:08:38 2009 UTC
+++ /tools/remoteserver/test/atest/arguments.py Fri Nov 29 13:01:53 2013 UTC
@@ -1,16 +1,18 @@
-# Can be used in the test data like ${MyObject()} or ${MyObject(1)}
 class MyObject:
-    def __init__(self, index=''):
+
+    def __init__(self, index=0):
         self.index = index
+
     def __str__(self):
-        return '<MyObject%s>' % self.index
+        return '<MyObject%s>' % (self.index or '')
+

 UNICODE = (u'Hyv\u00E4\u00E4 y\u00F6t\u00E4. '
            u'\u0421\u043F\u0430\u0441\u0438\u0431\u043E!')
 LIST_WITH_OBJECTS = [MyObject(1), MyObject(2)]
-NESTED_LIST = [ [True, False], [[1, None, MyObject(), {}]] ]
-NESTED_TUPLE = ( (True, False), [(1, None, MyObject(), {})] )
+NESTED_LIST = [[True, False], [[1, None, MyObject(), {}]]]
+NESTED_TUPLE = ((True, False), [(1, None, MyObject(), {})])
 DICT_WITH_OBJECTS = {'As value': MyObject(1), MyObject(2): 'As key'}
-NESTED_DICT = { 1: {None: False},
-                2: {'A': {'n': None},
-                    'B': {'o': MyObject(), 'e': {}}} }
+NESTED_DICT = {1: {None: False},
+               2: {'A': {'n': None},
+                   'B': {'o': MyObject(), 'e': {}}}}

==============================================================================
Revision: 8b6bf3ff4728
Branch:   default
Author:   Pekka Klärck
Date:     Fri Nov 29 13:33:49 2013 UTC
Log:      Remote: support generic iterables and mappings

Update issue 1597
Status: Done
Fixed on both sides.

robotremoteserver.py doesn't handle UserDicts or UserStrings correctly, but I seriously doubt anyone uses them in a test library. If they do, they can easily convert them to normal strings before returning them.
http://code.google.com/p/robotframework/source/detail?r=8b6bf3ff4728

Added:
 /tools/remoteserver/test/libs/mapping.py
Modified:
 /src/robot/libraries/Remote.py
 /tools/remoteserver/robotremoteserver.py
 /tools/remoteserver/test/atest/argument_types.txt
 /tools/remoteserver/test/atest/return_values.txt
 /tools/remoteserver/test/libs/examplelib.py

=======================================
--- /dev/null
+++ /tools/remoteserver/test/libs/mapping.py    Fri Nov 29 13:33:49 2013 UTC
@@ -0,0 +1,20 @@
+try:
+    from collections import Mapping
+
+    class MyMapping(Mapping):
+
+        def __init__(self, data=None, **extra):
+            self.data = data or {}
+            self.data.update(**extra)
+
+        def __getitem__(self, item):
+            return self.data[item]
+
+        def __len__(self):
+            return len(self.data)
+
+        def __iter__(self):
+            return iter(self.data)
+
+except ImportError:
+    MyMapping = dict
=======================================
--- /src/robot/libraries/Remote.py      Fri Nov 29 11:33:47 2013 UTC
+++ /src/robot/libraries/Remote.py      Fri Nov 29 13:33:49 2013 UTC
@@ -23,7 +23,7 @@
         pass

 from robot.errors import RemoteError
-from robot.utils import unic
+from robot.utils import is_list_like, is_dict_like, unic


 class Remote(object):
@@ -68,9 +68,9 @@
     def _handle_argument(self, arg):
         if isinstance(arg, (basestring, int, long, float)):
             return arg
-        if isinstance(arg, (tuple, list)):
+        if is_list_like(arg):
             return [self._handle_argument(item) for item in arg]
-        if isinstance(arg, dict):
+        if is_dict_like(arg):
             return dict((self._str(key), self._handle_argument(value))
                         for key, value in arg.items())
         return self._str(arg)
=======================================
--- /tools/remoteserver/robotremoteserver.py    Fri Nov 29 11:33:47 2013 UTC
+++ /tools/remoteserver/robotremoteserver.py    Fri Nov 29 13:33:49 2013 UTC
@@ -21,6 +21,10 @@
     import signal
 except ImportError:
     signal = None
+try:
+    from collections import Mapping
+except ImportError:
+    Mapping = dict


 class RobotRemoteServer(SimpleXMLRPCServer):
@@ -30,6 +34,7 @@
SimpleXMLRPCServer.__init__(self, (host, int(port)), logRequests=False)
         self._library = library
         self._allow_stop = allow_stop
+        self._shutdown = False
         self._register_functions()
         self._register_signal_handlers()
         self._log('Robot Framework remote server starting at %s:%s'
@@ -53,7 +58,6 @@
             signal.signal(signal.SIGINT, stop_with_signal)

     def serve_forever(self):
-        self._shutdown = False
         while not self._shutdown:
             self.handle_request()

@@ -150,12 +154,13 @@
     def _handle_return_value(self, ret):
         if isinstance(ret, (basestring, int, long, float)):
             return ret
-        if isinstance(ret, (tuple, list)):
-            return [self._handle_return_value(item) for item in ret]
-        if isinstance(ret, dict):
+        if isinstance(ret, Mapping):
             return dict([(self._str(key), self._handle_return_value(value))
                          for key, value in ret.items()])
-        return self._str(ret)
+        try:
+            return [self._handle_return_value(item) for item in ret]
+        except TypeError:
+            return self._str(ret)

     def _str(self, item):
         if item is None:
=======================================
--- /tools/remoteserver/test/atest/argument_types.txt Thu May 26 20:30:59 2011 UTC +++ /tools/remoteserver/test/atest/argument_types.txt Fri Nov 29 13:33:49 2013 UTC
@@ -3,6 +3,7 @@
 Library         Remote  localhost:${PORT}  WITH NAME  remote
 Library         Collections
 Variables       arguments.py
+Variables       ../libs/mapping.py

 *** Variables ***
 ${PORT}  8270
@@ -76,6 +77,9 @@

 Nested Dictionary As Argument
     Nested Dictionary As Argument  ${NESTED_DICT}
+
+Mapping As Argument
+    Dictionary As Argument    ${MyMapping(one=1, spam='eggs')}

 Control Char As Argument
[Documentation] In this situation the received error is not that good FAIL REGEXP: .*ExpatError.*
=======================================
--- /tools/remoteserver/test/atest/return_values.txt Thu May 26 20:30:59 2011 UTC +++ /tools/remoteserver/test/atest/return_values.txt Fri Nov 29 13:33:49 2013 UTC
@@ -89,6 +89,10 @@
 Return Nested Dictionary
     [Tags]  ruby
Return Value Should Be Return Nested Dictionary {'1': {'true': False}, '2': {'A': {'n': ''}, 'B': {'o': '<MyObject>', 'e': {}}} }
+
+Return Mapping
+    [Tags]  python
+ Return Value Should Be Return Mapping {'a': 1, '2': 'b', '': {'none': ''}}

 Return Control Char
[Documentation] FAIL REGEXP: Processing XML-RPC return value failed. Most often this happens when the return value contains characters that are not valid in XML. Original error was: ExpatError: .*
=======================================
--- /tools/remoteserver/test/libs/examplelib.py Fri Nov 29 11:33:47 2013 UTC
+++ /tools/remoteserver/test/libs/examplelib.py Fri Nov 29 13:33:49 2013 UTC
@@ -1,4 +1,4 @@
-import sys
+from mapping import MyMapping


 class RemoteTestLibrary:
@@ -302,6 +302,9 @@
     def return_nested_dictionary(self):
         return { 1: {None: False},
                  2: {'A': {'n': None}, 'B': {'o': MyObject(), 'e': {}}} }
+
+    def return_mapping(self):
+        return MyMapping({'a': 1, 2: 'b', None: MyMapping(none=None)})

     def return_control_char(self):
         return '\x01'

--

--- 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 robotframework-commit+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to