Hello community,

here is the log from the commit of package python-param for openSUSE:Factory 
checked in at 2019-03-14 14:59:49
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-param (Old)
 and      /work/SRC/openSUSE:Factory/.python-param.new.28833 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-param"

Thu Mar 14 14:59:49 2019 rev:7 rq:684696 version:1.8.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-param/python-param.changes        
2019-01-08 12:30:33.800135778 +0100
+++ /work/SRC/openSUSE:Factory/.python-param.new.28833/python-param.changes     
2019-03-14 15:01:01.823699307 +0100
@@ -1,0 +2,6 @@
+Wed Mar 13 13:43:12 UTC 2019 - Tomáš Chvátal <tchva...@suse.com>
+
+- Update to 1.8.2:
+  * Added output decorator and outputs lookup method (#299, #312)
+
+-------------------------------------------------------------------

Old:
----
  v1.8.1.tar.gz

New:
----
  v1.8.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-param.spec ++++++
--- /var/tmp/diff_new_pack.4Owr4S/_old  2019-03-14 15:01:04.031698872 +0100
+++ /var/tmp/diff_new_pack.4Owr4S/_new  2019-03-14 15:01:04.031698872 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-param
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -12,13 +12,13 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-param
-Version:        1.8.1
+Version:        1.8.2
 Release:        0
 Summary:        Declarative Python programming using Parameters
 License:        BSD-3-Clause

++++++ v1.8.1.tar.gz -> v1.8.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/README.rst new/param-1.8.2/README.rst
--- old/param-1.8.1/README.rst  2018-10-12 17:27:31.000000000 +0200
+++ new/param-1.8.2/README.rst  2019-01-28 03:52:15.000000000 +0100
@@ -13,17 +13,17 @@
 commercial use under a BSD license, so that it can easily be included
 as part of other projects.
 
-Please see `param's website <http://ioam.github.com/param/>`_ for
+Please see `param's website <http://param.pyviz.org>`_ for
 official releases, installation instructions, documentation, and examples.
 
-.. |LinuxTests| image:: https://travis-ci.org/ioam/param.svg?branch=master
-.. _LinuxTests: https://travis-ci.org/ioam/param
+.. |LinuxTests| image:: https://travis-ci.org/pyviz/param.svg?branch=master
+.. _LinuxTests: https://travis-ci.org/pyviz/param
 
-.. |WinTests| image:: 
https://ci.appveyor.com/api/projects/status/huoiwwamso2or7xw/branch/master?svg=true
-.. _WinTests: https://ci.appveyor.com/project/Ioam/param/branch/master
+.. |WinTests| image:: 
https://ci.appveyor.com/api/projects/status/1p5aom8o0tfgok1r?svg=true
+.. _WinTests: https://ci.appveyor.com/project/pyviz/param/branch/master
 
-.. |Coverage| image:: https://img.shields.io/coveralls/ioam/param.svg
-.. _Coverage: https://coveralls.io/r/ioam/param?branch=master
+.. |Coverage| image:: https://img.shields.io/coveralls/pyviz/param.svg
+.. _Coverage: https://coveralls.io/r/pyviz/param?branch=master
 
 .. |PyPIVersion| image:: http://img.shields.io/pypi/v/param.svg
 .. _PyPIVersion: https://pypi.python.org/pypi/param
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/numbergen/__init__.py 
new/param-1.8.2/numbergen/__init__.py
--- old/param-1.8.1/numbergen/__init__.py       2018-10-12 17:27:31.000000000 
+0200
+++ new/param-1.8.2/numbergen/__init__.py       2019-01-28 03:52:15.000000000 
+0100
@@ -655,8 +655,8 @@
     def __call__(self):
         Vi = self.starting_value
         Vm = self.ending_value
-        return Vm + (Vi - Vm) * self.base**(-1.0*float(self.time_fn())/
-                                                 float(self.time_constant))
+        exp = -1.0*float(self.time_fn())/float(self.time_constant)
+        return Vm + (Vi - Vm) * self.base**exp
 
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/param/__init__.py 
new/param-1.8.2/param/__init__.py
--- old/param-1.8.1/param/__init__.py   2018-10-12 17:27:31.000000000 +0200
+++ new/param-1.8.2/param/__init__.py   2019-01-28 03:52:15.000000000 +0100
@@ -27,7 +27,7 @@
 from .parameterized import Parameterized, Parameter, String, \
      descendents, ParameterizedFunction, ParamOverrides
 
-from .parameterized import depends           # noqa: api import
+from .parameterized import depends, output   # noqa: api import
 from .parameterized import logging_level     # noqa: api import
 from .parameterized import shared_parameters # noqa: api import
 
@@ -39,7 +39,7 @@
 # only two required files.
 try:
     from .version import Version
-    __version__ = str(Version(fpath=__file__, archive_commit="d175211", 
reponame="param"))
+    __version__ = str(Version(fpath=__file__, archive_commit="29839ba", 
reponame="param"))
 except:
     __version__ = "0.0.0+unknown"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/param/parameterized.py 
new/param-1.8.2/param/parameterized.py
--- old/param-1.8.1/param/parameterized.py      2018-10-12 17:27:31.000000000 
+0200
+++ new/param-1.8.2/param/parameterized.py      2019-01-28 03:52:15.000000000 
+0100
@@ -211,14 +211,23 @@
 
 @accept_arguments
 def depends(func, *dependencies, **kw):
+    """
+    Annotates a Parameterized method to express its dependencies.
+    The specified dependencies can be either be Parameters of this
+    class, or Parameters of subobjects (Parameterized objects that
+    are values of this object's parameters).  Dependencies can either
+    be on Parameter values, or on other metadata about the Parameter.
+    """
+
     # python3 would allow kw-only args
     # (i.e. "func,*dependencies,watch=False" rather than **kw and the check 
below)
     watch = kw.pop("watch",False)
     assert len(kw)==0, "@depends accepts only 'watch' kw"
 
     # TODO: rename dinfo
-    _dinfo = {'dependencies': dependencies,
-              'watch': watch}
+    _dinfo = getattr(func, '_dinfo', {})
+    _dinfo.update({'dependencies': dependencies,
+                   'watch': watch})
 
     @wraps(func)
     def _depends(*args,**kw):
@@ -231,6 +240,101 @@
     return _depends
 
 
+@accept_arguments
+def output(func, *output, **kw):
+    """
+    output allows annotating a method on a Parameterized class to
+    declare that it returns an output of a specific type. The outputs
+    of a Parameterized class can be queried using the
+    Parameterized.param.outputs method. By default the output will
+    inherit the method name but a custom name can be declared by
+    expressing the Parameter type using a keyword argument. Declaring
+    multiple return types using keywords is only supported in Python >= 3.6.
+
+    The simplest declaration simply declares the method returns an
+    object without any type guarantees, e.g.:
+
+      @output()
+
+    If a specific parameter type is specified this is a declaration
+    that the method will return a value of that type, e.g.:
+
+      @output(param.Number())
+
+    To override the default name of the output the type may be declared
+    as a keyword argument, e.g.:
+
+      @output(custom_name=param.Number())
+
+    Multiple outputs may be declared using keywords mapping from
+    output name to the type for Python >= 3.6 or using tuples of the
+    same format, which is supported for earlier versions, i.e. these
+    two declarations are equivalent:
+
+      @output(number=param.Number(), string=param.String())
+
+      @output(('number', param.Number()), ('string', param.String()))
+
+    output also accepts Python object types which will be upgraded to
+    a ClassSelector, e.g.:
+
+      @output(int)
+    """
+    if output:
+        outputs = []
+        for i, out in enumerate(output):
+            i = i if len(output) > 1 else None
+            if isinstance(out, tuple) and len(out) == 2 and isinstance(out[0], 
str):
+                outputs.append(out+(i,))
+            elif isinstance(out, str):
+                outputs.append((out, Parameter(), i))
+            else:
+                outputs.append((None, out, i))
+    elif kw:
+        py_major = sys.version_info.major
+        py_minor = sys.version_info.minor
+        if (py_major < 3 or (py_major == 3 and py_minor < 6)) and len(kw) > 1:
+            raise ValueError('Multiple output declaration using keywords '
+                             'only supported in Python >= 3.6.')
+          # (requires keywords to be kept ordered, which was not true in 
previous versions)
+        outputs = [(name, otype, i if len(kw) > 1 else None)
+                   for i, (name, otype) in enumerate(kw.items())]
+    else:
+        outputs = [(None, Parameter(), None)]
+
+    names, processed = [], []
+    for name, otype, i in outputs:
+        if isinstance(otype, type):
+            if issubclass(otype, Parameter):
+                otype = otype()
+            else:
+                from .import ClassSelector
+                otype = ClassSelector(class_=otype)
+        elif isinstance(otype, tuple) and all(isinstance(t, type) for t in 
otype):
+            from .import ClassSelector
+            otype = ClassSelector(class_=otype)
+        if not isinstance(otype, Parameter):
+            raise ValueError('output type must be declared with a Parameter 
class, '
+                             'instance or a Python object type.')
+        processed.append((name, otype, i))
+        names.append(name)
+
+    if len(set(names)) != len(names):
+        raise ValueError('When declaring multiple outputs each value '
+                         'must be unique.')
+
+    _dinfo = getattr(func, '_dinfo', {})
+    _dinfo.update({'outputs': processed})
+
+    @wraps(func)
+    def _output(*args,**kw):
+        return func(*args,**kw)
+
+    _output._dinfo = _dinfo
+
+    return _output
+
+
 def _params_depended_on(minfo):
     params = []
     dinfo = getattr(minfo.method,"_dinfo", {})
@@ -736,9 +840,9 @@
     @classmethod
     def is_equal(cls, obj1, obj2):
         for eq_type, eq in cls.equalities.items():
-            if ((isinstance(eq_type, FunctionType) and
-                 eq_type(obj1) and eq_type(obj2)) or
-                (isinstance(obj1, eq_type) and isinstance(obj2, eq_type))):
+            if ((isinstance(eq_type, FunctionType)
+                 and eq_type(obj1) and eq_type(obj2))
+                or (isinstance(obj1, eq_type) and isinstance(obj2, eq_type))):
                 return eq(obj1, obj2)
         if isinstance(obj2, (list, set, tuple)):
             return cls.compare_iterator(obj1, obj2)
@@ -1240,6 +1344,24 @@
         return 
_params_depended_on(MInfo(cls=self_.cls,inst=self_.self,name=name,method=getattr(self_.self_or_cls,name)))
 
 
+    def outputs(self_):
+        """
+        Returns a mapping between any declared outputs and a tuple
+        of the declared Parameter type, the output method, and the
+        index into the output if multiple outputs are returned.
+        """
+        outputs = {}
+        for name in dir(self_.self_or_cls):
+            method = getattr(self_.self_or_cls, name)
+            dinfo = getattr(method, '_dinfo', {})
+            if 'outputs' not in dinfo:
+                continue
+            for override, otype, idx in dinfo['outputs']:
+                if override is not None:
+                    name = override
+                outputs[name] = (otype, method, idx)
+        return outputs
+
     def _spec_to_obj(self_,spec):
         # TODO: when we decide on spec, this method should be
         # rewritten
@@ -1249,7 +1371,7 @@
         m = re.match("(?P<path>[^:]*):?(?P<what>.*)", spec)
         what = m.group('what')
         path = "."+m.group('path')
-        m = re.match("(?P<obj>.*)(\.)(?P<attr>.*)",path)
+        m = re.match(r"(?P<obj>.*)(\.)(?P<attr>.*)",path)
         obj = m.group('obj')
         attr = m.group("attr")
 
@@ -1474,7 +1596,7 @@
         # everything else access from here rather than from method
         # object
         for n,dinfo in dependers:
-            if dinfo['watch']:
+            if dinfo.get('watch', False):
                 _watch.append(n)
 
         mcs.param._depends = {'watch':_watch}
@@ -2025,8 +2147,8 @@
             if k in processed: continue
 
             # Suppresses automatically generated names.
-            if k == 'name' and (values[k] is not None and
-                                
re.match('^'+self.__class__.__name__+'[0-9]+$', values[k])):
+            if k == 'name' and (values[k] is not None
+                                and 
re.match('^'+self.__class__.__name__+'[0-9]+$', values[k])):
                 continue
 
             value = pprint(values[k], imports, prefix=prefix,settings=[],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/param/version.py 
new/param-1.8.2/param/version.py
--- old/param-1.8.1/param/version.py    2018-10-12 17:27:31.000000000 +0200
+++ new/param-1.8.2/param/version.py    2019-01-28 03:52:15.000000000 +0100
@@ -522,7 +522,7 @@
     archive_commit_key = 
autover_section+'.configparser_workaround.archive_commit'
     for section in config.sections():
         if section.startswith(archive_commit_key):
-            archive_commit = re.match(".*=\s*(\S*)\s*",section).group(1)
+            archive_commit = re.match(r".*=\s*(\S*)\s*",section).group(1)
     ###
     return 
get_setup_version(cfg,reponame=reponame,pkgname=pkgname,archive_commit=archive_commit)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/tests/API0/testclassselector.py 
new/param-1.8.2/tests/API0/testclassselector.py
--- old/param-1.8.1/tests/API0/testclassselector.py     2018-10-12 
17:27:31.000000000 +0200
+++ new/param-1.8.2/tests/API0/testclassselector.py     2019-01-28 
03:52:15.000000000 +0100
@@ -27,7 +27,7 @@
     def test_single_class_instance_error(self):
         exception = "Parameter 'e' value must be an instance of int, not 'a'"
         with self.assertRaisesRegexp(ValueError, exception):
-            p = self.P(e='a')
+            self.P(e='a')
 
     def test_single_class_type_constructor(self):
         p = self.P(f=float)
@@ -36,7 +36,7 @@
     def test_single_class_type_error(self):
         exception = "Parameter 'str' must be a subclass of Number, not 'type'"
         with self.assertRaisesRegexp(ValueError, exception):
-            p = self.P(f=str)
+            self.P(f=str)
 
     def test_multiple_class_instance_constructor1(self):
         p = self.P(g=1)
@@ -49,7 +49,7 @@
     def test_multiple_class_instance_error(self):
         exception = "Parameter 'g' value must be an instance of \(int, str\), 
not '3.0'"
         with self.assertRaisesRegexp(ValueError, exception):
-            p = self.P(g=3.0)
+            self.P(g=3.0)
 
     def test_multiple_class_type_constructor1(self):
         p = self.P(h=int)
@@ -62,4 +62,4 @@
     def test_multiple_class_type_error(self):
         exception = "Parameter 'float' must be a subclass of \(int, str\), not 
'type'"
         with self.assertRaisesRegexp(ValueError, exception):
-            p = self.P(h=float)
+            self.P(h=float)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/tests/API0/testdefaults.py 
new/param-1.8.2/tests/API0/testdefaults.py
--- old/param-1.8.1/tests/API0/testdefaults.py  2018-10-12 17:27:31.000000000 
+0200
+++ new/param-1.8.2/tests/API0/testdefaults.py  2019-01-28 03:52:15.000000000 
+0100
@@ -8,7 +8,8 @@
 from param import concrete_descendents, Parameter
 
 # import all parameter types
-from param import *
+from param import ClassSelector
+from param import * # noqa
 
 
 positional_args = {
@@ -18,12 +19,12 @@
 skip = []
 
 try:
-    import numpy
+    import numpy # noqa
 except ImportError:
     skip.append('Array')
 
 try:
-    import pandas
+    import pandas # noqa
 except ImportError:
     skip.append('DataFrame')
     skip.append('Series')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/tests/API0/testipythonmagic.py 
new/param-1.8.2/tests/API0/testipythonmagic.py
--- old/param-1.8.1/tests/API0/testipythonmagic.py      2018-10-12 
17:27:31.000000000 +0200
+++ new/param-1.8.2/tests/API0/testipythonmagic.py      2019-01-28 
03:52:15.000000000 +0100
@@ -9,7 +9,7 @@
 
 
 try:
-    import IPython
+    import IPython # noqa
 except ImportError:
     import os
     if os.getenv('PARAM_TEST_IPYTHON','0') == '1':
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/tests/API1/testclassselector.py 
new/param-1.8.2/tests/API1/testclassselector.py
--- old/param-1.8.1/tests/API1/testclassselector.py     2018-10-12 
17:27:31.000000000 +0200
+++ new/param-1.8.2/tests/API1/testclassselector.py     2019-01-28 
03:52:15.000000000 +0100
@@ -28,7 +28,7 @@
     def test_single_class_instance_error(self):
         exception = "Parameter 'e' value must be an instance of int, not 'a'"
         with self.assertRaisesRegexp(ValueError, exception):
-            p = self.P(e='a')
+            self.P(e='a')
 
     def test_single_class_type_constructor(self):
         p = self.P(f=float)
@@ -37,7 +37,7 @@
     def test_single_class_type_error(self):
         exception = "Parameter 'str' must be a subclass of Number, not 'type'"
         with self.assertRaisesRegexp(ValueError, exception):
-            p = self.P(f=str)
+            self.P(f=str)
 
     def test_multiple_class_instance_constructor1(self):
         p = self.P(g=1)
@@ -50,7 +50,7 @@
     def test_multiple_class_instance_error(self):
         exception = "Parameter 'g' value must be an instance of \(int, str\), 
not '3.0'"
         with self.assertRaisesRegexp(ValueError, exception):
-            p = self.P(g=3.0)
+            self.P(g=3.0)
 
     def test_multiple_class_type_constructor1(self):
         p = self.P(h=int)
@@ -63,7 +63,7 @@
     def test_multiple_class_type_error(self):
         exception = "Parameter 'float' must be a subclass of \(int, str\), not 
'type'"
         with self.assertRaisesRegexp(ValueError, exception):
-            p = self.P(h=float)
+            self.P(h=float)
 
 
 class TestDictParameters(API1TestCase):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/tests/API1/testdefaults.py 
new/param-1.8.2/tests/API1/testdefaults.py
--- old/param-1.8.1/tests/API1/testdefaults.py  2018-10-12 17:27:31.000000000 
+0200
+++ new/param-1.8.2/tests/API1/testdefaults.py  2019-01-28 03:52:15.000000000 
+0100
@@ -6,7 +6,8 @@
 from param import concrete_descendents, Parameter
 
 # import all parameter types
-from param import *
+from param import * # noqa
+from param import ClassSelector
 from . import API1TestCase
 
 positional_args = {
@@ -16,11 +17,11 @@
 skip = []
 
 try:
-    import numpy
+    import numpy # noqa
 except ImportError:
     skip.append('Array')
 try:
-    import pandas
+    import pandas # noqa
 except ImportError:
     skip.append('DataFrame')
     skip.append('Series')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/tests/API1/testipythonmagic.py 
new/param-1.8.2/tests/API1/testipythonmagic.py
--- old/param-1.8.1/tests/API1/testipythonmagic.py      2018-10-12 
17:27:31.000000000 +0200
+++ new/param-1.8.2/tests/API1/testipythonmagic.py      2019-01-28 
03:52:15.000000000 +0100
@@ -8,7 +8,7 @@
 from . import API1TestCase
 
 try:
-    import IPython
+    import IPython # noqa
 except ImportError:
     import os
     if os.getenv('PARAM_TEST_IPYTHON','0') == '1':
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/tests/API1/testparamoutput.py 
new/param-1.8.2/tests/API1/testparamoutput.py
--- old/param-1.8.1/tests/API1/testparamoutput.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/param-1.8.2/tests/API1/testparamoutput.py       2019-01-28 
03:52:15.000000000 +0100
@@ -0,0 +1,201 @@
+"""
+Unit test for param.output.
+"""
+import sys
+
+from unittest import SkipTest
+
+import param
+
+from . import API1TestCase
+
+
+class TestParamDepends(API1TestCase):
+
+    def test_simple_output(self):
+        class P(param.Parameterized):
+
+            @param.output()
+            def single_output(self):
+                return 1
+
+        p = P()
+        outputs = p.param.outputs()
+        self.assertEqual(list(outputs), ['single_output'])
+
+        otype, method, idx = outputs['single_output']
+        self.assertIs(type(otype), param.Parameter)
+        self.assertEqual(method, p.single_output)
+        self.assertEqual(idx, None)
+
+    def test_named_kwarg_output(self):
+        class P(param.Parameterized):
+
+            @param.output(value=param.Integer)
+            def single_output(self):
+                return 1
+
+        p = P()
+        outputs = p.param.outputs()
+        self.assertEqual(list(outputs), ['value'])
+
+        otype, method, idx = outputs['value']
+        self.assertIs(type(otype), param.Integer)
+        self.assertEqual(method, p.single_output)
+        self.assertEqual(idx, None)
+
+    def test_named_and_typed_arg_output(self):
+        class P(param.Parameterized):
+
+            @param.output(('value', param.Integer))
+            def single_output(self):
+                return 1
+
+        p = P()
+        outputs = p.param.outputs()
+        self.assertEqual(list(outputs), ['value'])
+
+        otype, method, idx = outputs['value']
+        self.assertIs(type(otype), param.Integer)
+        self.assertEqual(method, p.single_output)
+        self.assertEqual(idx, None)
+
+    def test_named_arg_output(self):
+        class P(param.Parameterized):
+
+            @param.output('value')
+            def single_output(self):
+                return 1
+
+        p = P()
+        outputs = p.param.outputs()
+        self.assertEqual(list(outputs), ['value'])
+
+        otype, method, idx = outputs['value']
+        self.assertIs(type(otype), param.Parameter)
+        self.assertEqual(method, p.single_output)
+        self.assertEqual(idx, None)
+
+    def test_typed_arg_output(self):
+        class P(param.Parameterized):
+
+            @param.output(int)
+            def single_output(self):
+                return 1
+
+        p = P()
+        outputs = p.param.outputs()
+        self.assertEqual(list(outputs), ['single_output'])
+
+        otype, method, idx = outputs['single_output']
+        self.assertIs(type(otype), param.ClassSelector)
+        self.assertIs(otype.class_, int)
+        self.assertEqual(method, p.single_output)
+        self.assertEqual(idx, None)
+
+    def test_multiple_named_kwarg_output(self):
+        py_major = sys.version_info.major
+        py_minor = sys.version_info.minor
+        if (py_major < 3 or (py_major == 3 and py_minor < 6)):
+            raise SkipTest('Multiple keyword output declarations only '
+                           'supported in Python >= 3.6, skipping test.')
+
+        class P(param.Parameterized):
+
+            @param.output(value=param.Integer, value2=param.String)
+            def multi_output(self):
+                return (1, 'string')
+
+        p = P()
+        outputs = p.param.outputs()
+        self.assertEqual(set(outputs), {'value', 'value2'})
+
+        otype, method, idx = outputs['value']
+        self.assertIs(type(otype), param.Integer)
+        self.assertEqual(method, p.multi_output)
+        self.assertEqual(idx, 0)
+
+        otype, method, idx = outputs['value2']
+        self.assertIs(type(otype), param.String)
+        self.assertEqual(method, p.multi_output)
+        self.assertEqual(idx, 1)
+
+    def test_multi_named_and_typed_arg_output(self):
+        class P(param.Parameterized):
+
+            @param.output(('value', param.Integer), ('value2', param.String))
+            def multi_output(self):
+                return (1, 'string')
+
+        p = P()
+        outputs = p.param.outputs()
+        self.assertEqual(set(outputs), {'value', 'value2'})
+        otype, method, idx = outputs['value']
+        self.assertIs(type(otype), param.Integer)
+        self.assertEqual(method, p.multi_output)
+        self.assertEqual(idx, 0)
+
+        otype, method, idx = outputs['value2']
+        self.assertIs(type(otype), param.String)
+        self.assertEqual(method, p.multi_output)
+        self.assertEqual(idx, 1)
+
+    def test_multi_named_arg_output(self):
+        class P(param.Parameterized):
+
+            @param.output('value', 'value2')
+            def multi_output(self):
+                return (1, 2)
+
+        p = P()
+        outputs = p.param.outputs()
+        self.assertEqual(set(outputs), {'value', 'value2'})
+
+        otype, method, idx = outputs['value']
+        self.assertIs(type(otype), param.Parameter)
+        self.assertEqual(method, p.multi_output)
+        self.assertEqual(idx, 0)
+
+        otype, method, idx = outputs['value2']
+        self.assertIs(type(otype), param.Parameter)
+        self.assertEqual(method, p.multi_output)
+        self.assertEqual(idx, 1)
+
+    def test_multi_typed_arg_output(self):
+        with self.assertRaises(ValueError):
+            class P(param.Parameterized):
+
+                @param.output(int, str)
+                def single_output(self):
+                    return 1
+
+    def test_multi_method_named_and_typed_arg_output(self):
+        class P(param.Parameterized):
+
+            @param.output(('value', param.Integer), ('value2', str))
+            def multi_output(self):
+                return (1, 'string')
+
+            @param.output(('value3', param.Number))
+            def single_output(self):
+                return 3.0
+
+        p = P()
+        outputs = p.param.outputs()
+        self.assertEqual(set(outputs), {'value', 'value2', 'value3'})
+
+        otype, method, idx = outputs['value']
+        self.assertIs(type(otype), param.Integer)
+        self.assertEqual(method, p.multi_output)
+        self.assertEqual(idx, 0)
+
+        otype, method, idx = outputs['value2']
+        self.assertIs(type(otype), param.ClassSelector)
+        self.assertIs(otype.class_, str)
+        self.assertEqual(method, p.multi_output)
+        self.assertEqual(idx, 1)
+
+        otype, method, idx = outputs['value3']
+        self.assertIs(type(otype), param.Number)
+        self.assertEqual(method, p.single_output)
+        self.assertEqual(idx, None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/tests/API1/testwatch.py 
new/param-1.8.2/tests/API1/testwatch.py
--- old/param-1.8.1/tests/API1/testwatch.py     2018-10-12 17:27:31.000000000 
+0200
+++ new/param-1.8.2/tests/API1/testwatch.py     2019-01-28 03:52:15.000000000 
+0100
@@ -168,7 +168,7 @@
         accumulator = Accumulator()
 
         obj = SimpleWatchExample()
-        watcher = obj.param.watch(accumulator, ['a','b'])
+        obj.param.watch(accumulator, ['a','b'])
 
         obj.a = 2
         self.assertEqual(accumulator.call_count(), 1)
@@ -196,12 +196,12 @@
         obj = SimpleWatchExample()
 
         accumulator = Accumulator()
-        watcher = obj.param.watch(accumulator, ['a', 'c'])
+        obj.param.watch(accumulator, ['a', 'c'])
 
         def set_c(*events):
             obj.c = 3
 
-        watcher2 = obj.param.watch(set_c, ['a', 'b'])
+        obj.param.watch(set_c, ['a', 'b'])
 
         obj.param.set_param(a=2)
         self.assertEqual(obj.c, 3)
@@ -216,7 +216,7 @@
         accumulator = Accumulator()
 
         obj = SimpleWatchExample()
-        watcher = obj.param.watch(accumulator, ['a','b'])
+        obj.param.watch(accumulator, ['a','b'])
         obj.param.set_param(a=23, b=42)
 
         self.assertEqual(accumulator.call_count(), 1)
@@ -265,8 +265,8 @@
         accumulator = Accumulator()
 
         obj = SimpleWatchExample()
-        watcher1 = obj.param.watch(accumulator, ['a','b'])
-        watcher2 = obj.param.watch(accumulator, ['c'])
+        obj.param.watch(accumulator, ['a','b'])
+        obj.param.watch(accumulator, ['c'])
 
         obj.param.set_param(a=23, b=42, c=99)
 
@@ -429,7 +429,7 @@
         accumulator = Accumulator()
 
         obj = SimpleWatchExample()
-        watcher = obj.param.watch_values(accumulator, ['a','b'])
+        obj.param.watch_values(accumulator, ['a','b'])
 
         obj.a = 2
         self.assertEqual(accumulator.call_count(), 1)
@@ -449,7 +449,7 @@
         accumulator = Accumulator()
 
         obj = SimpleWatchExample()
-        watcher = obj.param.watch_values(accumulator, ['a','b'])
+        obj.param.watch_values(accumulator, ['a','b'])
         obj.param.set_param(a=23, b=42)
 
         self.assertEqual(accumulator.call_count(), 1)
@@ -462,8 +462,8 @@
         accumulator = Accumulator()
 
         obj = SimpleWatchExample()
-        watcher1 = obj.param.watch_values(accumulator, ['a','b'])
-        watcher2 = obj.param.watch_values(accumulator, ['c'])
+        obj.param.watch_values(accumulator, ['a','b'])
+        obj.param.watch_values(accumulator, ['c'])
 
         obj.param.set_param(a=23, b=42, c=99)
 
@@ -488,7 +488,7 @@
     def test_simple_trigger_one_param(self):
         accumulator = Accumulator()
         obj = SimpleWatchExample()
-        watcher = obj.param.watch(accumulator, ['a'])
+        obj.param.watch(accumulator, ['a'])
         obj.param.trigger('a')
         self.assertEqual(accumulator.call_count(), 1)
 
@@ -501,7 +501,7 @@
     def test_simple_trigger_one_param_change(self):
         accumulator = Accumulator()
         obj = SimpleWatchExample()
-        watcher = obj.param.watch(accumulator, ['a'])
+        obj.param.watch(accumulator, ['a'])
         obj.a = 42
         self.assertEqual(accumulator.call_count(), 1)
 
@@ -523,7 +523,7 @@
     def test_simple_trigger_two_params(self):
         accumulator = Accumulator()
         obj = SimpleWatchExample()
-        watcher = obj.param.watch(accumulator, ['a','b'])
+        obj.param.watch(accumulator, ['a','b'])
         obj.param.trigger('a','b')
         self.assertEqual(accumulator.call_count(), 1)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/tests/__init__.py 
new/param-1.8.2/tests/__init__.py
--- old/param-1.8.1/tests/__init__.py   2018-10-12 17:27:31.000000000 +0200
+++ new/param-1.8.2/tests/__init__.py   2019-01-28 03:52:15.000000000 +0100
@@ -1,5 +1,5 @@
 import sys
-import unittest
+import unittest # noqa
 
 if sys.version_info[0]==2 and sys.version_info[1]<7:
     del sys.modules['unittest']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/param-1.8.1/tox.ini new/param-1.8.2/tox.ini
--- old/param-1.8.1/tox.ini     2018-10-12 17:27:31.000000000 +0200
+++ new/param-1.8.2/tox.ini     2019-01-28 03:52:15.000000000 +0100
@@ -40,3 +40,8 @@
 [testenv:flakes]
 skip_install = true
 commands = flake8
+
+[flake8]
+ignore = E,W,W605
+include = *.py
+exclude = 
.git,__pycache__,.tox,.eggs,*.egg,doc,dist,build,_build,.ipynb_checkpoints,run_test.py


Reply via email to